3 Kasım 2017 Cuma

Firmam 2. yaşını doldurdu, kutlu olsun!

Firmamı kuralı 2 sene oldu ve bu vesileyle bir teşekkür yazısı yazmak istedim.

2 sene önce sevgili dostum Yiğit Aktan'ın (t) da kışkırtmalarıyla artık kendi firmamı kurmam kaçınılmaz olmuştu. Ben de kaçınmadım, üşenmedim ve uzun yıllardır aşkla kullandığım, inciğine, cıncığına kadar kurcaladığım, hakkında sabah akşam okuyup dersler aldığım, sınavlarına girip, ödül kazandığım Microsoft SQL Server ürünü konusunda profesyonel danışmanlık hizmeti vermeyi hedeflediğim firmamı kurdum.


www.ekremonsoy.com adresindeki ilk yazım

Firmamı kurduğumdan beri sağolsun sevgili eşim başta olmak üzere, dostlar ve piyasanın çeşitli uç ve bucağına dağılmış olan eski iş arkadaşlarım desteklerini hiç esirgemediler. Bu süreçte bazılarıyla yollarımız farklı firmalarda tekrar kesişti, bazılarıyla tekrar birlikte çalışma fırsatımız oldu.

Bu 2 yıllık süreçte İzmir'deki bir matbaadan, Bursa'daki bir girişimciden, dünya çapında binlerce insan çalıştıran şirketlere kadar birçok şirket ile çalışma fırsatım oldu. Aşağıda, hala birçoğuyla çalıştığımız bu şirketlerin bazılarının isimlerini (alfabetik) paylaşmaktan memnuniyet duyuyor ve bana güvenip, benimle çalıştıkları için teşekkür ediyorum.

- Ada Yazılım
- Alp Havacılık
- Borusan Lojistik
- Doğa Sigorta
- Edenred Türkiye
- Ericsson
- Morhipo.com
- Papara
- Penta
- Pronet
- RND
- Tiposoft

Her geçen gün öğrendiğim yeni şeyleri 20 yılın tecrübesiyle ve ilk günkü hevesle uygulayıp, paylaşma fırsatı bulduğum için ve yetmezmiş gibi bir de bu sayede faturalarımı ödeyebildiğim için çok müteşekkirim, hayata ve katkısı olan herkese.

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

29 Eylül 2017 Cuma

Veritabanınızdaki veriler ne kadar güvende sizce?

Güvenlik gündemden düşmeyen ve düşmeyecek bir konu, sonuçta İhtiyaçlar Hiyerarşisinin de 2. basamağında. Hatta malumunuz son günlerde her yerde Gartner'ın Güvenlik Danışmanlığı dalında ve ciro bakımından 5 yıl art arda 1. sıraya koyduğu Deloitte'ta yaşanan güvenlik açığı konuşuluyor. Peki sizin sistemlerinizin güvenliği ne alemde? Bunu yeterince sorguluyor musunuz?

Bu yazımda size son günlerde yaşadığım bir güvenlik sorunundan ve bir Microsoft SQL Server veritabanı yöneticisinin gözünden güvenlik ile ilgili alınması gereken tedbirlerden bahsedeceğim.

Kısa bir süre önce yönetimini yaptığım sunucuların birinden güvenlik alarmları geldiğini gördüm, durumu analiz edip hemen ilgili IT yöneticisine bildirdim. O da ilgili diğer arkadaşlara bildirdi ve sisteme bir saldırı olduğu netleşti. İlgili ekip tarafından gerekli önlemler alındı ve atak engellenmiş oldu. 

Peki saldırının türü neydi ve saldırıyı nasıl fark ettim? Microsoft SQL Server ürününün varsayılan olarak böyle bir alarmı veya mekanizması yok. Fakat bunun temel altyapısı var. Eğer biraz tecrübeniz varsa, biraz bu konulara kafa yoruyorsanız ve üşengeç biri de değilseniz o zaman eminim sizin de aklınıza gelmiştir bu mekanizma ve bazılarınız zaten uygulamıştır. 

Bakım ve destek anlaşması kapsamında ilgili sunuculara kurduğum izleme sistemindeki onlarca kontrolden biri şöyle:
- Her X dakikada bir Error Log dosyası içerisindeki (ki Error Log dosyasına yazılan her şey Windows Application Event Log'a da yazılır, yani alternatif bir yöntem) tüm "Login Failed" kelimeleri geçen hatalar taranır, 
- Eğer bulunan kayıt sayısı beklenilen/normal sayılan değerden yüksekse, ilgili yöneticilere e-posta ile (aşağıdaki resimdeki gibi bir liste) bildirilir.

Çok basit bir oto-denetim, ama çok etkili. Bahsettiğim saldırıyı güvenlik, ağ ve sistem yönetiminden önce benim fark etmemi sağlayan yöntem bu idi.

Bu saldırıya "Brute Force" mu desek, DDoS mu? Sonuç itibariyle farklı farklı IP adreslerinden, farklı farklı kullanıcı adı ve şifre kombinasyonuyla veritabanına girilmeye çalışıldı.


Saldırı sırasında oluşan hatalar

Çok iyi hatırlıyorum, 2 sene önce bir başka ortamda da aynen yukarıdaki hata mesajlarına benzer hatalar oluşmuştu. Müşteriyle daha yeni bakım ve destek anlaşması yapmıştık. Bana sunucularının çok kritik olduğundan bahsetmişti. Sunucuya daha ilk bağlandığımda hata kayıt dosyalarının böyle mesajlarla dolu olduğunu görmüştüm. Kim bilir ne süredir saldırı altındaydı ve bundan hiç haberi yoktu. Bunu müşteriyle ilettiğimde tüyleri diken diken olmuştu.

Microsoft SQL Server, yıllardır güvenlik açıkları kapsamında rakiplerine göre katbekat güvenli bir ilişkisel veritabanı ürünüdür. Bununla birlikte, nasıl güvenli olduğundan emin olduğunuz herhangi bir aracı, gereci kullanırken tüm güvenlik önlemlerini almanız gerekiyorsa, SQL Server'ı da kullanırken en azından temel güvenlik önlemlerini almalısınız.


Kaynak: Microsoft'un bir sunumundan...

Uzun yıllardır gerek projeler kapsamında, gerekse tam zamanlı olarak verilerin çok hassas olduğu sağlık ve finans sektörlerlerinden birçok kurumda çalışmalar yaptım. Kontrolümde olan sunucular yüzlerce kez dahili ve harici denetimlere tabi tutuldu. Aşağıda sizlerle bu tecrübelerimden aklıma gelen başlıca maddeleri paylaşmak istiyorum. Eğer birçoğu klasikleşmiş bu maddeleri ortamınıza uygulayabilirseniz, SQL Server kapsamında alınabilecek başlıca güvenlik tedbirlerini almış olursunuz. Hem kendi güvenliğinizi sağlamış olursunuz, hem de olası denetimlerde başınız ağrımaz.

- SQL Server'ın varsayılan (daha fazla bilgi için) portu 1433'tür, bunu dünyadaki tüm saldırganlar bilir. Farklı bir port kullanın.

- SQL Server kurulumuyla birlikte "sa" hesabı varsayılan olarak gelir. Bunu da aynı şekilde tüm saldırganlar bilir. Bu nedenle yukarıdaki loglarda da görebileceğiniz üzere "sa" hesabı da saldırılan hesaplardan biriydi. "sa" hesabının yerine başka kullanabileceğiniz "sysadmin" rolü üyesi hesaplar olduğundan emin olduktan sonra "sa" hesabını "Disable" duruma getirin veya "sa" hesabının adını değiştirin.

- Guest hesabını kullanmayın. Public kullanıcısına yetki vermeyin.

- Kullanıcılarınızın Login'ler için basit veya boş şifreler belirleyebilmesini engelleyin. 

- Mümkün olduğunca SQL Authentication yerine Windows Authentication'ı tercih edin.

- Yazılımcılarınız "SQL Injection" konusunda bilinçlendirilmeli. Uygulama arayüzlerinde kullanılan metin kutuları sadece almaları gerektiği türden ve uzunlukta değerler almalı. Örneğin sayısal bir değer kutusuna metin girilememeli veya TC Kimlik No alanına 11'den fazla karakter girilememeli.

- Uygulamalarınız sadece ihtiyacı olan uygulama kullanıcılarıyla erişsin veritabanına. Böylece uygulamanızdaki bir açık vasıtasıyla veritabanına ulaşılırsa, sadece uygulamanın ulaşabileceği veriye ulaşılabilir olsun, daha fazlası yapılamasın.

- Kod yazarken güvenlik (ve performans) açısından mümkün olduğunca dinamik SQL kullanmayın. Kullanacağınız zaman da dinamik SQL metinlerini güvenlik denetimine tabi tutmadan çalıştırmayın.  Örneğin "Doğum Yılı" veya benzer bir veri giriş kutusuna kesme işareti, "DROP, ALTER, GRANT, EXECUTE" gibi komutlar girilememeli.

- Uygulama yazarken kesinlikle ve hiçbir zaman son kullanıcının gireceği veriye güvenmeyin. Sadece güvenlik açısından değil, performans ve işlevsellik açısından da.

- Uygulama yazılırken sadece işlev değil, güvenlik (ve performans) odaklı yazılmalı. Yazılımcılar bu konuda net olarak bilinçli ve eğitimli olmalı. Projeler sadece işlevsellik ihtiyaçlarının giderileceği kadar sürelendirilmemeli. Yazılımcılar ve iş analistleri üstünde zaman baskısı olursa herkes sadece işlevselliğe odaklanır. Güvenlik ve performans testleri için de projelere süreler eklenmeli. Gerçekçi süreler! Zaman baskısı nedeniyle birçok şirkette hala doğru düzgün işlevsellik testi bile yapılmadan canlıya kod taşıması yapıldığını biliyorum maalesef.

- Her seviyedeki tüm kullanıcılara, sadece gerektiği kadar yetki verilmeli. Birçok ortamda gördüğümüz gibi tüm kullanıcılar "sysadmin" olmasın veya tek bir kullanıcıyla (genellikle "sa") tüm sistemi yönetmeye kalkmayın.

- Veritabanı yöneticisinin işlemleri dahil tüm kritik işlemleri 3. parti araçlarla veya SQL Server'ın sağladığı imkanlarla kayıt altına alın. Fakat birçok ortamda olduğu gibi sadece işlemleri kaydetmekle kalmayın, bu kayıtları otomatik olarak inceleyin ve anlam çıkartın ve sonuçlar için alarmlar ve raporlar ürettirin. 

- Görevler ayrılığı ilkesini işletin. Domain veya Windows yöneticileri için "sysadmin" rolüyle kullanıcılar olmadığından emin olun. Mümkünse herkes kendi işini yapsın. Örneğin bir önceki maddede bahsettiğim kayıt mekanizmasını hem kuran, hem yöneten aynı kişi olmamalı. Kayıt altına alınan işlemler değiştirilememeli.

- Sisteminizde her zaman neyin normal, neyin anormal olduğunu bilmelisiniz. Nasıl performans için bir referans hattınız varsa (var, değil mi?), güvenlik için de bir referans hattınız olmalı. Örneğin özellikle çok kritik tablolardan toplu sorgulamalar yapılmasını istemeyebilirsiniz ve böyle bir şey olduğunda haberdar olmak isteyebilirsiniz. Böyle tabloları belirleyin ve gerekli alarm mekanizmalarını kurun.

- Yazılımcılar, iş analistleri ve diğer personel uygulama kullanıcılarının şifrelerini bilmemeli. Bu bilgiler (Connection String) şifreli saklanmalıdır.

- Yazılımcılar, iş analistleri ve diğerlerinin doğrudan canlı sunuculara uygulama kullanıcılarının bilgileri ile bağlanamamasını sağlayın. Canlı sunuculara uygulama kullanıcıları kullanılarak ancak uygulama sunucularından veya ilgili sunuculardan ve uygulamalar aracılığıyla gelinebilmeli.

- Mümkünse canlı ortamınız için ağ bölümü ile koordineli çalışarak IP kısıtlaması koydurtun. Canlı ortamınıza mümkünse sadece belli IP adreslerinden/bloklarından (uygulama sunucuları) gelinebilsin.

- Gerek canlı ortamınız, gerekse geliştirme ve test ortamınızdaki hassas verilerinizi maskeleyin. Sadece yetkili kişiler, görmeleri gereken verilerin, görmeleri gereken kısımlarını görebilsinler. Hem bir veri sızıntısı durumunda ilgili, ilgisiz herkes zan altında kalmamış olur, hem saldırganların işi zorlaşmış olur, hem de olası sızıntının nereden kaynaklanabileceği hakkında inceleme yapacağınız daha dar bir alan olur.

- Veritabanı yedeklerinizi de canlı ortamınızı koruduğunuz gibi koruyun. Mümkünse yedeklerinizi şifreleyin (Backup Encryption SQL Server 2014 ile geldi). Yedeklere kimlerin erişebildiği net ve sınırlı olmalı. Ayrıca mümkünse kimlerin eriştiğinin kaydı tutulmalı ve raporlanmalı.

- SQL Server servis hesaplarınız olarak Local System gibi geniş yetkilere sahip hesapları kullanmayın. Eğer bir Domain hesabı kullanacaksanız bu normal bir "Domain User" hesabı olsun mesela.

- CLR veya xp_cmdshell gibi aktif olarak kullanılmayacak hiçbir özelliği etkinleştirmeyin. Kullanmayacağınız hiçbir SQL Server servisini veya uygulamayı veritabanı sunucunuza kurmayın.

- Daha ileri seviye güvenlik tedbirleri için örneğin diskteki veriyi ve yedekleri korumak için Transparent Data Encryption özelliğini kullanmayı düşünün. (İleri seviye. Enterprise Edition gerektirir.)

- Veriyi hareket halindeyken (uygulama ve veritabanı arasında gidip geliyorken) ve veri veritabanında dururken şifreli olsun istiyorsanız SQL Server 2016 ile birlikte gelen Always Encrypted özelliğini kullanmayı düşünün. (İleri seviye, her senaryo için uygulanabilir değil. Enterprise Edition gerektirir.)

- Kullandığınız SQL Server versiyonunun güncel sürümlerini kullandığınızdan emin olun.

- Güvenlik haberlerini yakından takip edin, sadece yazılımlarınızı değil, kendinizi de güncel tutun.

Unutmayın, güvenlik sadece ağ katmanı veya daha çok bütçeniz varsa güvenlik bölümlerinde kullanılan pahalı araç gereçlerle sınırlı değildir. Diğer katmanlardan bağımsız olarak sadece veritabanında alacağınız önlemler de yeterli değildir. Geliştirdiğiniz ve kullandığınız uygulamalarınız da kesinlikle bir istisna değildir, olamaz. Güvenlik baştan sona bir bütündür, şirket sekreterinden girişteki güvenliğe, finans müdüründen yazılım mimarına kadar bir takım işidir. Bu katmanlar zincirindeki en zayıf halkanız kadar güçlüdür güvenliğiniz.


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

18 Eylül 2017 Pazartesi

Performans: Kendi kendini sabote etmek

Vahşi yaşamdaki Sahadaki sunucularda sağlık kontrolü ve performans iyileştirmesi gibi çalışmalar yaparken, hangi akla hizmet hiç anlam veremediğim bazı ilginç ayarlar yapıldığını, sunucularda aylardır oluşan hataların izlenmediğini ve haliyle herhangi bir müdahalede de bulunulmadığını görüyorum. Ahh, sonra bir de "SQL Server kötü" demiyorlar mı!

Bu tür durumlar, ki piyasada gerçekten çok yaygın, son model spor aracınızı el freni kalkık şekilde kullanmaya benziyor. Donanım kaynaklarına ve lisanslara onca para harcanıyor, fakat bu yatırımlardan verimli bir şekilde faydalanılamıyor.

Geçenlerde 16 işlemci çekirdekli bir sunucuda çalışma yaparken zaman zaman aşağıdaki hataların alındığını gördüm:

"New queries assigned to process on Node 0 have not been picked up by a worker thread in the last 240 seconds. Blocking or long-running queries can contribute to this condition, and may degrade client response time. Use the "max worker threads" configuration option to increase number of allowable threads, or optimize current running queries. SQL Process Utilization: 5%. System Idle: 93%."

Ve bu hatalarla birlikte Dump alınıyordu.

Bu hata mesajı sorguların uzun sürdüğünün, olası bağlantı hatalarının ve CPU kaynaklarının verimli kullanılmadığının işaretidir.

Bekleme tiplerini kontrol ettiğimde "Threadpool" bekleme tipinin "CXPACKET"tan hemen sonra geldiğini görüyordum. Konumuz dahilinde değil, ama "CXPACKET" bekleme tipi paralelliğin kullanıldığı tüm ortamlarda olur ve kendi başına doğrudan bir sorun anlamına gelmez. Fakat ilk 10 bekleme tipi arasında "Threadpool"u görüyorsanız ve bu da ikinci sıradaysa "Worker Thread"lerle ilgili bir sorununuz var ve buna odaklanmanız gerekir demektir.


Threadpool bekleme tipi sorununun görseli

Peki nedir bu "Threadpool" ve "Worker Thread"?

Threadpool, çok miktarda istemci sunucuya bağlandığında performansın optimize edilmesini sağlar. Kullanıcıların yaptığı talepler için, yani çalıştırdıkları sorgular için bir Thread havuzu oluşturur. Threadpool'da kullanılabilecek Worker Thread sayısını SQL Server sunucu mimarisi ve işlemci çekirdek sayısına göre Database Engine servisinin başlangıcında yapar. Bu şartlara göre oluşturulacak Worker Thread sayısını Microsoft'un dokümantasyonundan inceleyebilirsiniz.

Eğer bu hesaplamaya müdahale etmeniz gerekirse, ki şahsen henüz bunu gerektirecek bir durumla hiç karşılaşmadım, o zaman "Max Worker Thread" ayarını değiştirmeniz gerekir. Bu ayar varsayılan olarak 0'dır ve çok istisnai durumlar haricinde de 0 olarak kalması gerekmektedir.

Herhangi bir SQL Server Instance'ındaki o anki "Max Worker Thread" sayısını görmek için aşağıdaki komutu çalıştırabilirsiniz:

SELECT [max_workers_count] FROM sys.dm_os_sys_info;

"Max Worker Thread" ayarınızı görmek için de aşağıdaki komutu kullanabilirsiniz:

SELECT [value], [value_in_use] FROM sys.configurations WHERE [name] = 'max worker threads';

Eğer "Max Worker Thread" ayarınız için [value] ve [value_in_use] alanlarının değerleri 0 ise ayarınız varsayılan değerdedir ve önceden de belirttiğim gibi birçok ortam için de doğru olan değer budur. Eğer bu alanlardan herhangi biri 0 değilse, birisi bu ayarı değiştirmiştir ve eğer bunu gerçekten işini bilen birisi yapmadıysa büyük ihtimalle bu hatalı bir hamledir. Eğer bu ayarı değiştirmeniz gerekirse, değişikliği uyguladıktan sonra Database Engine servisini yeniden başlatmanız gerekir, aksi takdirde değişiklik hemen devreye girmez.

Gelelim Worker Thread'in ne olduğuna. SQL Server'da her bir işlemci çekirdeği Scheduler'la temsil edilir. SQL Server Instance'ınızda kaç tane Scheduler olduğunu, bunların kaç tanesinin kullanılabilir (Visible) olduğunu sys.dm_os_schedulers isimli DMV'yi sorgulayarak görebilirsiniz. Örneğin bazı Scheduler'lar sistem tarafından kullanılır, bazıları ise lisanslama yüzünden (bakınız) pasif durumda olabilir. Worker Thread'ler, Scheduler'lar tarafından kendine atanmış olan Task'ları (örneğin bir sorgunun çalışması veya log in işlemi gibi) çalıştırırlar. Mesela havuzda yeterince kullanılabilir Worker Thread olmazsa bu nedenle "Login failed" hataları alabilirsiniz.

Peki 16 çekirdekli bir işlemci kaynağının olduğu bu ortamda yukarıdaki hata neden alınıyordu dersiniz? Sağolsun birisi ne hikmetse bu ayarı "255" olarak değiştirmiş. Bu nedenle havuzda "704" Worker Thread olabilecekken "255" tane var. Yani aslında ortamda yeterli altyapı var; ama el freni kalkık ve SQL Server çığlık ata ata çalışıyor... Haliyle bir Blocking sorunu oluştuğunda, paralel veya uzun süren bir işlem sık ve yaygın olarak çalıştırıldığında yukarıdaki gibi hata mesajlarına rastlamak da olası oluyor.

Sistem yöneticisi, veritabanı yöneticisi, yazılımcı (evet maalesef...), SQL Server yönetimi yapan tüm arkadaşlar! Eğer ne yaptığınızdan emin değilseniz, emin olmadığınız bir ayarı değiştireceğinize lütfen varsayılan haliyle bırakın. O ayarı çok merak ediyorsanız, o ayar sizi çok rahatsız ediyorsa ve farenize hakim olamıyorsanız buyurun Türkçe Microsoft SQL Server forumlarında sorun, ben veya başka bir arkadaşım müsait olduğunda elinden geldiğince cevaplar. Bu yazıda bahsettiğim sadece bir örnek, bunun gibi daha niceleri var. Yapmak istediğiniz değişiklikleri lütfen ne yaptığınızdan emin olduktan sonra yapın.

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

6 Eylül 2017 Çarşamba

Veritabanı sunucularınızın maliyetleri nasıl azaltılır?

Her sektörden birçok firmaya giriyorum, çıkıyorum. Bazılarıyla sadece sohbet ediyoruz, bazılarıyla kısa dönemli, bazılarıyla da uzun dönemli çalışıyoruz. Her firmanın kendine göre ihtiyaçları var, bununla birlikte sonuç itibariyle tüm şirketlerin hedefleri aşağı yukarı aynı:

Yapılması gereken işlemlerin düşük maliyetle, kesintisiz olarak ve performanslı şekilde tamamlanması. Bu sayede firma çalışanlarının daha verimli çalışmasının ve müşteri memnuniyetinin sağlanması. Verimlilik.

Bu amacı gerçekleştirmek için bazı yöneticiler daha fazla donanım veya personel alımı yapıyor. Bu yatırımlarla sorunun çözülmediğini gördüklerinde ise hayal kırıklığına uğrayıp sorunun o anda kullandıkları üründen kaynaklandığını düşünebiliyorlar.

Benim örneğimde, tahmin edebileceğiniz gibi Microsoft SQL Server'dan bahsediyorum. Bugüne kadar bu konuda birçok yazı (son 1 senedeki yazı1, yazı2, yazı3, yazı4, yazı5, yazı6) yazdım. Bu seferki de çarpıcı bir örnek diye ayrıca paylaşmak istedim.

Aşağıda, bakım ve destek anlaşması kapsamında çalışma yaptığım sunuculardan birine ait işlemci kullanımının grafiğini paylaşıyorum. 

Büyütmek için resmin üstüne tıklayın.
Bu sunucuda 16 CPU Core'u mevcut. Yine bu sunucuda 1 ay içerisinde gerçekleştirdiğimiz performans iyileştirme çalışmaları sonucunda işlemci kullanımını zirve yaptığı zamanlarda bile %70'lerden %10 civarına indirdik. Gün içerisinde ise işlemci kullanımı eskiden %40 civarındayken artık ortalama %2'yi geçmiyor.

Bu çalışmanın sonucuna daha geniş bir kapsamdan bakarsak: 
- Microsoft SQL Server, 2012 versiyonundan beri Core başına lisanslanıyor. Eğer Open Licensing gibi bir anlaşmanız yoksa lisanslama maliyeti Enterprise Edition için Core başına 14,256$, Standard Edition için ise 3,717$ (kaynak). 16 Core'lu bir Enterprise Edition 228.096$ ediyor. Yukarıdaki gibi bir performans iyileştirme çalışması sonucu artık gereken işlemci kaynağı büyük ölçüde azalmış oluyor. Bunun sonucu olarak en basit haliyle işlemci kaynakları %50 azaltıldığında bile doğrudan ve sadece Microsoft SQL Server lisanslamasından 114 bin dolarlık kar sağlanmış oluyor.

- Birçok firmada çok elzem olmadığı halde Enterprise Edition kullanıldığını görüyorum veya bazı projelerin sadece Enterprise Edition'da gerçekleştirilebileceği düşünülebiliyor. SQL Server 2016 + Service Pack 1 ile birlikte birçok Enterprise Edition özelliği artık Standard Edition'a da geldi (konu hakkındaki yazım). SQL Server 2016 ile gayet şık ve iş gören sürekli kullanılabilirlik ve felaketten kurtulma projeleri gerçekleştirebiliyoruz. Yukarıdaki gibi bir performans iyileştirme çalışmasından sonra Enterprise Edition'a geçmeye hiç gerek kalmadan veya Standard Edition'a Downgrade yaparak lisans maliyetlerini neredeyse 4 kat düşürmek birçok senaryo için mümkün. Bir önceki madde üstünden gidecek olursak 8 Core'dan oluşan 114 bin dolarlık Enterprise Edition maliyetini, 8 Core'dan oluşan Standard Edition ile 29,736$'a düşürebiliriz.

- Lisans maliyetinin yanısıra, artık daha az donanım kaynağı gerektiği için donanım maliyetlerini de azaltmış oluyoruz.

- Şirket çalışanlarının gün içerisinde verimli çalışabildikleri 2-3 saati en verimli şekilde kullanabilmeleri sağlanmış oluyor. Daha az zamanda, daha çok iş gerçekleştirilebiliyor.

- Nihai olarak son kullanıcı olan müşteriler de memnun oluyor.

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

1 Ağustos 2017 Salı

Sahadaki sunucu sağlık-kontrolü tecrübelerimden birkaç kesit

Uzun zamandır sahada, şirketlerin en kritik Microsoft SQL Server sunucularında sağlık-kontrolü çalışmaları yapıyorum. Şirketler bu çalışmayı başlıca şu nedenlerle talep ediyor:

- Kurulum en iyi pratiklere göre yapılmamış, vakti zamanında bir yazılımcı veya sistem yöneticisi "ileri" düğmesine tıklayarak yapmış kurulumu,
- Nedeni net olarak anlaşılamayan ve veritabanından kaynaklandığı tahmin edilen performans sorunları var,
- Veritabanı sunucusu uzun zamandır kendi kendine, bir şekilde çalışıyor, ama acaba her şey gerçekten de yolunda mı diye merak ediliyor ve bir bilenin kontrol etmesi isteniyor.

Şunu belirtmekte fayda var, veritabanı yöneticisi pozisyonu illa her şirkette olmak zorunda olan bir pozisyon değil. Çünkü birçok şirketin tam zamanlı olarak bir veritabanı yöneticisi çalıştırması gerekmiyor, bu nedenle bir süre varolan personel kaynağıyla durum idare ediliyor; özellikle KOBİ'ler için bu hem maliyet, hem de fayda açısından makul olmayabiliyor. Bununla birlikte veritabanı sunucularınız olduğunda, ki aşağı yukarı her şirketin vardır diyebiliriz, barındırılan veriler illa ki kritik oluyor ve IT yöneticileri bu verilerin sağlığından endişe ediyor.

Şimdiye kadar yaptığım sağlık-kontrolü çalışmalarını 3GB'lık veritabanı sunucularından tutun, 20TB'lık veritabanı sunucularına kadar uyguladım. Bu çalışmalar sayesinde birçok sürpriz ve olası felaket durumlarını ortaya çıkarttım. Bu yazıda bu sürprizlerden bazılarını, özetle de olsa vurgulamak istedim. Böylece belki hiç beklemediğiniz olası sürprizler hakkında sizin de haberiniz olur veya önlem almak için bir algı oluşur.

Senaryo 1:
Şirket yetkilisi veritabanlarının çok önemli olduğunu, finansal veri içerdiğini, güvenlik açısından asla taviz veremeyeceklerini iletti.

Sunucuyu kontrol ederken karşılaştığım en çarpıcı noktalar:
- Veritabanı sunucusunun internete açık olması,
- SQL Server TCP port numarasının varsayılan port numarası olan 1433 olması,
- "sa" kullanıcısının etkin olması ve şifresinin basit olması,
- Error Log dosyasında birçok farklı sunucudan, "admin", "sa" gibi birçok farklı kullanıcı adıyla bu "kritik" olan sunucuya bağlanılmaya çalışılmasıydı.

Bu konuda bilgili ve tecrübeli olanlarınız bunların çok bariz ve temel şeyler olduğunu düşünebilir, ama unutmayın, bunlar bilene kolay...

Senaryo 2:
Çok kritik verileri olan bir başka şirket veritabanı sunucularının sağlık kontrolünü yapmamı istedi, veritabanlarındaki veriler yine finansal açıdan çok kritik.

Sunucuyu kontrol ederken en kritik olan veritabanının yedeğinin en son 2 ay önce alındığını gördüm. Bunu kendilerine ifade ettiğimde, elbette oldukça soğuk bir duş etkisi yarattı.

Senaryo 3:
Uluslararası ortakları olan bir firma ile sağlık kontrolü çalışması yaparken, veritabanı yedeklerinin disk doluluğu nedeniyle uzun zamandır alınamadığını gördük. Maalesef ortamda disk kapasite takibi veya Job'lar hata aldığında bunları izleyecek bir mekanizma yoktu. Bu nedenle kimsenin bu hatalardan haberi olmamıştı.

Senaryo 4:
Bir firmanın kritik bir sunucusunda sağlık kontrol çalışması yaparken sunucuda ortalama olarak eşit şekilde yük yaratması beklenen en kritik iki veritabanından birinin aslında CPU, IO ve RAM kaynaklarının %80'ini kullandığını gördük. Tabii bir sorun olduğu net olarak ortaya çıkmış oldu ve iyileştirme çalışmaları için sistem kaynaklarını beklenenden daha fazla tüketen veritabanına odaklanıldı.

Senaryo 5:
Firmanın en kritik veritabanı sunucusunda performans sorunları olduğu iletildi. Sağlık kontrolü çalışması yaparken, 45 dakika ve daha fazla süren sorgular olduğunu tespit ettim. Kimsenin bu kadar uzun süren sorgular olduğundan haberi bile yoktu. Bu ve benzeri sorguları tespit edip, iyileştirme çalışmaları yaptıktan sonra sorunun büyük bir bölümü çözülmüştü.

Senaryo 6:
Canlı ortam olarak kullanılmak üzere düşünülen bir ortama Always On Availability Groups (AG) kurulumu yapılmıştı. Kurulumun yapılandırılmasını kontrol ettiğimde, kurulumu yapanların bir Listener oluşturmadıklarını gördüm. Kurulumu yapanlar, firmaya Connection String'te Cluster adını kullanabileceklerini iletmişti. Firmaya bunun -malumunuz- böyle çalışmayacağını, dilerse test edebileceğini ve testin hata ile sonuçlanacağını ilettim. Tabii ki test hata ile sonuçlandı. Firma tekrar kurulum yaptırmak istemediğini, bütçe ayıramayacağını söyledi ve firmanın "stand-alone" olan sistemlerini Always On AG ortamına taşıma projesi rafa kaldırıldı.

İlginizi çektiyse sağlık-kontrolü çalışmam hakkında daha fazla bilgi için lütfen buraya tıklayın.

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

17 Temmuz 2017 Pazartesi

Bir içeriden saldırı hikayesi

Geçen hafta bir firmadan bir e-posta aldım, içeriği aynen şöyleydi:

"Elektrik gidip geldi ve SQL Database Recovery Pending moduna geçti. Konu hakkında yardımcı olabilir misiniz?"

Kısa ve öz.

Kendilerini aradım, konuştuk. Gündüz başka işlerim olduğu için, akşam bağlanıp kontrol edebileceğimi söyledim kendilerine. Akşam bağlanıp kontrol ettiğimde ve görüşmelere devam edip durum hakkında daha fazla şey öğrendiğimde ortaya çıkan tablo şöyleydi:

- "Recovery Pending" durumunda olduğu söylenen veritabanı dosyaları "Corrupt" idi, yani bozulmuşlardı,
- Bozulan veritabanı bir muhasebe uygulamasına aitti,
- Bozulan veritabanının yedek dosyaları da bozulmuş durumdaydı,
- Bozulan veritabanının normal şartlarda bağlı olduğu SQL Server Instance'ı silinmişti,
- Bozulan veritabanına ait yedek dosyaları Rar uygulaması ile şifreli sıkıştırılmıştı,
- Bozulan veritabanına ait ulaşılabilen ve çalışır halde olan en güncel yedek 3 ay öncesine aitti.

Sanırım hikayenin aslının ne olduğunu, biraz da dehşete kapılarak tahmin etmişsinizdir. Ben durumun böyle olduğunu gördüğümde, görüştüğüm yetkiliye bu durumun ancak "sinirli" ve "kırgın" bir şekilde işten ayrılan eski bir çalışan tarafından oluşturulabileceğini ilettim. Kendisi de bu senaryoyu onayladı.

Veritabanı dosyaları ve yedekler gerçekten elektrikler birden gidip sunucu kapandığı için mi, yoksa eski çalışan tarafından kasten mi bozulmuştu bilemiyorum, bunun aslını sanırım ancak beni arayan kişi ve işten ayrılan kişi bilir; ama durum içinden çıkılmaz bir haldeydi. Çünkü tüm kontrol sadece o işten ayrılan kişideydi, başka hiçbir yedekleme mekanizması yoktu. Haliyle ben de bir şey yapamadım.

Saldırıları veya felaketleri sadece firma dışından beklemeyin. Paranoyak olun ve herkese düşman gibi nefretle bakın demiyorum elbette, ama gerekli önlemleri aldığınızdan emin olmalısınız. İnsanların niyeti iyi veya kötü olabilir, siz her türlü niyet ve senaryo için olabildiğince hazırlıklı olmalısınız. Aksi takdirde kendinizi yukarıdakine benzer bir senaryonun oyuncularından biri durumunda bulabilirsiniz.

Not: Bir çözüm üretemediğim, müşteriyi memnun edemediğim işlerden ücret talep etmiyorum. Fakat en azından harcadığım o kadar zaman ve emek için bir teşekkür beklemek sanırım hakkım. Maalesef bu firmadaki yönetici arkadaş bunca inceleme ve harcanan zaman sonrası gönderdiğim durum raporuna cevap bile vermedi. Yine maalesef, bu örnek tek değil. Bu gibi durumlarda iletişime geçen herhangi bir kişi veya firmaya neden hemen yardımcı olmak istediğimi, bu kadar iyi niyetli yaklaştığımı ciddi ciddi sorguluyorum. Bazıları böyle bir ilgiyi gerçekten, hiç hak etmiyor.

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

11 Temmuz 2017 Salı

"Transaction Log" yedeğinin alınması neden uzun sürebilir?

Son zamanlarda bir ortamda Transaction Log yedeği alınırken yedek alma işleminin 1-2 saati bulabildiğini gözlemledim. Normal şartlar altında 2 dakikada bir yedek alınan ve yedeklerin de ortalama 10MB olduğu bir ortamdan bahsediyorum.

Sorunu incelerken Transaction Log yedek alma işleminin (BACKUP LOG ...) bir sistem işlemi tarafından (o anki "session_id"si 18 idi) bloke edildiğini gördüm. İşler gerçekten ilginçleşiyordu. O sistem işleminin ne olduğunu inceleyince Checkpoint olduğunu gördüm. Açıkçası, Checkpoint işleminin Transaction Log yedek işlemini bloke ettiğini ilk defa görüyordum.

Sorunu daha fazla inceledikçe aslında sorunun disk altyapısında olduğunu tespit ettim. Yani Transaction Log yedek alma işlemi aslında doğrudan kendi başına bir sorun değildi, başka bir sorunun sonucu oluşan bir durumdu.

Aklına "Disk altyapısındaki sorun, Checkpoint ve Transaction Log yedeği ne alaka?" diye soru gelenler için Checkpoint işlemine çok özetle deyineyim. SQL Server'da varolan kayıtlarda değişiklikler yaptığınızda veya yeni kayıtlar oluşturduğunuzda bu değişiklikler doğrudan veritabanı veri dosyalarına işlenmez, önce Transaction Log dosyasına işlenir, daha sonra da belli formüllere göre devreye giren Checkpoint ile bu değişiklikler ilgili veritabanı veri dosyalarına işlenir. Disk altyapısında performans sorunu olunca, Checkpoint ile değişikliklerin diske işlenmesi uzun sürüyordu ve bu da Transaction Log yedeklenmesi işlemini bloke ediyordu. Ben de bu sayede Checkpoint devam ediyorken Transaction Log yedek alınma işleminin sonlanamadığını, bloke olduğunu öğrenmiş oldum.

Biraz kısa bir yazı oldu, ama yine de değerli bir tecrübe olduğunu düşünerek paylaşmak istedim. Olur da bir gün Transaction Log'unun yedeğinin alınması uzun sürerse, disk altyapısının performansını da kontrol etmeyi unutmayın.

Not: Transaction Log ve veritabanı yedekleme işleminin uzun sürmesinin daha başka birçok nedeni var, ama bu yazıda belirli bir konuya değinmek istedim. 

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

3 Temmuz 2017 Pazartesi

Bakım çalışması sırasında disk alanının geçici olarak azalması durumu

Yönettiğim ortamların birinde aşağıdaki gibi bir senaryo oluştu, durumu bir veritabanı yöneticisinin ağzından aktarayım:

- Veritabanının veri dosyalarından biri (*.mdf veya *.ndf) E: diskinde konumlandırılmış durumda,
- Bu veri dosyasının otomatik büyüme (auto growth) özelliği kapalı,
- Gece diskin kapasitesine dair bazı alarmlar gelmiş. Sabah kalktığımda kontrol ettim, diskte sadece veritabanı veri dosyası görünüyor ve dosya değiştirilme tarihi bugünden daha eski bir tarih, bu dosya büyümemiş bundan eminim. Diskin boyutu da alarmlarda belirtilenden farklı. Zaten alarmlar da belli bir süre sonra durmuş.
- Bunun nasıl bir açıklaması olabilir?

Bu durum, DBCC CHECKDB komutuyla bütünlük kontrolü yapılırken oluşabilir. Eğer yukarıdakine benzer bir senaryo yaşadıysanız, ki umuyorum ki düzenli olarak en azından haftada bir kere bu bakımı yapıyorsunuzdur, bunun nedeni DBCC CHECKDB komutunun oluşturduğu dahili "snapshot"tır.

Dahili "snapshot" veritabanı, DBCC CHECKDB komutunun çalıştırıldığı veritabanının her bir veri dosyası için aşağıdaki ekran görüntüsünde olduğu gibi ayrı ayrı "snapshot" dosyaları oluşturur. Örneğin aşağıdaki durumda diskin kapasitesi 500GB idi; ama iki tane 460GB'lık dosya görüyorsunuz, peki bu nasıl oluyor? Çünkü "snapshot" dosyalarının boyutları her ne kadar veri dosyalarıyla aynı görünse de, o kadar yeri birden rezerve etmiyorlar. Bu dosyalar, dosya sistemi seviyesinde "sparse" olarak işaretlenirler. DBCC CHECKDB komutu çalıştığı sürece ilgili veritabanında ne kadar çok işlem yapılıyorsa, bu "snapshot" dosyaları da o kadar dolar.


Yine bu senaryoda E: diskinin kapasitesi 500GB iken ve gerçek veritabanının veri dosyasının boyutu 460GB iken, gelen disk kapasite alarmları azar azar artarak geliyordu. Bunun nedeni de bir önceki paragrafta belirttiğim gibi "snapshot" dosyalarının DBCC CHECKDB komutu çalışmaya devam ederken gerçek veritabanı dosyasında yapılan değişiklikler nedeniyle, yine yapılan işlem hacmine göre dosyanın adım adım dolması.

Veritabanı bütünlük kontrolü tamamlandıktan sonra "snapshot" dosyaları otomatik olarak silinir. Eğer sunucu veritabanı bütünlük kontrolü sırasında beklenmedik bir şekilde kapanırsa, o zaman bu dosyalar silinmez ve hem diskte boş yere yer kaplarlar, hem de tekrar bütünlük kontrolü yapmaya kalktığınızda ilginç hatalarla karşılaşabilirsiniz.

DBCC CHECKDB komutu zaten çok IO yoğunluklu bir işlemdir. Bu nedenle muhakkak veritabanı sistemlerinizin "yatış" durumunda oldukları zaman çalıştırılmalıdırlar. DBCC CHECKDB komutunun neden yoğun zamanlarda çalıştırılmaması gerektiğine bir de bu yazımda anlattığım nedeni ekleyebilirsiniz. Çünkü DBCC CHECKDB komutu çalıştığı sürece veri dosyalarınızın bulunduğu disklerin doluluk oranları artacaktır. Eğer disklerde yeterince yer yoksa çeşitli sorunlar yaşayabilirsiniz, en kötü ihtimalle can sıkıcı ve korkutucu alarmlar alabilirsiniz, ki umarım disk doluluk oranlarınızı yakınen takip ediyorsunuzdur.

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

23 Haziran 2017 Cuma

Yine, gene ve tekrar: Bir felaket hikayesi (veri kaybı) daha...

Ne kadar yazarsak yazalım (yazı, yazı, yazı) sonuçta yazdıklarımız, konuştuklarımız belli bir kitleye ulaşabiliyor.

Dün akşam bir tekstil firmasından aradılar ve teknik işlere bakan arkadaş telefonda şöyle dedi: 

"Bir veritabanı sunucumuz var ve bunun diskleri aslında yedekli, ama bu disklerden biri hata verdi ve yedek diskten veritabanı dosyalarını ve yedek dosyalarını kurtardık; ama bir türlü Attach edemiyoruz."

Sorunun yaşandığı SQL Server sunucusuna uzaktan bağlandım ve veritabanı dosyalarını ve yedek dosyalarını kontrol ettim.

Veritabanı dosyalarını Attach etmeye çalıştığımda bütünlük/IO tutarlılığı hatası alındığını gördüm. Bu etapta hata 9 sayılı Page'te alınıyordu. Bu da Boot Page demek. Bu noktada yedek dosyalarını düşündüm, fakat onların bütünlük kontrollerini yaptığımda veritabanı yedek dosyalarının bozulmuş olduğunu gördüm.

Veritabanlarının 6 ay önceki çalışan hallerinin sağlam kopyaları da ayrıca vardı. Sorun Boot Page'te olduğu için, eski veritabanlarından Boot Page'leri bu sorun yaşanan veritabanlarına aktarabilirdim. Bunu yaptım. Fakat gördüm ki tek sorun Boot Page'te değil. Boot Page'i onardıktan sonra da farklı farklı Page'lerde sorun yaşandığını gördüm. Sonraki kontrollerimde 3. Page'ten 36. Page'e kadar verilerin veritabanı dosyalarından komple silinmiş olduklarını gördüm.

Bu noktada artık şahsen benim yapabileceğim bir şey kalmadı. Kendilerine veri kurtarma konusunda çalışabilecekleri bir firma aramalarını önerdim. Ne kadar başarılı bir sonuç alınabilir, emin değilim; ama maalesef bu noktada artık görüşmeyi sonlandırdık.

Benim başıma gelmez demeyin, gerekli önlemleri almazsanız herkesin başına gelebilir bu durum. Geçen hafta sağlık bakımı çalışması yaptığım çok önemli bir veritabanı sunucusunda 2 aydır yedek alınmadığını tespit edip ilgili yöneticilere bildirdiğimde şok oldular.

Veritabanı dosyalarınızı ve aldığınız yedekleri aynı sunucu üstünde tutsanız bile en azından aynı disk altyapısında tutmayın. Mümkünse muhakkak yedeklerinizi uzaktaki, ayrı bir sunucuda düzenli ve güncel olarak barındırın. Kaybetmeye tahammülünüz olabilecek veri miktarını ve azami olarak ne kadar sürede geri dönmeniz gerektiğini önceden belirleyin ve yedekleme stratejinizi buna göre oluşturun. Yedekleme "kısmet" kategorisine girmeyecek kadar önemli bir konu. Yukarıda bahsettiğim tekstil firması muhtemelen son 6 aylık verisini kaybetti. Şirket bununla nasıl başa çıkacak bilemiyorum, ama umarım çok büyük kayıp yaşamazlar. Başkalarının hatalarından ders alarak kazanılan tecrübe, en ucuz ve acısız kazanılan tecrübedir, unutmayın.

Kazasız, belasız güzel günler dilerim.

Ekrem Önsoy
Microsoft SQL Server Danışmanı

6 Haziran 2017 Salı

Veritabanlarıyla rus ruleti oynamak

Yedeklemenin önemi ile ilgili (Bağlantı1, Bağlantı2) birçok yazı yazmama karşın maalesef sahada bu konuda birçok kötü pratik görüyorum. Son zamanlarda ilginç bir iş geldi. Önceden de bir projede birlikte çalıştığımız bir şirketten aradılar ve şöyle bir senaryo anlattılar:

- Yazılımcı, sistem yöneticisine Y veritabanının yedeğinin olup olmadığını soruyor,
- Sistem yöneticisi "var" diyor ve X konumuna Y veritabanının dosyalarını kopyalıyor,
- Yazılımcı, Y veritabanının zaten yedeği var diye, Y veritabanının kendisini (ayrıntılarını bilmediğim bir nedenden dolayı) ilgili SQL Server Instance'ından siliyor,
- Aradan 15 günden fazla bir süre geçtikten sonra yazılımcı X konumundaki yedeklerden dosyaları Attach ederek Y veritabanını geri getirmeye çalışıyor; fakat fark ediyor ki veritabanı dosyalarından biri eksik ve bu nedenle veritabanı Attach olmuyor,
- Yazılımcı, sistem yöneticisine bu eksikliği bildiriyor,
- Sistem yöneticisi geriye dönük olarak sadece 15 günlük yedek tuttuklarını iletiyor ve Y veritabanı ilgili SQL Server Instance'ından silineli 15 günden fazla olduğu için artık herhangi bir yerde bu veritabanının herhangi bir yedeğinin olmadığı anlaşılıyor,
- Bahsi geçen Y veritabanı, ilgili şirketin 4-5 senelik arşivi.
- Bu noktada benimle temas kurdular.

Hiçbir ekstra açıklamaya gerek kalmadan sırf yukarıdaki maddelerden, neyi nasıl yapmamanız gerektiğine dair birçok sonuç çıkarmışsınızdır diye tahmin ediyorum.

Bu sefer gerçekten çok şanslılardı ve veritabanını ciddi bir kayıp olmadan kurtarabildik. Ben elimden geleni yaparım, ama kimse bu konularda sadece şansına güvenmesin lütfen, her zaman bu seferki gibi şanslı olmayabilirsiniz.

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

18 Mayıs 2017 Perşembe

Bir sorun "çözme" yöntemi: SQL Server servisinin düzenli olarak kapatılıp açılması fenomeni

Microsoft SQL Server ortamları için "sağlık-kontrolü / healthcheck" ve performans iyileştirme çalışmaları için yeni müşterilere gittiğimde zaman zaman "Procedure ve Data Cache"in düzenli olarak boşaltıldığını veya Microsoft SQL Server sunucusunun düzenli olarak (mesela haftada bir veya ayda bir) yeniden başlatıldığını görüyorum. Müşteriye nedenini sorduğumda ise şöyle yanıtlar geliyor:

  1. Zamanla SQL Server çok RAM kullanıyor, bunu düzeltmek için,
  2. CPU kullanımı zaman zaman tavan yapıyor, sunucuyu yeniden başlatınca düzeliyor,
  3. Tam emin değiliz; ama zamanla SQL Server'da çalışan sorgular yavaşlıyor, yeniden başlatmak sorunları çözüyor.
  4. Sizden önceki gelen danışman veya X arkadaş böyle tavsiye etti,


    Bahsettiğim senaryoda aldığım yanıtlar aşağı yukarı hep böyle. Bu yanıtları özellikle numaralandırdım, çünkü aşağıda tek tek özetle açıklayacağım.

    1- SQL Server kurulumlarında varsayılan olarak SQL Server sunucuda varolan tüm hafıza kaynağını kullanmak üzere ayarlıdır ve doğası gereği sadece SQL Server değil, tüm veritabanı sistemleri olabildiğince RAM kullanmak ister. Ne kadar çok işlem diskten değil de doğrudan hafızadan yapılabilirse, işlemler o kadar hızlı gerçekleşir. 

    İşletim sistemi, SQL Server'ın kendi diğer bileşenleri veya sunucu üstündeki diğer uygulamaların da hafıza ihtiyacı vardır ve SQL Server yapılandırması da bu çerçevede ayarlanmalıdır. Aksi takdirde "Paging / Swap" oluşur, bu da uygulamaların ağır çalışmasına, yani performans sıkıntılarına neden olur. Çünkü yetersiz hafıza kaynağı nedeniyle uygulamalar çatışır ve Windows işletim sisteminin Page File'ı kullanılmaya başlanır. Yani hafıza (RAM) yerine bazı uygulamalar için fiziksel disk hafıza niyetiyle kullanılmaya başlanır, ki bu yöntem hafızaya göre defalarca kat yavaştır. Donmalara, uzun süreli beklemelere neden olur.

    2- Bunun nedeni genellikle "Parameter sniffing"tir. Parameter sniffing normal şartlar altında kendi başına bir sorun değildir, ama planlar anormal değerlere göre derlendiğinde parameter sniffing can yakabilir. Her sorgu çalışmadan önce o sorgu için bir çalıştırma planı (Execution Plan) oluşturulur ve bu çalıştırma planı da sorgu çalıştırılırken kullanılan ilk parametre değerine göre oluşturulur. Çalıştırma planı Plan Cache'te konumlandıktan sonra (parameterize sorgular, stored procedure'ler ve diğer basit sorgular gibi) ilgili sorgular artık bu planı kullanarak çalışır. Eğer plan en uygun şekilde ve en genel talebe hitap edecek değerlerle oluşmadıysa, kötü bir performans ile çalışabilir ve bu da CPU'nun ve diğer donanım kaynaklarının verimsiz olarak kullanılmasına neden olabilir.

    Plan Cache'i boşalttığınızda veya SQL Server servisini yeniden başlattığınızda (veya bazı SQL Server Instance'ı düzeyinde ayarı değiştirdikten sonra veya tekil bir planı Plan Cache'ten sildikten sonra) sorunlu çalıştırma planı gitmiş olur ve ilgili sorgu veya stored procedure ilk çalıştırışınızda yeni bir plan oluşturulur. Şansınıza yeni plan daha uygun değerler kullanılarak oluşturulabileceği için o anda "sorun çözüldü" sanabilirsiniz. Fakat Plan Cache'in bir dahaki sıfırlanışında veya herhangi başka bir nedenle ve zamanda bu plan yeniden kötü bir şekilde derlendiğinde yine bu sorunu yaşarsınız.

    Yani sunucuyu veya SQL Server servisini kapatıp açmak kalıcı bir çözüm değildir, bu nedenle sürekli kapatıp açmaya devam edersiniz.

    3- Bunun nedeni genellikle ya 2. maddede açıkladığım neden veya sorguların bloklanması (blocking) kaynaklı oluyor. Haliyle sunucu veya servis yeniden başlatılırken tüm bloke eden sorgular da sonlandırılmış oluyor ve servis yeniden başlayınca bloke olma sorunu "çözülmüş" oluyor.

    4- Eğer bir danışman veya X arkadaş ilk 3 maddede yaşanılan sorunlar için size en iyi pratik olarak "SQL Server servisini veya sunucusunu düzenli olarak yeniden başlatmayı" veya "Cache'leri boşaltmayı" önerirse arkanıza bakmadan kaçın. Tabii ofis ve ortam sizin olacağı için kaçamayacağınıza göre "arkadaşa" veya her ne sıfatla size bunu öneriyorsa ona bir çay ısmarlayıp nazikçe konuyu düşüneceğinizi iletebilir ve numarasını telefonunuzdan silebilirsiniz.

    Peki "Cache"lerin boşaltılması neden kötü?
    • Ad-hoc ve dinamik olmayan, parameterize olan tüm sorguların ilk çalışışlarında bir çalıştırma planı oluşturulur ve (sunucu ayarlarınıza göre) bu plan ilk veya ikinci seferinde Plan Cache'te konumlandırılır. Daha sonra ilgili sorgu / stored procedure her çalıştığında bu planı kullanır. Çalıştırma planının oluşturulma işlemi CPU yüklü bir işlemdir. Eğer sık sık Plan Cache'i boşaltırsanız veya ilgili sorgu her çalıştığında planın yeniden derlenmesini sağlarsanız sık sık tüm ilgili işlemler için yeniden çalıştırma planı oluşturulması gerekir ve bu da işlemlerinizin anlık olarak yavaşlamasına, genel olarak sunucu işlemci masraflarınızın artmasına neden olur.
    • SQL Server'da geleneksel (In-memory / Hekaton olmayan) bir tablodaki kayıtlar için işlem yapacağınız zaman bu işlem hafızada (RAM) yapılır ve daha sonra Lazy Writer veya Checkpoint ile diske aktarılır. Update, Delete ve Insert hangi DML komutu çalıştırırsanız çalıştırın, ilgili kayıtlar önce hafızada değiştirilir doğrudan diskteki kayıt değiştirilmez. Eğer değişiklik yapılmak istenen kayıtlar Data Cache'te / Buffer Pool'da yoksa, önce diskten okunur ve Buffer Pool'a getirilir ve kayıtlardaki değişiklik hafızada yapılır (bu durumda ilgili kayıtlar "Dirty Page" olur). Select için de aynı şey söz konusu, sorguladığınız kayıtları içeren Page'ler hafızada yoksa önce diskten Buffer Pool'a taşınır ve sorgunuz ondan sonra cevap verir. Bu nedenle işlem yapılacak kayıtların ne kadar çoğu hafızadaysa, işlemler o kadar hızlı gerçekleşir. Eğer siz düzenli olarak Buffer Pool / Data Cache'i boşaltırsanız, bu sefer her seferinde, her kayıt için önce diske gidip o kayıtları hafızaya yüklemek gerekiyor. Böyle bir ortamda da bol bol PAGEIOLATCH bekleme tipleri görürsünüz, çünkü diskleriniz harıl harıl çalışır durur, kullanıcılar yavaşlık hisseder. Bazı senaryolarda Deadlock ve Blocking'in nedeni de budur.
    Veritabanı sunucunuzu sürekli yeniden başlatarak ve Cache'leri düzenli olarak boşaltarak sorunları sadece ötelemiş olursunuz. Bu sorunları çözmek için SQL Server Instance'larınızın doğru yapılandırılması, sorunlu sorguların iyileştirilmesi, çalıştırma planlarının çeşitli tekniklerle istikrarlı hale getirilmesi ve gerekiyorsa dondurulması gerekiyor. Yukarıda maddeler halinde sıraladığım sorunların tek çözümü budur.

    Ekrem Önsoy
    Microsoft SQL Server Danışmanı

    4 Mayıs 2017 Perşembe

    Bir Cumulative Update kazası

    Bu sıralar bir müşterimin canlı veritabanı sunucusu için SQL Server 2012'den SQL Server 2016'ya sürüm yükseltme çalışmaları yapıyorum. Bu çalışmalar sırasında geçen sene de karşılaştığım, ama hakkında yazı yazamadığım bir sorun ile tekrar karşılaştım. Bu sefer bu sorunu günlüğüme kaydediyorum.

    Bu çalışma kapsamında yeni bir Windows Server 2016 kurulumu ve üstüne de SQL Server 2016 kurulumu yaptık. Müşterim SQL Server Standard Edition kullandığı için, SQL Server 2016 Service Pack 1 ile gelen birçok Enterprise Edition özelliğinden faydalanabileceği gibi SQL Server 2016 ile gelen yeniliklerden de faydalanabilecek. Bu ortamdaki en büyük maliyet disklerden kaynaklanıyor. Bu sürüm yükseltme çalışmasıyla Data Compression ve Columnstore indeksler ile müşterimin disk maliyetlerini ciddi oranda düşürmeyi ve aynı zamanda performansın iyileşmesini hedefliyorum. Ayrıca dahili ve harici denetim firmaları hassas verilerin maskelenmesini ve nesne düzeyinde kayıt tutulmasını talep ediyor; Dynamic Data Masking ile verilerin maskelenmesini ve Database Level Auditing ile de nesne düzeyinde kayıt tutulmasını sağlayacağız. Tüm bu ihtiyaçlar ekstra bir ürün alıp hem karmaşaya hem de ekstra maliyete neden olmadan sağlanmış olacak.

    Windows Server 2016'yı, SQL Server 2016'yı ve Service Pack 1'i kurduktan sonra en son Cumulative Update'i de kurarken, kurulumun sonunda gereğinden uzun süre bekleyince bir sorunun olduğunu anlamıştım. Tabii ki bekledim ve ardından beni bekleyen hata mesajıyla karşılaştım:


    Cumulative Update (KB4013106) kurulumunda oluşan hata mesajı
    Başlatılamayan tek servis "SQLSERVERAGENT" değildi, "MSSQLSERVER" yani Database Engine servisi de "Change Pending" durumunda kalmıştı. Windows Event Log'larını ve SQL Server Error Log'larını inceledim, şu mesajlar vardı:

    "Script level upgrade for database 'master' failed because upgrade step 'msdb110_upgrade.sql' encountered error 226, state 6, severity 16. This is a serious error condition which might interfere with regular operation and the database will be taken offline. If the error happened during upgrade of the 'master' database, it will prevent the entire SQL Server instance from starting. Examine the previous errorlog entries for errors, take the appropriate corrective actions and re-start the database so that the script upgrade steps run to completion."

    "Cannot recover the master database. SQL Server is unable to run. Restore master from a full backup, repair it, or rebuild it. For more information about how to rebuild the master database, see SQL Server Books Online."

    Nasıl, mesajlar yeterince korkutucu mu? Bu sefer bu sorun ile yeni, geçiş sunucusunda karşılaştım; ama geçen sene bu sorunla karşılaştığımda ortam canlı ortamdı. Benzer hataları bir de canlı bir ortamda aldığınızı düşünün...

    SQL Error Log'da aşağıdaki mesaj öbeğine odaklandım:


    SQL Server Error Log'tan bir görüntü

    Mesajlardan da görebileceğiniz üzere haliyle önce replikasyondan şüphelendim, bu sunucuda 70 küsur veritabanı var ve canlıda 2 tanesi Transactional Replication ile raporlama sunucusuna replike ediliyor. Önce bu 2 veritabanındaki replikasyon artıklarını kaldırmayı düşündüm ve bunu yapmam için de [sp_removedbreplication] sistem SP'sini çalıştırmam gerekiyor, ama Database Engine servisi hiç açılmıyor, bunu nasıl yapacağım?

    Neyse ki böyle durumlarda kullanabileceğimiz bir Trace Flag var, T902. Database Engine servisini Trace Flag 902 ile başlatırsanız, Service Pack veya Cumulative Update Script'leri servis açılışında çalıştırılmaz ve böylece Database Engine servisiniz açılabilir. Ben de böyle yaptım ve Database Engine servisini T902 ile çalıştırdım ve ardından ilgili 2 veritabanı için [sp_removedbreplication] komutunu çalıştırıp veritabanlarındaki replikasyon artıklarını temizledim ve Database Engine servisini T902'siz çalıştırdım. Maalesef sorun çözülmemişti.

    Not: Unutmayın, Trace Flag'leri bilinçli bir şekilde kullanmalısınız. Örneğin Trace Flag 902 sadece böyle bir durumda ve geçici olarak kullanılmalıdır. Canlı ortamınızı sürekli Trace Flag 902 çalıştırmamalısınız.

    Bu sefer hata mesajının oluştuğu silsileye odaklandım ve tam olarak her seferinde Upgrade Script'inin belli bir veritabanı adından sonra hata aldığını fark ettim. Bu veritabanı da önceden replike ediliyordu, ama uzun süre önce ilgili arkadaşların talebiyle replikasyondan çıkartmıştım. Database Engine servisini yine T902 ile çalıştırdım ve bu veritabanını bu SQL Server Instance'ından Detach ettim, yani bu veritabanının ilişiğini kestim. Daha sonra Upgrade Script'i olan [sp_vupgrade_replication] isimli Script'i Query Editor'den elle çalıştırınca hata oluşmadığını gördüm. Database Engine servisini T902'siz tekrar çalıştırdım ve Viola! Database Engine servisim artık sorunsuz çalışıyordu. Demek ki bir şekilde, kim bilir neden, ama bu veritabanımın içinde eski replikasyon kurulumuyla ilgili bazı sıkıntılar/artıklar vs kalmıştı ve Service Pack 1 kurulumunda değil, ama Cumulative Update kurulumunda hataya neden olmuştu.

    Tabii ki konuyu burada bırakamazdım, sonuçta bu veritabanının da Upgrade işlemini tamamlatmam ve taşımam gerekiyordu. İçimden bir ses veritabanını tekrar Attach edince, yani tekrar SQL Server Instance'ına bağlayınca sorunun kendiliğinden çözüleceğini söylüyordu ve aynen öyle de oldu. Cumulative Update ve Upgrade Script'lerinin çalıştırılması sırasında hataya neden olan veritabanı, tekrar Attach edilince herhangi bir sıkıntıya neden olmamıştı.

    Böylece bir güncelleme sürecini daha kazalı belalı da olsa atlatmış oldum. Olur da benzer bir sorun ile karşılaşırsınız ve faydası olabilir diye sizlerle de paylaşmak istedim.

    Kazasız, belasız günler dilerim!

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