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



    20 Nisan 2017 Perşembe

    Duyuru: Microsoft İş Ortaklığı

    Gün itibariyle, gerek Microsoft Azure bulut ortamında, gerekse geleneksel ortamlardaki Microsoft SQL Server konusunda kurulum, sağlık bakımı (healthcheck), performans iyileştirme çalışmaları, sürekli kullanılabilirlik ve felaket önleme planlama ve kurulumları konusunda uzmanlaşmış olan ve hizmet veren şirketimin Microsoft Silver Cloud Partner olduğunu iftihar ile ilan ederim efendim.

    Bu iş ortaklığı sayesinde, yaptığımız projelerde Microsoft ile daha yakın çalışabileceğiz. Projelerimizde Microsoft ürünleriyle ilgili karşılaştığımız sorunlar için Microsoft'tan daha iyi destek alabileceğiz.

    Bu süreçteki desteği için Hakan Türköner'e ve bu vesileyle benimle çalışmayı tercih eden değerli tüm müşterilerime teşekkür ederim.

    Verdiğimiz hizmetler hakkında daha fazla bilgi için lütfen tıklayın.