2 Aralık 2019 Pazartesi

SQL Server'da Hafıza Kullanımı

Bazen müşterilerimden, bazen de forumlarda insanlardan SQL Server'ın hafıza (RAM) kullanımı hakkında benzer soru ve şikayetleri alıyorum: "CPU kullanımı düşükken veritabanı sunucusundaki RAM kullanımının %90 olması normal mi?" veya "SQL Server'da performans sorun var, RAM'in tamamını kullanıyor!".


İnsanları endişelendiren ekranın görüntüsü

Sorunun kısa yanıtı: "Evet, çok normal ve aslında tam da görmek istediğimiz manzara!"

Bundan sonrası sorunun uzun yanıt kısmı, vakti ve merakı olan okumaya devam edebilir.

Veritabanlarındaki tablolarınızda bulunan kayıtları ilgilendiren bir sorgu çalıştırdığınızda SQL Server öncelikle ilgili kayıtları içeren Page'ler* zaten hafızada mı (Buffer Pool) yoksa değil mi diye kontrol eder, şayet ilgili Page'ler hafızada değilse diske gider ve ilgili Page'leri hafızaya alır. Sonrasında ilgili kayıtlar için işlemler gerçekleştirilir.

* Page, SQL Server'daki en küçük depolama birimidir, 8 kilobayttır ve tablolarınızdaki kayıtlar bu mantıksal birimlerde saklanır.

Hafıza (RAM), disk donanım kaynağına göre çok daha hızlıdır. Bu nedenle SQL Server hafızadan olabildiğince çok faydalanmak ister ve aynı nedenle bir Page diskten hafızaya alındığında, o Page'in olabildiğince makul bir süre hafızada kalmasını isteriz, ki SQL Server sürekli diske gidip tekrar aynı Page'leri hafızaya taşıma işlemi gerçekleştirmesin. En sık kullanılan Page'lerin en makul miktar ve sürede hafızada kalması* yararımızadır.

* Bir Page'in ortalama hafızada kalma süresini Performance Monitor'deki "Page Life Expectancy" (PLE) sayacıyla ölçebiliriz.

Eski iyi pratikler PLE değerinin 300 (saniye cinsinden) iyi bir beklenti olduğunu söyler, fakat 300 zamanımızda artık oldukça düşük bir değer. Peki en iyi değer nedir? Herkes için en iyi değer diye bir değer yoktur, bu değer iş yükünüze, uygulamanızın çalışma doğasına, imkanlarınıza/bütçenize ve beklentinize göre değişir. Bununla birlikte, her halükarda beklentimiz ve hedefimiz, Page'lerin olabildiğince uzun süre hafızada kalması olmalıdır.

Varsayılan Ayar
Yeni bir SQL Server Instance'ı kurduğunuzda varsayılan olarak "Max Server Memory" ayarı 2147483647 megabayttır, yani bir anlamda Buffer Pool için "kullanabildiğin kadar RAM'i kullan"dır. Buna SQL Server literatüründe "dinamik hafıza yönetimi" denir. 

Kurulumlardan sonra yapılacak ayar değişikliklerinden biri de bu ayarı makul bir değer* ile değiştirmektir. Çünkü aynı sunucu üstünde SQL Server'ın haricinde işletim sistemi ve diğer elzem uygulama ve hizmetlerin de çalışması ve çalışacak her uygulamanın da hafızaya ihtiyacı olacaktır. Varolan hafıza kaynağının tüm bu uygulamalar arasında herhangi bir çatışmaya neden olmayacak şekilde dikkatlice paylaştırılması gerekiyor.

* Makul değer sunucudan sunucuya ve kullanılabilir fiziksel hafıza miktarına göre değişiklik gösterir. Ayrıca ayarlayıp unutmamak, ayardan sonra sürekli izlemek gerekir. Çünkü zamanla ihtiyaçlar değişebilir. Hafıza kaynağımızı atıl şekilde de bırakmak istemeyiz, sanal hafıza (Windows Page File) kullanılmasını da istemeyiz.

Eğer "Max Server Memory" ayarını yapılandırmazsanız veya yanlış yapılandırırsanız o zaman Task Manager veya başka araçlarla sunucuda kullanılan hafıza oranına bakarsanız %100'leri görebilirsiniz*, işte bu hiç istediğimiz bir durum değildir. Çünkü böyle bir manzara uygulamalar arasında hafıza için çatışma yaşandığı veya yaşanabileceği, sanal hafıza alanının kullanımı gibi şeyleri getirir akla. Performans açısından hiç istemediğimiz bir durum.

* Eğer sunucunuzdaki fiziksel hafıza miktarı, sunucu üstündeki veritabanının hacminden daha yüksekse hafıza kullanımının %100'e çıktığını hiç görmeyebilirsiniz de. Misal sunucuda 128GB RAM varsa ve o sunucu üstündeki toplam veritabanı boyutu 10GB ise muhtemelen hafıza kullanımınız 15-20GB'ı hiç geçmeyecektir.

En sık kullandığınız kayıtlara ait Page'ler hafızadayken sunucu üstündeki başka bir hizmetin veya uygulamanın veya işletim sisteminin hafıza ihtiyacı nedeniyle SQL Server ile hafıza çatışmasına girdiğini ve bu çatışma sonucunda en yüksek işlem hacminin gerçekleştiği bir vakitte işletim sisteminin hafıza kaynağının bir kısmını diğer uygulamalar ve hizmetlere ayırmak için SQL Server'ın Page'lerinin bir kısmını RAM'den attığını ve bunun sonucunda da SQL Server'ın aşağıdaki hatayı ürettiğini düşünün?

"A significant part of sql server process memory has been paged out. This may result in a performance degradation."*

* Bu bir örnek değil, gerçek hayatta tam da böyle oluyor. Bu durum oluştuğunda bu hatayı SQL Server Error Log ve Windows Application Event Log'ta bulabililirsiniz.

Özellikle kritik veritabanı sunucuları için bu tüylerimizi diken diken eden bir manzaradır. Bu olumsuz sonucu son kullanıcılarınız hemen hissedecektir. Çünkü bu durumda uygulamalarınız bloklanma, donmalar ve yavaşlıklar yaşarlar ve bunların sonucunda uygulamalarınız zaman aşımı hataları alabilir. Sonuç olarak ciddi ve düzensiz performans sorunları yaşarsınız ve performans açısından istikrarsız bir ortamınız olur.

Windows Local Security Policy'deki "Lock pages in memory" ayarı sayesinde işletim sisteminin SQL Server'ın Page'lerine müdahale etmesini engelleyebilirsiniz. Fakat yukarıdaki açıklamalardan görebileceğiniz üzere bu sandaldaki bir deliği tıkar, diğer deliğin açılmasına neden olur. Çünkü belli ki bir hafıza ihtiyacı var ve bu bir şekilde karşılanmalı, gerekiyorsa Windows Page File kullanılarak. Diğer hizmet sunucularını bilemiyorum; ama şahsen ben sunucumdaki Windows Page File'ın rutin olarak kullanıldığını görmek istemem.

Bazen...
Bazen tüm yapılması gereken ayarları yaptıktan sonra bile zaman zaman Page Life Expectancy değerinin birden dip yaptığını, misal 100'lerin altına kadar indiğini görebilirsiniz. Böyle anlarda eğer bir takip mekanizmanız varsa veya bilgisayar başından anlık olarak kontrol edebilirseniz ender çalışan, oldukça büyük tablolardan oldukça yüklü miktarda verilerin çağrıldığı masraflı bir sorgunun çalıştığını görebilirsiniz. Özellikle karışık iş yüklerinin olduğu* ortamlarda bu durumla karşılaşılabilinir.

* Hem OLTP işlemlerin hem de raporlama işlerinin çalıştığı ortamlar.

Eğer ortam kritik bir veritabanı ortamı ise farklı raporlama tasarım ve çözümlerini masaya getirmekte fayda olabilir, ki böylece ortam OLTP iş yükü için çok daha homojen hale getirilebilir ve böylece ortamın performans açısından çok daha istikrarlı olması sağlanabilir; fakat bu tamamen farklı bir yazının konusu.

Sonuç
Sonuç itibariyle: 
- SQL Server veritabanlarınızdaki tablolara ait kayıtları olabildiğince uzun süre fiziksel hafızada tutmak istersiniz,
- Bunun için Performance Monitor'deki "Page Life Expectancy" sayacının değerini en azından birkaç gün izleyip doğru noktada olup olmadığınızı ölçebilirsiniz,
- Bunları sağlamak için de sunucunuzda yeterli miktarda fiziksel hafıza kaynağı bulunduğundan ve kurulumdan sonra SQL Server'ın "Max Server Memory" ayarını yapılandırdığından emin olmalısınız.

Veritabanı sunucularınızı her zaman yakından takip etmenizi öneririm, çünkü her an, her şey değişebilir. Veritabanını kullanan uygulamalarınızdaki kodlar, iş birimlerinizin ihtiyaçları, kampanyalar, fiziksel/sanal ortamlarınızdaki altyapı değişiklikleri veritabanı sunucularınızın performansını etkileyen başlıca faktörlerdir. Eğer sunucularınızı sürekli izlerseniz, anormal bir durum karşısında hangi değerin normal, hangisinin anormal olduğunu rahatlıkla ayırt edebilir ve doğrudan anormalliklere odaklanabilirsiniz.

Microsoft SQL Server veritabanı sunucularınızında sorun mu yaşıyorsunuz? Size yardımcı olabilirim!

Ekrem Önsoy
Microsoft SQL Server Danışmanı
www.ekremonsoy.com


3 yorum:

Unknown dedi ki...

çok güzel bir yazı olmuş Ekrem bey. Evet genelde SQL server hep fazla ram kullanır ve bu normaldir diye düşünürüz.

Unknown dedi ki...

Merhaba Hocam

SQL Serverde yapılması gereken ince ayarlar nelerdi peki ?

Ekrem Önsoy dedi ki...

"SQL Serverde yapılması gereken ince ayarlar nelerdi peki ?"

Bu çok genel bir soru olmuş. O kadar genel ki, dallanıp budaklanıp kitap olur rahatlıkla.

Bir blog yazısının yorum kısmında, soruyu da yanıtsız bırakmamak adına ancak çok özetle başlıklarına değinebilirim.

- Windows Server düzeyinde SQL Server'ın en performanslı şekilde çalışabilmesi için gereken ayarlar yapılmalıdır,
- Veritabanı ortamının tasarımı ve altyapısında kullanılacak olan donanım, üretim ortamının veritabanından olan beklentileri dikkate alınarak tasarlanmalıdır,
- Veritabanları ve içerdiği ilgili nesneler, yine iş birimlerinin beklentilerini kapsayacak şekilde yeni teknolojiler (in-mem OLTP, Columnstore indeksler, SQL on Linux, tail of log caching [nvdimm ile], graph engine vd.) ve arşivleme ihtiyaçları dikkate alınarak tasarlanmalıdır,
- Veritabanı ortamlarınızı iyi bir izleme uygulaması ile 360 derece izlemelisiniz ve gerektiğinde geriye dönük toplanan verilerden (baseline) faydalanmalısınız,
- Yazılım birimleri ORM kullanıyorsa (EF vb) tembellik yapıp her sorgu için tüm tablolardaki tüm alanları çağırmamalılar, bu konuda bilgilendirilmeliler (belki yeni bir yazı konusu),
- Yazılım birimleri tablolarda en doğru şekilde indeks oluşturabilecek kapasiteye getirilmeli, veritabanı yöneticisi ancak gözden kaçan noktalara müdahale etmeli, tüm indekslerin oluşturulması veritabanı yöneticisinden beklememeli. Çünkü bu reaktif bir yoldur, kritik veritabanı ortamları için ise beklenti proaktif çözümdür.

Çok çok genel olarak bunları paylaşabilirim şimdilik.