Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Peningkatan potensial untuk ASPSstate

Banyak orang telah menerapkan ASPSstate di lingkungan mereka. Beberapa orang menggunakan opsi dalam memori (InProc), tetapi biasanya saya melihat opsi basis data yang digunakan. Ada beberapa potensi inefisiensi di sini yang mungkin tidak Anda perhatikan di situs dengan volume rendah, tetapi hal itu akan mulai memengaruhi kinerja saat volume web Anda meningkat.

Model Pemulihan

Pastikan ASPState disetel ke pemulihan sederhana – ini akan secara dramatis mengurangi dampak pada log yang dapat disebabkan oleh volume tinggi penulisan (sementara dan sebagian besar sekali pakai) yang kemungkinan besar masuk ke sini:

ALTER DATABASE ASPSstate SET PEMULIHAN SEDERHANA;

Biasanya database ini tidak perlu dalam pemulihan penuh, terutama karena jika Anda berada dalam mode pemulihan bencana dan memulihkan database Anda, hal terakhir yang harus Anda khawatirkan adalah mencoba mempertahankan sesi untuk pengguna di aplikasi web Anda – yang cenderung lama hilang pada saat Anda telah dipulihkan. Saya tidak berpikir saya pernah menemukan situasi di mana pemulihan point-in-time merupakan kebutuhan untuk database sementara seperti ASPState.

Minimalkan / isolasi I/O

Saat menyiapkan ASPState pada awalnya, Anda dapat menggunakan -sstype c dan -d argumen untuk menyimpan status sesi dalam database khusus yang sudah ada di drive yang berbeda (seperti yang Anda lakukan dengan tempdb). Atau, jika database tempdb Anda sudah dioptimalkan, Anda dapat menggunakan -sstype t argumen. Ini dijelaskan secara rinci dalam dokumen Session-State Modes dan ASP.NET SQL Server Registration Tool di MSDN.

Jika Anda telah menginstal ASPState, dan Anda telah menentukan bahwa Anda akan mendapat manfaat dari memindahkannya ke volumenya sendiri (atau setidaknya volume yang berbeda), maka Anda dapat menjadwalkan atau menunggu periode pemeliharaan singkat dan mengikuti langkah-langkah berikut:

ALTER DATABASE ASPSstate SET SINGLE_USER DENGAN ROLLBACK SEGERA; ALTER DATABASE ASPSstate SET OFFLINE; ALTER DATABASE ASPState MODIFY FILE (NAME =ASPState, FILENAME ='{new path}\ASPState.mdf');ALTER DATABASE ASPState MODIFY FILE (NAME =ASPState_log, FILENAME ='{new path}\ASPState_log.ldf'); 

Pada titik ini Anda perlu memindahkan file secara manual ke <new path> , lalu Anda dapat menghidupkan kembali basis data tersebut:

ALTER DATABASE ASPSstate SET ONLINE; ALTER DATABASE ASPSstate SET MULTI_USER;

Isolasi aplikasi

Dimungkinkan untuk mengarahkan lebih dari satu aplikasi ke database status sesi yang sama. Saya sarankan menentang ini. Anda mungkin ingin mengarahkan aplikasi ke database yang berbeda, bahkan mungkin pada instance yang berbeda, untuk mengisolasi penggunaan sumber daya dengan lebih baik dan memberikan fleksibilitas maksimal untuk semua properti web Anda.

Jika Anda sudah memiliki beberapa aplikasi menggunakan database yang sama, tidak apa-apa, tetapi Anda ingin melacak dampak yang mungkin dialami setiap aplikasi. Rex Tang dari Microsoft menerbitkan kueri yang berguna untuk melihat ruang yang digunakan oleh setiap sesi; berikut adalah modifikasi yang akan merangkum jumlah sesi dan total/rata-rata ukuran sesi per aplikasi:

PILIH a.AppName, SessionCount =COUNT(s.SessionId), TotalSessionSize =SUM(DATALENGTH(s.SessionItemLong)), AvgSessionSize =AVG(DATALENGTH(s.SessionItemLong))FROM dbo.ASPStateTempSessionsOUTER SEBAGAI JOLEINFT ASPStateTempApplications SEBAGAI ON SUBSTRING(s.SessionId, 25, 8) =SUBSTRING(sys.fn_varbintohexstr(CONVERT(VARBINARY(8), a.AppId)), 3, 8) GROUP BY a.AppNameORDER BY TotalSessionSize DESC;

Jika Anda menemukan bahwa Anda memiliki distribusi miring di sini, Anda dapat mengatur database ASPState lain di tempat lain, dan mengarahkan satu atau lebih aplikasi ke database itu.

Buat penghapusan yang lebih ramah

Kode untuk dbo.DeleteExpiredSessions menggunakan kursor, menggantikan satu DELETE dalam implementasi sebelumnya. (Menurut saya, ini sebagian besar didasarkan pada posting ini oleh Greg Low.)

Awalnya kodenya adalah:

BUAT PROSEDUR DeleteExpiredSessionsAS DECLARE @now DATETIME SET @now =GETUTCDATE() DELETE ASPState..ASPStateTempSessions WHERE Expires <@now RETURN 0GO

(Dan mungkin masih, tergantung di mana Anda mengunduh sumbernya, atau berapa lama Anda menginstal ASPState. Ada banyak skrip usang di luar sana untuk membuat database, meskipun Anda benar-benar harus menggunakan aspnet_regsql.exe.)

Saat ini (mulai .NET 4.5), kodenya terlihat seperti ini (ada yang tahu kapan Microsoft akan mulai menggunakan titik koma?).

ALTER PROCEDURE [dbo].[DeleteExpiredSessions]AS SET NOCOUNT ON SET DEADLOCK_PRIORITY LOW DECLARE @now datetime SET @now =GETUTCDATE() CREATE TABLE #tblExpiredSessions ( SessionID nvarchar(88) NOT NULL PRIMARY KEY ) PILIH SessionID FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED) WHERE Expired <@now JIKA @@ROWCOUNT <> 0 MULAI DECLARE ExpiredSessionCursor KURSOR LOKAL FORWARD_ONLY READ_ONLY FOR SELECT SessionID FROM #t BERIKUTNYA DARI ExpiredSessionCursor KE @SessionID SEMENTARA @@FETCH_STATUS =0 MULAI HAPUS DARI [ASPState].dbo.ASPStateTempSes sions WHERE SessionID =@SessionID DAN Kedaluwarsa <@now FETCH NEXT DARI ExpiredSessionCursor INTO @SessionID AKHIR TUTUP ExpiredSessionCursor DEALLOCATE ExpiredSessionCursor AKHIR DROP TABLE #tblExpiredSespresis RETURN 0
 Ide saya adalah untuk memiliki media yang bahagia di sini – jangan mencoba menghapus SEMUA baris dalam satu gerakan, tetapi juga jangan memainkan satu per satu pukulan. Sebagai gantinya, hapus n baris pada satu waktu dalam transaksi terpisah – mengurangi panjang pemblokiran dan juga meminimalkan dampak pada log:

ALTER PROCEDURE dbo.DeleteExpiredSessions @top INT =1000ASMULAI SET NOCOUNT ON; MENYATAKAN @sekarang DATETIME, @c INT; PILIH @sekarang =GETUTCDATE(), @c =1; MULAI TRANSAKSI; SEMENTARA @c <> 0 MULAI;DENGAN x AS ( SELECT TOP (@top) SessionId FROM dbo.ASPStateTempSessions WHERE Expires <@now ORDER BY SessionId ) DELETE x; SET @c =@@ROWCOUNT; JIKA @@TRANCOUNT =1 MULAI TRANSAKSI KOMIT; MULAI TRANSAKSI; AKHIR AKHIR JIKA @@TRANCOUNT =1 MULAI TRANSAKSI KOMIT; ENDENDGO

Anda ingin bereksperimen dengan TOP tergantung pada seberapa sibuk server Anda dan apa dampaknya terhadap durasi dan penguncian. Anda mungkin juga ingin mempertimbangkan untuk menerapkan isolasi snapshot – ini akan memaksa beberapa dampak pada tempdb tetapi dapat mengurangi atau menghilangkan pemblokiran yang terlihat dari aplikasi.

Juga, secara default, tugas ASPState_Job_DeleteExpiredSessions berjalan setiap menit. Pertimbangkan untuk memutar ulang sedikit – kurangi jadwal menjadi mungkin setiap 5 menit (dan sekali lagi, sebagian besar dari ini akan bergantung pada seberapa sibuk aplikasi Anda dan menguji dampak perubahan). Dan di sisi lain, pastikan ini diaktifkan – jika tidak, tabel sesi Anda akan bertambah dan tidak terkendali.

Sesi sentuh lebih jarang

Setiap kali halaman dimuat (dan, jika aplikasi web belum dibuat dengan benar, mungkin beberapa kali per halaman dimuat), prosedur tersimpan dbo.TempResetTimeout dipanggil, memastikan bahwa batas waktu untuk sesi tertentu diperpanjang selama mereka terus menghasilkan aktivitas. Pada situs web yang sibuk, ini dapat menyebabkan volume aktivitas pembaruan yang sangat tinggi terhadap tabel dbo.ASPStateTempSessions . Berikut adalah kode saat ini untuk dbo.TempResetTimeout :

ALTER PROCEDURE [dbo].[TempResetTimeout] @id tSessionId AS UPDATE [ASPState].dbo.ASPStateTempSessions SET Kedaluwarsa =DATEADD(n, Timeout, GETUTCDATE()) WHERE SessionId =@id RETURN 0

Sekarang, bayangkan Anda memiliki situs web dengan 500 atau 5.000 pengguna, dan mereka semua dengan gila-gilaan mengklik dari halaman ke halaman. Ini mungkin salah satu operasi yang paling sering disebut dalam implementasi ASPState, dan saat tabel dikunci pada SessionId – sehingga dampak dari setiap pernyataan individu harus minimal – secara keseluruhan hal ini dapat sangat boros, termasuk pada log. Jika batas waktu sesi Anda adalah 30 menit dan Anda memperbarui batas waktu untuk sesi setiap 10 detik karena sifat aplikasi web, apa gunanya melakukannya lagi 10 detik kemudian? Selama sesi itu diperbarui secara asinkron di beberapa titik sebelum 30 menit habis, tidak ada perbedaan bersih bagi pengguna atau aplikasi. Jadi saya pikir Anda dapat menerapkan cara yang lebih terukur untuk "menyentuh" ​​sesi untuk memperbarui nilai batas waktu mereka.

Satu ide yang saya miliki adalah menerapkan antrian broker layanan sehingga aplikasi tidak harus menunggu penulisan yang sebenarnya terjadi – ini memanggil dbo.TempResetTimeout prosedur tersimpan, dan kemudian prosedur aktivasi mengambil alih secara tidak sinkron. Tapi ini masih mengarah ke lebih banyak pembaruan (dan aktivitas log) daripada yang benar-benar diperlukan.

Ide yang lebih baik, IMHO, adalah mengimplementasikan tabel antrian yang hanya Anda masukkan, dan pada jadwal (sehingga proses menyelesaikan siklus penuh dalam beberapa waktu lebih pendek dari batas waktu), itu hanya akan memperbarui batas waktu untuk sesi apa pun itu melihat sekali , tidak peduli berapa kali mereka *mencoba* memperbarui batas waktu mereka dalam rentang itu. Jadi tabel sederhana mungkin terlihat seperti ini:

CREATE TABLE dbo.SessionStack( SessionId tSessionId, -- nvarchar(88) - tentu saja mereka harus menggunakan alias jenis EventTime DATETIME, Processed BIT NOT NULL DEFAULT 0); BUAT INDEKS CLUSTERED dan DI dbo.SessionStack(EventTime);GO

Dan kemudian kami akan mengubah prosedur stok untuk mendorong aktivitas sesi ke tumpukan ini alih-alih menyentuh tabel sesi secara langsung:

ALTER PROCEDURE dbo.TempResetTimeout @id tSessionIdASBEGIN SET NOCOUNT ON; INSERT INTO dbo.SessionStack(SessionId, EventTime) SELECT @id, GETUTCDATE();ENDGO

Indeks berkerumun ada di smalldatetime kolom untuk mencegah pemisahan halaman (dengan potensi biaya halaman panas), karena waktu acara untuk sentuhan sesi akan selalu meningkat secara monoton.

Kemudian kita memerlukan proses latar belakang untuk meringkas baris baru secara berkala di dbo.SessionStack dan perbarui dbo.ASPStateTempSessions sesuai.

BUAT PROSEDUR dbo.SessionStack_ProcessASBEGIN AKTIFKAN NOCOUNT; -- kecuali jika Anda ingin menambahkan tSessionId ke model atau secara manual ke tempdb -- setelah setiap restart, kita harus menggunakan tipe dasar di sini:CREATE TABLE #s(SessionId NVARCHAR(88), EventTime SMALLDATETIME); -- tumpukan sekarang hotspot Anda, jadi masuk &keluar dengan cepat:UPDATE dbo.SessionStack SET Diproses =1 OUTPUT dimasukkan.SessionId, dimasukkan.EventTime INTO #s WHERE Processed IN (0,1) -- jika ada yang gagal terakhir waktu DAN Waktu Peristiwa  

Anda mungkin ingin menambahkan lebih banyak kontrol transaksional dan penanganan kesalahan di sekitar ini - saya hanya menyajikan ide yang tidak terduga, dan Anda bisa menjadi gila di sekitar ini seperti yang Anda inginkan. :-)

Anda mungkin berpikir ingin menambahkan indeks non-cluster pada dbo.SessionStack(SessionId, EventTime DESC) untuk memfasilitasi proses latar belakang, tetapi saya pikir lebih baik untuk memfokuskan bahkan peningkatan kinerja yang paling kecil pada proses yang ditunggu pengguna (setiap halaman dimuat) daripada yang tidak mereka tunggu (proses latar belakang). Jadi saya lebih suka membayar biaya pemindaian potensial selama proses latar belakang daripada membayar pemeliharaan indeks tambahan selama setiap penyisipan. Seperti indeks berkerumun pada tabel #temp, ada banyak "itu tergantung" di sini, jadi Anda mungkin ingin bermain dengan opsi ini untuk melihat di mana toleransi Anda bekerja paling baik.

Kecuali jika frekuensi kedua operasi harus berbeda secara drastis, saya akan menjadwalkannya sebagai bagian dari ASPState_Job_DeleteExpiredSessions pekerjaan (dan pertimbangkan untuk mengganti nama pekerjaan itu jika demikian) sehingga kedua proses ini tidak saling menginjak.

Satu ide terakhir di sini, jika Anda merasa perlu untuk memperbesar lebih banyak lagi, adalah membuat beberapa SessionStack tabel, di mana masing-masing bertanggung jawab atas subset sesi (misalnya, di-hash pada karakter pertama SessionId ). Kemudian Anda dapat memproses setiap tabel secara bergantian, dan menjaga agar transaksi tersebut jauh lebih kecil. Bahkan Anda dapat melakukan hal serupa untuk pekerjaan penghapusan juga. Jika dilakukan dengan benar, Anda seharusnya dapat menempatkan ini dalam tugas individu dan menjalankannya secara bersamaan, karena – secara teori – DML seharusnya memengaruhi kumpulan halaman yang sama sekali berbeda.

Kesimpulan

Itulah ide-ide saya sejauh ini. Saya ingin mendengar tentang pengalaman Anda dengan ASPState:Skala seperti apa yang telah Anda capai? Jenis kemacetan apa yang Anda amati? Apa yang telah Anda lakukan untuk menguranginya?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Manajemen Transaksi dengan Django 1.6

  2. Salesforce SOQL dari Microsoft Office

  3. Mempartisi dengan Anggaran

  4. Cara Menemukan Nilai Minimum Kolom di SQL

  5. FORMAT() bagus dan semuanya, tapi…