26 Aralık 2016 Pazartesi

Azure Standard Storage'larınızda TRIM etkin mi?

Microsoft Azure sanal makinelerinizde kullandığınız Standard Storage (HDD)'lerdeki TRIM özelliğinden haberdar mısınız? Eğer değilseniz, Microsoft Azure'da sanal diskleriniz varsa ve Storage maliyetlerinizi düşürmek istiyorsanız okumaya devam edin.

Efendim artık öyle veya böyle bulut projelerine bulaşmak kaçınılmaz oldu. Bu konuda da edindiğim tecrübe ve bilgileri olabildiğince sizlerle paylaşıyor olacağım.

Bu aralar benim de dahil olduğum bir Azure projesinde çalışırken oluşturulan bazı disklerde TRIM kullanılmadığını gördüm. Eğer TRIM kullanılmazsa ne mi olur? Diskiniz için ne kadar alan tanımlandıysa, ki bu alan miktarı an itibariyle azami 1TB'tır, o kadar alan boyutu için ücretlendirilirsiniz. Fakat o disk için TRIM özelliği etkinleştirilmişse, o zaman sadece o diskte kullandığınız alanlar kadar ücretlendirilirsiniz.

Misal yeni veya varolan bir sanal makineniz için 1TB boyutunda bir Standard Storage disk oluşturdunuz ve kullanmaya başladınız. Bu diskteki dosya veya dosyalar sabit belli bir boyutta değil, zaman zaman büyüyor, zaman zaman küçülüyor. İşte özellikle böyle senaryolar için TRIM özelliğini kullanırsanız Azure faturanız azalır.

Peki TRIM özelliğinin etkin olup olmadığını nasıl anlayabilirsiniz? Diskin bağlı olduğu sanal makineye bağlanın ve Command Prompt'tan aşağıdaki komutu çalıştırın:

fsutil behavior query DisableDeleteNotify

Eğer yukarıdaki komut sonuç olarak 0 döndürüyorsa o zaman TRIM etkin demektir, eğer sonuç olarak 1 dönüyorsa o zaman TRIM etkin değildir. TRIM'i etkinleştirmek için aşağıdaki komutu çalıştırabilirsiniz.

fsutil behavior set DisableDeleteNotify 0

Kaynak:
https://docs.microsoft.com/en-us/azure/virtual-machines/virtual-machines-windows-attach-disk-portal?toc=%2fazure%2fvirtual-machines%2fwindows%2ftoc.json


Ekrem Önsoy

19 Aralık 2016 Pazartesi

Varolan donanım kaynaklarınızı gerçekten verimli kullanıyor musunuz?

Microsoft SQL Server ürününün, eski önyargılar nedeniyle birçok yönetici gözünde doğru yerde olmadığını düşünüyorum. Evet SQL Server eskiden, özellikle 2000 ve öncesi versiyonlarda gerçekten çok ilkeldi. Birçok sıkıntıları vardı. Özellikle SQL Server 2005 ile başlayan ve gün itibariyle gelinen noktada SQL Server 2016 ve Azure ile çok daha farklı bir noktada. Bunu 10.000+ kullanıcılı bir ortamda SQL Server 2000 kullanan biri olarak rahatlıkla söyleyebilirim.

Böyle bir giriş yapmamın nedeni, geçenlerde büyük bir firmanın yöneticisinin masaya oturduğu anda bana şöyle demesi:
- "Biliyorum, SQL Server zaten performanslı çalışmayan bir ürün, haliyle Oracle seviyesinde performans alabilmemiz için daha fazla donanıma ihtiyacı var."
- "Bu kadar geçmişte kaldığınız için üzgünüm bayım, ama bu çok demode bir fikir!" diyemedim ne yazık ki, ortam müsait değildi.

İpucu: İlgili firmada sadece birkaç günlük bir çalışma ile %66 performans iyileştirmesi sağladık!

Eğer bugün hala SQL Server veritabanlarınızdaki performanstan şikayetçiyseniz, ilk bakacağınız şeyler veritabanı sunucunuzun yapılandırılması / kurgusu, en iyi pratiklerin uygulanıp uygulanmadığı ve uygulamalarınızın çalıştırdığı veritabanı kodlarının "performans" özelliği ile birlikte yazılıp yazılmaması olmalı. Yazılımlar KOBİ'dekilerden büyük firmadakilere kadar daha ziyade "işlev" odaklı kod yazılıyor. Genellikle "Ekran benim makinemde / test ortamında iş tarafından talep edildiği gibi çalışıyor, kafi!" düşüncesi hakim. Maalesef hala birçok kurumda yazılım yazılırken "performans" ve "güvenlik" konuları birer özellik olarak görülmüyor. Neyse, bunlar belki başka bir yazının veya başka bir yazarın konusu. Bu yazımda başka bir konuya değineceğim.

Efendim SQL Server 2012 Standard Edition olan kritik ortamlardan birinde SQL Server sunucusunun CPU yapılandırmasında bir ilginçlik gördüm. Durum aşağıdaki gibiydi:

6 tane CPU soketi görünüyor, 2 tanesi kullanım dışı
Daha sonra kullanım dışı (OFFLINE) görünen 4 ve 5 numaralı CPU soketlerini başka bir yolla daha kontrol ettim:


Bu makinede 6 tane CPU soket, her sokette de 2'şer tane Core var görünüyordu. Yani toplamda 12 Core vardı.

Bu ortamdaki Log'larda şöyle bir mesaj görüyordum:
"SQL Server detected 6 sockets with 2 cores per socket and 2 logical processors per socket, 12 total logical processors; using 8 logical processors based on SQL Server licensing. This is an informational message; no user action is required."


Yani makinede 12 Core olmasına rağmen, SQL Server bunun 8'ini görebiliyor, CPU kaynaklarının %33'ünden faydalanılamıyordu. Neden mi? Çünkü SQL Server 2012 Standard Edition'ın 4 soket lisanslama sınırlaması var. SQL Server 2012 Standard Edition'da 4'ten fazla CPU Soketi, 16'dan fazla Core kullanılamaz. Sonuç olarak israf edilen %33'lük bir CPU donanımı söz konusu, ama ilgili yöneticiler SQL Server'ın tüm varolan kaynağı kullandığını düşünüyor. Emin olabilirsiniz, daha farklı ortamlarda bundan çok çok daha büyük israf oranlarını gördüm.

İlave örnek: İsraf oranlarının nereye varabileceği hakkında sadece fikir vermesi açısından aşağıdaki mesaja bakın bir de, ama o hikayenin ayrıntılarına burada girmeyeceğim. Bu bir kurgu değildir, gerçek bir ortam.

SQL Server detected 8 sockets with 8 cores per socket and 8 logical processors per socket, 64 total logical processors; using 20 logical processors based on SQL Server licensing. This is an informational message; no user action is required.


Nasıl ama? CPU kaynaklarının %68,75'i SQL Server tarafından kullanılamıyor.


Asıl hikayemize dönersek, söz konusu makine bir sanal makineydi, ben de ilgili sistem yöneticilerine bu sanal makinenin CPU ayarlarının SQL Server lisanslaması açısından doğru olmadığını, değiştirmemiz gerektiğini ilettim. Ufak bir planlı kesintiyle, artık SQL Server makinedeki 12 Core'dan yani CPU kaynaklarının tümünden faydalanabiliyordu. SQL Server için herhangi bir CPU modelini kullanmamalısınız. Bir SQL Server sunucu için CPU seçimi özenle yapılmalıdır. Makinenin sanal veya fiziksel oluşu da dikkate alınmalıdır. Bu sadece performans açısından değil, lisanslama maliyeti açısından da çok önemlidir. Sırf yapacağınız yanlış bir CPU modeli seçimiyle bile işe onbinlerce dolar zararla başlayabilirsiniz.

Bu yapılandırma işinin tabii ki daha hafıza, disk ve ağ altyapısı ayakları var. Sonra da veritabanı tasarımı ve kodlar...

Demem o ki söylenmek, kızmak kolay; ama gerçekten de ürün mü sıkıntılı, yoksa hakkını veremeyenler mi? Birçok yönetici giderleri kısmak için yollar arıyor, ama "varolan kaynaklardan gerçekten verimli yararlanılabiliyor mu?" sorusu sorulmuyor.

Eğer sizin de farkında olduğunuz veya kuşkulandığınız benzer sorunlarınız varsa iletişime geçmek için beklemeyin.

İyi işler!
Ekrem Önsoy

14 Aralık 2016 Çarşamba

Microsoft Güvenlik Zirvesi

Bugün sabahtan öğlene kadar Sakıp Sabancı Müzesi'nde, Microsoft'un düzenlediği Güvenlik Zirvesi etkinliğindeydim.

Bu etkinliğe katılmak istememin nedeni özellikle yeni çıkan veya gelişmekte olan Microsoft güvenlik teknolojilerinden ziyade, Kişisel Verilerin Korunma Kanunu (6689 numaralı kanun) hakkında bilgi edinmekti. "Bir kanun hakkında bilgi edinmek için neden bir Microsoft etkinliğine katılıyorsun ki?" diye bir soru gelebilir tabii akla mantıklı olarak. Biliyorsunuz Microsoft'un bir bulut çözümü var Azure (ki bu konuda size bir sürprizim olacak yakında!), birçok müşteri Kişisel Verilerin Korunması kanunu çerçevesinde verilerini bir bulut ortamına koymaya çekiniyor. Microsoft da Azure'a ciddi yatırım yapıyor ve (bazen biraz agresif bir şekilde de olsa) kullanılmasını istiyor. Bu nedenle bu kanunun verilerimizi Azure veya herhangi bir bulut ortamına koymaya engel olup olmadığını herkesten çok Microsoft ve benzer sektördeki firmalar araştırıyordur diye düşünüyorum.

Peki ben neden Kişisel Verilerin Korunma Kanunu ile bu kadar ilgileniyorum? Bu kanun çerçevesinde verilerden biz de sorumlu oluyoruz arkadaşlar. Birçok müşteri ile çalışıyoruz. Hem müşterilerimde bu konuda bir farkındalık yaratmak, hem de bu konudaki hukuki yükümlülüklerimizi daha iyi bilmek ve anlamak istediğimden bu kanun beni doğrudan ilgilendiriyor. Eğer bu yazıyı okuyorsanız, muhtemelen sizi de ilgilendiriyor!

Etkinliğin yapıldığı salondan bir görüntü

Yine anladım ki Kişisel Verilerin Korunması Kanunu henüz daha emekleme aşamasında. Birçok net olmayan yer var, soru işaretleri var. Kanun çerçevesinde bir kurulun belirlenmesi ve bu kurulun da bazı şeyleri belirlemesi gerekiyor. Fakat henüz kurul tamamen belirlenmiş değil. Bu nedenle bu kanunda kurulun belirleyeceği söylenen bazı şeyler belirlenemiyor. Bunlar belirlenemediği için de bahsettiğim muğlaklıklar oluyor. Sonuç olarak Microsoft dahil, konu ile ilgilenen herkes sabırsızlıkla bu kurulun seçilmesini ve görevini yerine getirmesini bekliyor!

Efendim edindiğim diğer bilgilerden de bazılarını aktarayım. Öncelikle seminerde veriler bilgilere göre Türkiye'de internet kullanıcısı 46 milyon civarındaymış. Türkiye'deki cihazlarda bulunan zararlı uygulamalar (Malware) dünya ortalamasına göre 2 kat fazlaymış.

Bir çalışmaya göre kötü niyetli bir kullanıcı bir şirketteki kullanıcılara zararlı içerik olan bir e-posta gönderdiğinde, 100 kişiden 6'sının gelen e-postadaki ekli dosyaları açtığı belirtlenmiş. Bu kadar çok Bot olmasının, zararlı uygulamaların bu kadar yaygın olmasının ve her geçen gün daha fazla şirketin sunucu ve bilgisayarlarının fidye isteyen korsanlar tarafından ele geçirilmesine şaşmamalı.

Etkinlik sırasında konuşmacılardan birisi, büyük bir şirketin CEO'sunun kendisine anlattığı yaşanmış bir olaydan bahsetti. O büyük şirkette çalışan bir mühendisin gelen ekli bir e-postayı açması neticesinde sunucu, fidye isteyen bir yazılımca kitlenmiş. Çok büyük bir fidye karşılığı kilidi açmayı başarmışlar. Fakat aynı kişi o fidye yazılımının nasıl çalıştığını merak etmiş ve tekrar çalıştırınca aynı fidyeyi yine ödemek zorunda kalmışlar. Konuşmacı bunu anlatırken dinlemeliydiniz, çok güldük.

Yukarıda bahsettiğim gibi doğrudan bize yansımayan başka birçok çeşit ihlal var. Firmaların bu ihlalleri keşfetmesi ortalama 200 gün sürüyormuş. Tabii 200 güne kadar olan oluyor. Yani veritabanınıza sızıldıysa oradaki veriler sızdırılabiliyor veya değiştirilebiliyor veya aklınıza ne gelirse artık, çünkü bu noktada tamamen korsanın insafına kalıyorsunuz.

Veritabanı bazında güvenlik sadece Login oluşturmak/silmek, Ali ve Ayşe'yi X rolünün üyesi yapmak veya yapmamakla sağlanmıyor arkadaşlar. Bu konuda çok daha etraflıca düşünmeniz gerekiyor. Artık her zamankinden çok daha fazla sorumluluğumuz var. Kötü niyetli kişiler kadar çeşitli ve hızlı çözüm geliştiremediğiniz noktada, geri kalıyorsunuz ve hem kendinizi hem de verilerinizi tehlikeye atıyorsunuz. Aman dikkat!


Hayırlı işler,
Ekrem Önsoy

11 Aralık 2016 Pazar

2. Bölüm: Yedeklemeye gereken önemi vermek için canınızın yanması şart mı?

Bir önceki yazımda doğru yedeklemenin önemini vurgulamış, bir canlı ortamda disklerin silindiğini ve yedeklerden nasıl (neredeyse) hiç veri kaybetmeden geri döndüğümüzü bir sonraki yazımda anlatacağımı söylemiştim. Doğru yedeklemenin nasıl hayat kurtardığını somut bir örnekle bu yazımda anlatacağım.

1-2 ay önce ortamlardan birinde bir Cuma öğlen saat 14:30 gibi çok kritik olan bir canlı SQL Server sunucusundan ilginç mesajlar ve son kullanıcıdan şikayetler gelmeye başladı.

İlgili sunucuya bağlanmaya çalıştım, ama nafile. Ne SQL Server Management Studio ile bağlanabiliyordum ne de uzak masa üstü bağlantısı yapabiliyordum. Sunucu sanal bir sunucuydu. İlgili sistemci arkadaşımla temas kurdum ve şikayetimi ilettim. Az sonra sistemci arkadaşımdan telefon geldi ve telefondaki ses şöyle diyordu: "Diskleri kaybettik...".

Bir felaket senaryosunun yolunu açan ilk kelimelerdi bunlar. Daha fazla bilgiye ihtiyacım olduğu için doğrudan disk yöneticisi arkadaşlarla temas kurdum. Yeni bir disk verilmeye çalışılırken, varolan veritabanı Transaction Log, SQL Server ve işletim sistemi dosyalarının bulunduğu diskler silinmişti ve geri getirilme olasılığı yoktu. Sorunun teknik olmadığını ve insan hatasından kaynaklandığını öğrendikten sonra, sorun en azından o anda tekrar etmeyeceği için ilk etapta öğrenmek istediklerim sadece bunlardı. Neden ve nasıl olduğunun ayrıntıları bu etapta beni ilgilendirmiyordu, çünkü sorunun çözümüne hiçbir katkısı yoktu.

Sistemi geri ayağa kaldırabilmek için elimdeki seçeneklerimi düşündüm.
- Yerel sunucuda, veritabanlarının bulunduğu fiziksel disk altyapısından hariç başka bir disk altyapısından verilen disklere düzenli ve sık aldırdığım yedeklerim vardı,
- Uzakta Log Shipping ile beslediğim, tüm veritabanlarının ve Instance düzeyindeki nesnelerin olduğu bir yedek sunucum vardı,
- Alınan imaj yedekleri vardı (hatırlatırım, ortam sanal makine idi).

Buradaki en kilit madde 1. madde, o maddeyi birkaç kere okuyun lütfen. Eğer disk altyapıları fiziksel olarak farklı olmasaydı o zaman disk yönetimi bölümündeki arkadaş bu diskleri de silebilirdi, büyük risk. 2. madde bize ekstra bir yedekleme seçeneği sağlamıştı. Eğer 2. disk altyapısında da bir sıkıntı olsaydı, ODM ortamımıza yönelecektik.

Eldeki imkanları ve seçenekleri düşünerek hemen bir plan yaptık ve sıfırdan bir makine kurarak sistemi en kısa sürede tekrar ayağa kaldırdık. Eğer üzerinde düşünülmüş bir yedekleme planı olmasaydı, belki de şirket iş hayatına devam edemeyecekti.

Bazen gayet güzel bütçe imkanı oluyor, ama güzel yedekleme planları olmuyor. Biri olmadan, diğeri hiçbir işe yaramıyor. İyi bir felaketten kurtarma planı, hayat kurtarır.

Kazasız, belasız iyi işler dilerim,
Ekrem Önsoy

6 Aralık 2016 Salı

Yedeklemeye gereken önemi vermek için canınızın yanması şart mı?

Düşününce İstanbul'daki bir sonraki deprem için alınması gereken, alınıyormuş gibi gösterilen ama aslında alınmayan ve yedeklemeye verilmesi gereken, veriliyormuş gibi görünen ama aslında verilmeyen önem ve ciddiyet arasında ne kadar benzerlik olduğu geliyor aklıma. İstanbul'daki son büyük depremde ne kadar canımız yanmıştı, o kadar konuşuldu, yazıldı, çizildi... Sonuç? Önce sağda solda, içlerinde kazma kürek olduğu söylenen konteynırlar gördük, bir süre sonra yok oldular tek tek, sonra "Kentsel Dönüşüm" adı altında, sadece müteahhitlerin kar edebileceği binaların yenilendiği abuk bir çözüm çıktı ortaya. Altyapı, aynı. Maksadım elbette politik bir tartışma yaratmak değil, yedeklemeye dikkat çekmek.

Çünkü, efendim birçok firmada şahit oldum ve olmaya da devam ediyorum:

- "Yedekleme bizim için çok önemli!"
- "Yedekleme için Veaam, Data Protection Manager, Glasshouse gibi çeşitli çözümler kullanıyoruz."
- "Yedekleme araçlarımızdan sorumlu, kullanan personelimiz var."
- "Yedekleme için gerekli tüm kaynaklarımız var"

deniyor... Sonuç? Yıllardır biriktirdiğim tecrübeye dayanarak çok farklı ortamlardan, ama gerçek örneklerle anlatıyorum, sonuç şöyle:

- Çok daha kısa sürede alınabilecek yedeğin alınması 10 saat sürüyor,
- Veaam ile aynı veritabanlarının günde 8 kere yedeği alınıyor. VSS ile aldığı için gün içerisinde donmalara neden oluyor,
- Data Protection Manager (DPM) ile alındığı zannedilen yedek konusunda DPM yöneticisinin bile haberi yok,
- Yedekler, veritabanı ve diğer tüm dosyaların da bulunduğu aynı disk altyapısındaki disklere alınıyor. Yani disk altyapısı gitti mi, yedekler de gidiyor, asıl dosyalar da..
- Yedekler alınıyor, ama ne sıkıştırma özelliği kullanılıyor, ne "checksum" kontrolü yapılıyor. Bu nedenle yedek depolama maliyeti artıyor. Çok daha fazla yedek, daha uzun süre depolanabileceğine, çok daha az yedek daha kısa süreliğine tutulabiliyor. Sonra yenilerine yer açmak için eskiler, daha uzun süre tutulabilecekken siliniyorlar. Yani kaynaklar verimli kullanılmıyor,
- Çok kritik veritabanları için sadece bir kere tam veritabanı yedeği (full database backup) alınıyor, ama Transaction Log yedeği alınmıyor, yani bir kriz anında 24 saatlik veri kaybı olasılığı var,
- Restore testleri yapılmıyor veya yapılıyor, ama bir düzen yok. Restore testlerine gerekli önem verilmiyor,
- Hangi veritabanı ve sunucu ne kadar kritik? Hangisi için hangi yedek ne kadar süre tutulmalı? Ne kadar sürede geri dönüş sağlanmak zorunda? Ne kadarlık veri kaybı tolere edilebilir? RPO ve RTO'lar belirlenmemiş.

Ve daha neler neler... Nasıl? Size de bir şeyler hatırlattı mı yukarıdaki maddeler? Eminim birçok kişiye kendi ortamlarıyla ilgili bir şeyler çağrıştırmıştır.

Öyle veya böyle, üzgünüm ama o felaket bir gün başınıza gelecek ve felaketin binbir türlü çeşidi var. Disk altyapısı bozulabilir, yeni bir disk verilirken varolan canlı ortam diskleri silinebilir (daha 1,5 ay önce geldi başıma), Windows veya SQL Server Update'leri nedeniyle makine bir daha açılmayabilir veya servisler doğru çalışmayabilir (bu da 1 ay önce geldi başıma), bir çalışan yanlışlıkla veya kızgınlıkla verilerinizi bozabilir, güncelleyebilir veya silebilir...  Bunun için artık çok daha çeşitli, uygun fiyatlı seçenekler ve birçok şirketin bu seçenekleri kullanabilmesi için kaynak da var. Tek sorun, bu konuya vaktinde yeterince önem verilmemesi gibi geliyor bana. Vaktinde önem verilmeyince de, imkan da olsa, personel de olsa, artık iş işten geçmiş oluyor.

Doğru yedekleme politikası zamanı gelince hayat kurtarır. Bir sonraki yazımda, yukarıdaki paragrafta başıma gelen canlı ortam disklerinin silinmesinden ve doğru bir yedekleme politikasıyla neredeyse hiç veri kaybetmeden nasıl o ortamı kurtardığımızdan bahsedeceğim.

Sevgiler,
Ekrem Önsoy

21 Kasım 2016 Pazartesi

SQL Server on Linux ile ilk flört!

Selamlar!

Microsoft'taki bu değişim ve dönüşüm herkesin malumu, yeni bir şey değil. Buna Steve Ballmer'dan sonra göreve gelen Satya Nadella ile başlayan veya belki çığ gibi büyüyen bir hareketlenme demek sanırım yanlış olmaz.

Geçen gün SQL Server'ın Linux Red Hat ve Ubuntu üstünde çalışan versiyonları yayınlandı. SuSE versiyonu da yakında geliyormuş. Bunların yanında Linux, MacOS ve Windows'ta Docker Container'da çalışacak versiyonu da mevcut.

Madem gelmiş, hoş gelmiş diyerek ben de bir makinede Ubuntu Linux kurulumu yaptım ve "bakalım Linux üstünde Microsoft SQL Server kullanımı nasıl oluyormuş?" dedim. SQL Server'ın bu versiyonuyla yaptığım ilk flörtümün tecrübelerini sizlerle de paylaşayım istedim.

Efendim öncelikle Ubuntu'nun sitesinden 1,51GB boyutundaki son versiyonun imaj dosyasını indirip Linux kurulumunu yaptım. Daha sonra da Microsoft'un yayınladığı dokümantasyona göre SQL Server on Linux kurulumunu yaptım. Çeşitli adımlardan sonra yükleme adımının sonucunu aşağıda görebilirsiniz.

Database Engine kurulumu

Yukarıdaki ilk kurulum adımını hallettikten sonra kurulumu tamamlamak için yine yukarıdaki açıklamada belirtilen dosyayı çalıştırdım ve sonucu aşağıdaki gibi oldu.

Database Engine kurulumunun tamamlanması

Yukarıdaki hamleyle SQL Server kurulumumu tamamlamış oldum. Bu kurulum sadece SQL Server Database Engine servisini içeriyor. SQL Server Instance'ımıza bağlanabilmemiz için SQL Server Management Studio veya SQLCMD gibi Tool'lara ihtiyacımız var. Neyse ki SQLCMD yardımımıza koşuyor! SQLCMD'yi kurmak için yine ve bu sefer başka bir adresteki dokümantasyondan faydalanabiliyoruz.

SQLCMD ve Provider kurulumlarından sonra bu sefer aşağıdaki ekranda gösterdiğim gibi SQL Server servisimin çalışıp çalışmadığını kontrol ettim.

SQL Server Database Engine servisinin çalışma durumu

Servisimin çalışıyor olduğunu gördükten sonra biraz SQL Server Error Log dosyasını kurcalamak istedim. Error Log, Extended Event Log ve Default Trace dosyaları /var/opt/mssql/log altında barındırılıyor varsayılan olarak. Ekran görüntüsü aşağıda.

Log dosyalarının konumu

Güncel Error Log'un içeriğini biraz incelediğimde aşağıdaki gibi hoş bir sürpriz ile karşılaştım, dosya yolları "C:\..." olarak duruyor hala =) Bu bilinen bir Bug imiş, Microsoft bunun gelecek versiyonlarda düzeltileceğini söylüyor.

SQL Server Error Log dosyasının içinden bir görüntü


Sistem veritabanlarının dosyaları /var/opt/mssql/data yolunda konumlandırılmış. Yeni bir veritabanı oluşturulduğunda da varsayılan olarak burada oluşturuluyor dosyalar.

SQLCMD Tool'unun kullanımı aşağı yukarı Windows'taki kardeşiyle aynı. Mesela aşağıdaki gibi bir komut ile SQL Server Instance'ıma bağlandım ve versiyon bilgisini aldım:

SQLCMD ile SQL Server Instance'ına bağlantı

Gördüğünüz gibi bildiğiniz -U ve -P parametreleri. Elbette şu anda diğer parametrelerde farklılıklar olabilir, hepsini tek tek incelemedim henüz.

Bu konudaki gelişmeleri tararken bir Microsoft çalışanının aşağıdaki yorumunu gördüm ve aslında dün akşam Twitter'dan paylaştım (@EkremOnsoy).

DB Admin GUI?

Bu henüz muğlak ve resmi olmayan bir yorum olsa da, belli ki bu konuda çalışan takımların böyle bir fikri var. Eğer Microsoft personeli böyle şeyleri sağda solda konuşuyorsa, ki zaten yatırımlar da bu yönde, bence böyle bir Tool'un deneme versiyonunu da yakında görürüz. Sonra Ekrem demedi demeyin!

Beni az çok tanıyan birisi bu işin peşini sadece SQLCMD ile bırakmayacağımı sanırım tahmin ediyordur. Elbette dahili bir ağ kurdum ve bir Windows 7 işletim sistemimdeki SQL Server Management Studio'unun son versiyonu olan 16.5 ile Ubuntu üstündeli SQL Server on Linux (vNext CTP1)'e bağlanmayı denedim. Sonuç aşağıda:

SQL Server Management Studio ile Linux'te çalışan SQL Server Instance'ına bağlantı

Nasıl? Etkileyici değil mi?

Evet arkadaşlar, artık "comfort-zone"dan çıkma veya "dinozor" olarak emekliliğe adım atma zamanının geldiği çok daha net. Cesur olun!

Sevgiler,
Ekrem Önsoy

18 Kasım 2016 Cuma

Daha neler göreceğiz! Microsoft bir bomba daha patlattı!

Merhabalar!

SQL Server 2016 Service Pack 1 duyurusu ile Microsoft çok büyük bir bomba daha patlattı millet!

Sahada pratik olarak kullanabileceğiniz ve çok verimli olan birçok Enterprise Edition özelliği artık diğer Edition'larda da kullanılabilecek! Artık diğer Edition'larda da kullanılabilecek özelliklere ait başlıklar, yukarıdaki duyuru adresinden aldığım aşağıdaki tabloda.


Row-Level Security ve Dynamic Data Masking özelliklerinin zaten Standard Edition'da kullanılabileceğini RTM duyurularından biliyorduk. Fakat yukarıdaki listeden de görebileceğiniz gibi, piyasada birçok firmanın çok işine yarayabilecek özelliklerin özellikle
- Table Partitioning: Neredeyse kesintisiz arşivleme,
- Data Compression: Tabloları, indeksleri sıkıştırabilmek,
- Fine grained auditing: Tablo bazında, SELECT, INSERT, UPDATE, DELETE gibi işlemlerin de artık loglanabilmesi,
- Columnstore: Bu indekslerle raporlama ihtiyaçlarının çok daha verimli karşılanabilmesi,
- Database snapshot: Kritik işlemlerden önce (mesela yeni bir kod yayınını düşünün) veritabanının Snapshot'ının alınması

Not: Dynamic Data Masking ve Row-level security'den de gayet faydalanılabilir, yukarıda özellikle eskiden Enterprise Edition özelliği olanlara değindim.

Not2: In-Memory OLTP'nin ne kadar ilgi göreceğini kestiremiyorum, çünkü henüz Microsoft SQL Server Standard Edition'ın RAM sınırlamasında bir değişiklik yapmadı. In-Memory OLTP de doğrudan RAM kaynakları ile ilgili olduğu için kullanılabilse de çok sınırlı tablolar ve SP'ler için kullanılabilir olur. Bu özelliğin kullanımı düşünülüyorsa kaynak ayarlaması muhakkak iyi hesaplanmalı.

Sahada pratik olarak en çok bunların kullanılabileceğini, Standard Edition kullanan firmaların en çok bu özelliklerden faydalanabileceğini düşünüyorum.

Hemen belirteyim, bu özellikler sadece SQL Server 2016 + Service Pack 1 ile mümkün olacak, geriye dönük, yani SQL Server 2012, 2014 gibi önceki versiyonlarda Standard Edition'da bu özellikle kullanılamayacak.

Yukarıdaki özellikleri iyi planlayarak, kurgulayarak devreye alabilirseniz birçok alanda kaynaklardan tasarruf sağlayıp, firmanıza karlılık sağlayabilirsiniz.

Eğer projelerinizde yardıma ihtiyacınız varsa beni aramaktan çekinmeyin!

Sevgiler,
Ekrem Önsoy

14 Kasım 2016 Pazartesi

Database Mail ile başka bir sorun daha

Merhaba millet!

Bu aralar biraz yoğunum, o nedenle bir süre bir şeyler yazamadım. Geçen hafta yurtdışındaydım, Hollanda'nın Den Haag şehrinde. Orada, önceden Antalya Havalimanında çalışan ve şimdi de Amsterdam'da çalışıyor olan veritabanı yöneticisi Hayri Özler ile de tanışmış olduk, pek de hoş oldu, ona da selam olsun!

Cumartesi gecesi yurtdışından gelir gelmez bir de AlwaysOn Availability Group geçişi yaptık. Yoğunluk hala devam etmesine rağmen araya hemen bir yazı sıkıştırayım dedim.

Bugün ortamlardan birinden bir süredir eposta almadığımı fark ettim. Sorunu incelediğimde Database Mail'in yine çeşitli sebeplerden biri yüzünden çalışmadığını gördüm. Arkadaşlar, yine sonra söyleyeceğimi baştan söyleyeyim, eğer DatabaseMail sizin için kritik bir özellik ise ve ortamınızda bir izleme uygulamanız varsa o zaman muhakkak gönderilirken hata alan veya Queue'da çok bekleyen e-postalarınızı kontrol ettirin.

Sorunu incelemek için ilk önce [msdb] sistem veritabanında bulunan Database Mail ile ilgili tabloları sorguladım. Mesela:

SELECT TOP (10) * FROM msdb.dbo.sysmail_event_log ORDER BY log_date DESC

ve

SELECT TOP (10) * FROM msdb.dbo.sysmail_allitems a ORDER BY a.send_request_date DESC

Bu ortamda hem e-posta'ların gönderilemediğine dair hatalar vardı, hem de öylece gönderilmeyi bekleyen birçok e-posta vardı.

Önce Database Mail yapılandırmamın doğruluğunu kontrol ettim. Database Mail Account'umun kullanıcı bilgilerini kontrol ettim. Doğruluğundan emin olduktan sonra ve Database Mail'in hala çalışmadığını gördükten sonra Database Mail'i tekrar başlatmayı düşündüm. Database Mail, SQL Server kurulumu ile birlikte gelir, ama SQL Server Database Engine servisine gömülü bir özellik değildir. Misal Task Manager'dan bakarsanız DatabaseMail.exe diye harici bir uygulamanın çalıştığını görürsünüz. Bu, SQL Server ile birlikte gelen Database Mail özelliği için kullanılan uygulamanın ta kendisidir. Eğer bu uygulama çalışmıyorsa, Database Mail özelliği de çalışmaz.

Database Mail'i tekrar başlattıktan sonra sorunun yine devam ettiğini gördüm. Bunun üzerine Database Mail'in Queue'larını incelemeye karar verdim. "O da nesi?" diye soran arkadaşlarım, Database Mail özelliği Service Broker'ı kullanır, e-postalarınızı bu sayede asenkron olarak gönderilir. Service Broker yapısında da birçok eleman gibi Queue'lar da vardır. Gönderilmek istenen mesajlar önce Queue'lara kaydedilir, sonra da sırasıyla işlenirler. İşte Database Mail'in yine [msdb] veritabanındaki External Queue'sunu ([msdb].[dbo].[ExternalMailQueue]) incelediğimde 20 binden fazla mesaj biriktiğini gördüm. Bunların çoğu zaten artık vakti geçmiş, gereksiz mesajlardı. Bu Queue'yu temizleyince Database Mail ile bir test e-postası gönderdi ve Voila! Artık Database Mail'im çalışıyordu.

Yine vurgulamakta fayda görüyorum. Eğer Database Mail özelliği sizin için kritikse, yani mesela bazı kritik e-postalarınızı Database Mail ile gönderiyorsanız veya 3. parti izleme uygulamalarına bütçe ayıramıyor ve kendi çözümlerinizi kullanıyor ve yine bu kapsamda alarmları Database Mail ile gönderiyorsanız, aynı SQL Server Database Engine servisini izlettiğiniz gibi (izletiyorsunuz, değil mi?) Database Mail'in sağlıklı çalışırlığını da kontrol ettirmelisiniz.

Sevgiler!
Ekrem Önsoy

22 Ekim 2016 Cumartesi

"SQL Server Reporting Services: The feature: "Scale-out deployment" is not supported in this edition of Reporting Services."


Selam millet,

Ortamlardan birinde bir felaket yaşandı ve yeniden kurulum gerekti. Bunu belki başka bir yazıda yazarım. Bu yazıda değinmek istediğim şey Reporting Services ile ilgili.

İlgili ortamda kurulumları tekrar yaptık, tahmin edeceğiniz üzere bu ortamda Reporting Services da kullanılıyor.

Daha sonra kullanıcılardan Reporting Services ile ilgili şikayetler gelmeye başladı, aşağıdaki gibi:

No connection could be made because the target machine actively refused it XXX.XX.X.XXX:80

Önce Reporting Services servisinin çalıştığından emin oldum, sonra fark ettim ki Encryption Key'i Restore etmemişim. Onu da hallettikten sonra bir baktım aşağıdaki hatayı alıyorum:

"SQL Server Reporting Services: The feature: "Scale-out deployment" is not supported in this edition of Reporting Services."

Emin olamadım, bir Google'a sorayım dedim. Baktım Enterprise Edition özellikleri kullanılıp Standard Edition'a geçilince böyle sorun oluyor falan demiş birçok kişi. Mantıklı gelmedi, çünkü önceki kurulum da, bu kurulum da Standard Edition idi ve bir şey değişmemişti.

Biraz daha inceledikten sonra Reporting Services Configuration Manager'daki Scale-out Deployment bölümünde aynı sunucu adından 2 tane olduğunu gördüm. Emin değilim, ama sanırım Encryption Key'i Restore ettikten sonra oluştu bu durum. 

Basit bir şekilde listedeki sunuculardan birini "Remove Server" düğmesiyle kaldırdım ve Ta taaa! Sorun çözüldü.

Olur da bu sorun ile karşılaşırsanız tek nedeninin Edition farkı olduğunu düşünmeyin diye bu yazıyla bu durumu tarihe not etmek istedim.

Sevgiler!
Ekrem Önsoy

27 Eylül 2016 Salı

"NOLOCK or READUNCOMMITTED in UPDATE or DELETE"

Merhaba,

Dünkü çalışmada bir blog konusu daha vardı, şimdi fırsatım varken o konuda da yazmak istedim.

Diğer test edip emin olmak istediğimiz konu da hangi versiyonda hatırlamıyorum, ama halihazırda SQL Server'ın "Deprecated" özellikler listesine giren, UPDATE ve DELETE komutlarıyla "NOLOCK" Hint'inin kullanımı konusuydu. Dünkü yaptığımız çalışmada, çalıştığımız sunucuda "NOLOCK or READUNCOMMITTED in UPDATE or DELETE" uyarılarının olduğunu gördük. İlgili arkadaşlar bunun olamayacağını, böyle bir kullanım pratiğinin kurumda uygulanmadığını, başka bir kullanım şeklinin bu sayacı arttırmış olabileceğini düşünüyorlardı. O zaman test edelim ve görelim dedik, böylece yeni bir blog konusu çıktı ortaya.

Öncelikle "Deprecated" olmuş bir özellik ne demek çok özetle buna değineyim. Bir özellik SQL Server'ın yeni versiyonlarından kaldırılmadan birkaç versiyon önce "Deprecated" özellikler listesine girer. Özellik yeni versiyonda kaldırılmışsa da "Discontinued" özellikler listesine girer artık. SQL Server'ın yeni versiyonlarıyla güncellenir bu listeler. Bu nedenle veritabanı uygulaması geliştirirken, eğer birkaç yıl içerisinde uygulamanızda ilginç ilginç hatalar görmek istemiyorsanız bu listelerdeki değişiklikleri de takip etmenizde fayda var.

Efendim bu kontrolü aşağıdaki sorgu ile yapabilirsiniz:

SELECT * FROM sys.dm_os_performance_counters
WHERE [object_name] = 'SQLServer:Deprecated Features' and [instance_name] = 'NOLOCK or READUNCOMMITTED in UPDATE or DELETE' AND [cntr_value] > 0

Aşağıdaki gibi bir komutu her çalıştırdığınızda, bu sayacın değeri bir bir artacaktır:

Not: Önce X isimli ve içerisinde metin veritipiyle "name" alanı olan ve içinde de en azından "Ekrem" kaydı bulunan bir tablo oluşturmalısınız.

Örnek1:
UPDATE alias_name SET name = 'Ekrem' FROM x AS alias_name WITH (NOLOCK);

Not: Eğer sürekli aynı değerle güncellerseniz sayaç artmıyor. Sadece değer değiştiğinde artıyor. Yani ilk testinizde değeri "Ekrem" olarak belirttikten sonra, mesela "Ekrem1" yapın, sayaç öyle artıyor.

Eğer aşağıdaki gibi bir komut çalıştırırsanız bu sayacın değeri artmıyor:

Örnek2:
UPDATE alias_name SET name = 'Ekrem' FROM (SELECT * FROM X WITH (NOLOCK)) AS alias_name;

Bu nedenle sanılanın aksine, ilgili ortamdaki uygulamada ilk örnekteki gibi bir kullanım olduğunu sanıyorum. Belli ki gerçekten NOLOCK Hint'ini doğrudan UPDATE komutuyla kullandığımızda artıyor bu değer. Tabii ki daha da emin olmak için ikinci örnekteki kod farklı şekillerde değiştirilerek de uygulanabilir. Fakat benim ilk etapta aklıma gelen bu örneklerle sonuç böyle.

Sevgiler,
Ekrem Önsoy

Veritabanı bütünlük kontrolünün kontrolü

Selamlar,

Dün bir müşterimde sağlık bakımı çalışması yaparken bir şey dikkatimi çekti ve ilgili arkadaşlarla aramızda bu konuda konuştuk ve bir fikir ayrılığı oldu, daha doğrusu aslında hepimiz birlikte emin olamadık ve bu bir blog konusu olsun, biz de sonuç hakkında daha kesin bir fikir sahibi olalım ve herkesle de paylaşalım dedik.

Konumuz şuydu efendim, bir SQL Server Agent Job'ı ile DBCC CHECKDB komutu kullanılarak rutin olarak veritabanı bütünlük kontrolü yapılıyor. Örneğin:

Job içerisinde her bir veritabanı için ayrı bir Step var ve her birinde ayrı ayrı

Step1: DBCC CHECKDB('Veritabanı1')
Step2: DBCC CHECKDB('Veritabanı2')
Step3: DBCC CHECKDB('Veritabanı3')
...

Şeklinde tanımlanmış diyelim, şayet DBCC CHECKDB komutu ikinci adım için aşağıdaki gibi bir sonuç döndürürse ne olur?

CHECKDB found 0 allocation errors and 4 consistency errors in table 'tablo_adı' (object ID 1154103152).
CHECKDB found 0 allocation errors and 4 consistency errors in database 'Veritabanı2'.
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (Veritabanı2).

Esas merak ettiğimiz şey buydu: İlgili Job hata verir ve bu sayede Job'ın Notification bölümündeki ilgili operatöre e-posta gönderilir mi? Yoksa DBCC komutu böyle bir sonuç üretse de hatanın nedeni ve kaynağı DBCC komutu olmadığı için komut başarıyla tamamlanmış olur ve Job da başarıyla tamamlandığı için Notification bölümündeki operatöre e-posta göndermez mi? Sonuç olarak eğer böyle bir kontrol sonucu bir alarm üretilmezse bu kontrolün pek bir önemi kalmamış olacak ve bu da riskli bir durum oluşturacak.

"Peki bunu bugüne kadar hiç mi fark etmedin?" diyebilirsiniz, efendim ben bu kontrolü daha farklı şekilde yapıyorum. Benim yönettiğim ortamlarda yaptığım bütünlük testlerinin sonuçlarını kendime eposta ile göndertiyorum. Bu iş için sadece bu bütünlük Job'ı hata alırsa e-posta gelsin gibi bir mekanizma kullanmıyorum. Bu nedenle bu konu hakkında çok net bir fikrim yoktu.

Öncelikle şunu bilmek gerekiyor, bir veritabanı birçok şekilde Corrupt duruma düşebilir. Mesela bazen veritabanı Corrupt olduğunda hiç açılmıyor. Suspect durumda olabiliyor. Recovery Pending durumda olabiliyor. Bazen de Online gibi görünüyor, bazı tablolara ve verilere ulaşılabiliyor, fakat bazılarına ulaşılamıyor... Hatta aynı tablodaki bazı kayıtlara ulaşılabilip, bazılarına ulaşılamadığı da olabiliyor.

DBCC CHECKDB komutu da veritabanının içinde bulunduğu duruma göre bazen veritabanı hiç açılamadığı için daha baştan hata verip çalışmıyor, bazen de tarama yapılabiliyor; bunun sonucunda yukarıdaki gibi sonuçlar üretebiliyor. Bir veritabanının böyle birçok farklı Corruption senaryosu olduğunu bildiğim için, ben de dünkü tartışmamızda bu nedenle net olarak emin olamadım ve test etmek istedim.

BÖYLE BİR TESTİ KESİNLİKLE PRODUCTION, PRE-PRODUCTION, TEST ve DEV ORTAMLARINIZDA YAPMAYIN. Tamamen gözden çıkartabileceğiniz bir SQL Server Instance'ında ve ortamında yapabilirsiniz.

Test için:
- Testim için yalıtılmış test ortamlarımdan birindeki AdventureWorks2012 veritabanını kullandım.
- Veritabanımı Detach etmeden OFFLINE duruma getirdim.
- Veritabanımın veri dosyasının içeriğinde bir Hex Editör ile değişiklik yaparak test veritabanımı Corrupt duruma getirdim.
- Veritabanımı tekrar ONLINE duruma getirdim.
- Veritabanım tamamen sağlam görünüyordu. DBCC CHECKDB'yi çalıştırdığımda aşağıdaki sonucun oluştuğunu gözlemledim:



Bunun sonucunda, yukarıdaki ekran görüntüsünden de görülebileceği üzere DBCC CHECKDB komutu hata ile tamamlanmış sayıldı. Yani DBCC CHECKDB komutu bir veritabanında Corruption olduğuna dair bir sonuç üretirse, bu komutun kendi de hata ile tamamlanıyordu. Tabii hal böyle olunca, ilgili SQL Server Agent Job'ı da hata ile tamamlanmış oluyor ve Job'ın Notification bölümünde tanımlanan operatöre e-posta gönderiyor.

Önceden de belirttiğim gibi Corruption birçok şekilde gerçekleşebiliyor, bu nedenle her ne kadar bu test sonucunda en azından tablo/indeks boyutunda yaşanan bir Corruption sonucu DBCC CHECKDB komutunun hata ile tamamlanacağını ve ilgili Job'ın da hata üretip ilgili noktaları tetikleyeceğini görsek de, ben bu konuda hala temkinliyim. Özellikle kritik ortamlarımda DBCC CHECKDB sonuçlarını e-posta ile almayı yeğlerim.

Sevgiler,
Ekrem Önsoy


8 Eylül 2016 Perşembe

An alternative way to manage jobs during an AlwaysOn AG failover

Hello beautiful SQL people!

In this article, I'd like to share a solution to handle SQL Server Agent Jobs (I'll call them "jobs" from now on) during a failover scenario in an AlwaysOn Availability Group environment. I know, there are some different suggestions around but I promise, this is a new one as far as I am aware.

I'll skip the basics and I assume you already know about SQL Server AlwaysOn Availability Group (AG), jobs and SQL Server Agent Alerts (alerts from now on) features. This is all about managing the status (enabled/disabled) of the jobs and not synchronising / copying them among AG replicas. Also for now, this solution works between 2 replicas only, but it can be expanded to cover more with some extra work.

Note: I haven't tested it yet, but I strongly believe that with some tweaking, this solution can be implemented in a Log Shipping or Database Mirroring environment too.

The solution is absolutely not a totally-new one. I love to read published articles written by my peers about SQL Server and try to follow them daily and up until now I've seen some variations of this solution around. However, I find this way much simpler to implement and manage. That's why I want to share it with the community and to reach out to a wider portion of the community, I'm writing it in English obviously which I do not do so often.

As you know SQL Server does not have a native solution to handle jobs after a AG failover. In terms of its enabled/disabled status, a job stays as is after a failover occurs, they are not failover-aware. In some environments, jobs are critical if not vital. So at least for a lot of DBAs out there, it's very important to switch the status of the jobs at the primary and secondary replicas immediately after a failover.

Some suggest adding conditional checks to each job, however it is sometimes almost impossible (SSIS, too many jobs to modify etc.), some suggest adding some tags to each job and schedule a job at both replicas to enable / disable them accordingly after a failover. Michael K. Campbell has a very long series of articles about AG on SQLMag. I'd like to thank to him to let me use his Function code below to detect the primary and secondary AG replicas in this solution. I prefer to use this function so that I can implement the solution to my SQL Server 2012 instances too.

With this solution, my aim is to set up & forget about jobs should a failover occurs. After implementing this, the only thing you may want to do is adding the names of some jobs to the exclusion table to exclude them from switching status after failovers. The rest will be handled by the solution and when a failover occurs, the status of your jobs will be the same at the new primary and secondary as it was previously. Enabled/disabled jobs at the previously-primary replica will be enabled/disabled at the new-primary replica and the same for the secondary. It does not matter if you perform a manual failover or an automatic failover in case the primary shuts down. Even if your primary shuts down / powered off, it will update the status of the jobs when the SQL Server Agent service is up. It just works.

I recommend you to create the following objects in your DBA / Tools database if you have any. Here are the codes and descriptions to create the solution.


************************** Beginning of the script **************************

-- REMINDER: The following codes must be executed at both of the replicas.


-- Create a Linked Server named "PARTNER" that goes to the other replica and same for the other one. 


-- [Optional] Create a schema named "jobs" to distinguish this solution from others. If you do not prefer to create this schema or if it's already taken and can not be used for this purpose, then please modify rest of the code below.

USE ;
GO
CREATE SCHEMA [jobs];
GO


-- This table will be updated automatically by a stored procedure "[jobs].[update_job_status_accross_nodes]". I prefer to execute this SP hourly by another scheduled job which is not scripted here. But hey! You already know how to do it.

CREATE TABLE [jobs].[job_status](
[job_name] [nvarchar](256) NULL,
[primary_enabled] [bit] NULL,
[secondary_enabled] [bit] NULL,
[collection_date] [datetime] NULL
) ON [PRIMARY]
GO

CREATE UNIQUE CLUSTERED INDEX CUIX_jobname ON [jobs].[job_status](job_name);
GO


-- This is the table you may want to add some jobs to exclude from switching automatically.

CREATE TABLE [jobs].[job_status_exclusion_list](
[job_name] [nvarchar](256) NULL
) ON [PRIMARY]

GO

CREATE UNIQUE CLUSTERED INDEX CUIX_jobname ON [jobs].[job_status_exclusion_list](job_name);
GO


-- To find out if the current replica is primary or not (courtesy of Michael K. Campbell)
CREATE FUNCTION [dbo].[fn_hadr_group_is_primary] (@AGName sysname)
RETURNS bit 
AS
        BEGIN 
                DECLARE @PrimaryReplica sysname; 

                SELECT TOP (1) @PrimaryReplica = hags.primary_replica 
                FROM 
                        sys.dm_hadr_availability_group_states hags
                        INNER JOIN sys.availability_groups ag ON ag.group_id = hags.group_id
                WHERE
                        ag.name = CASE WHEN @AGName IS NULL THEN ag.name ELSE @AGName END;

                IF UPPER(@PrimaryReplica) =  UPPER(@@SERVERNAME)
                        RETURN 1; -- primary

                RETURN 0; -- not primary
                
        END; 



-- Updates the "[jobs].[job_status]" table about the status of the jobs at the primary and secondary separately.

CREATE PROCEDURE [jobs].[update_job_status_accross_nodes]
AS
SET NOCOUNT ON;

IF (SELECT dbo.fn_hadr_group_is_primary(NULL)) = 1
BEGIN
DECLARE @date DATETIME;
SELECT @date = GETDATE();

DELETE FROM [jobs].[job_status];
INSERT INTO [jobs].[job_status]([job_name], [primary_enabled], [secondary_enabled], [collection_date]) 
SELECT 
[name] = CASE WHEN [primary].[name] IS NULL THEN [secondary].[name] ELSE [primary].[name] END, 
[primary].[enabled], 
[secondary].[enabled], 
@date 
FROM [msdb].[dbo].[sysjobs] AS [primary]
FULL OUTER JOIN [PARTNER].[msdb].[dbo].[sysjobs] AS [secondary] ON [primary].[name] = [secondary].[name];

DELETE FROM [PARTNER].[DBA].[jobs].[job_status];
INSERT INTO [PARTNER].[DBA].[jobs].[job_status]([job_name], [primary_enabled], [secondary_enabled], [collection_date]) 
SELECT 
[name] = CASE WHEN [primary].[name] IS NULL THEN [secondary].[name] ELSE [primary].[name] END, 
[primary].[enabled], 
[secondary].[enabled], 
@date 
FROM [msdb].[dbo].[sysjobs] AS [primary]
FULL OUTER JOIN [PARTNER].[msdb].[dbo].[sysjobs] AS [secondary] ON [primary].[name] = [secondary].[name];
END


-- Enables the jobs at the primary and secondary according to the records in "[jobs].[job_status]" and "[jobs].[job_status_exclusion_list]" tables and is executed by a job named "_DBA: Configure SQL Server Agent jobs after a failover" which is triggered by an alert. These are going to be created later.

CREATE PROCEDURE [jobs].[enable_jobs_after_failover]
AS
BEGIN
SET NOCOUNT ON;

-- If the SP is running at the new-Primary Replica, except for the ones in the exclusion list, enable all jobs which was enabled at the previously Primary Replica.
IF (SELECT [dbo].[fn_hadr_group_is_primary](NULL)) = 1
BEGIN
DECLARE @sql NVARCHAR(max) = '';

SELECT 
@sql += N'EXEC msdb.dbo.sp_update_job @job_name = ''' + [name] + N''', @enabled = 1; '
FROM [msdb].[dbo].[sysjobs] AS [j]
INNER JOIN [jobs].[job_status] AS [js] ON [j].[name] = [js].[job_name]
WHERE 
NOT EXISTS(SELECT [job_name] 
FROM [jobs].[job_status_exclusion_list] AS [jsel] WHERE [jsel].[job_name] = [j].[name]) AND
[js].[primary_enabled] = 1
ORDER BY [j].[name];

EXEC (@sql);
END

-- If the SP is running at the new-Secondary Replica, except for the ones in the exclusion list, enable all jobs which was enabled at the previously Secondary Replica.
IF (SELECT [dbo].[fn_hadr_group_is_primary](NULL)) = 0
BEGIN
DECLARE @sql2 NVARCHAR(max) = '';

SELECT 
@sql2 += N'EXEC msdb.dbo.sp_update_job @job_name = ''' + [name] + N''', @enabled = 1; '
FROM [msdb].[dbo].[sysjobs] AS [j]
INNER JOIN [jobs].[job_status] AS [js] ON [j].[name] = [js].[job_name]
WHERE 
NOT EXISTS(SELECT [job_name] 
FROM [jobs].[job_status_exclusion_list] AS [jsel] WHERE [jsel].[job_name] = [j].[name]) AND
[js].[secondary_enabled] = 1
ORDER BY [j].[name];

EXEC (@sql2);
END
END


-- Disables the jobs at the primary and secondary according to the records in "[jobs].[job_status]" and "[jobs].[job_status_exclusion_list]" tables and is executed by a job named "_DBA: Configure SQL Server Agent jobs after a failover" which is triggered by an alert.

CREATE PROCEDURE [jobs].[disable_jobs_after_failover]
AS
BEGIN
SET NOCOUNT ON;

-- If the SP is running at the new-Secondary Replica, except for the ones in the exclusion list, disable all jobs which was disabled at the previously Secondary Replica.
IF (SELECT [dbo].[fn_hadr_group_is_primary](NULL)) = 0
BEGIN
DECLARE @sql NVARCHAR(max) = '';

SELECT 
@sql += N'EXEC msdb.dbo.sp_update_job @job_name = ''' + [job_name] + N''', @enabled = 0;' 
FROM [jobs].[job_status] AS [j]
WHERE 
NOT EXISTS(SELECT [job_name] FROM [jobs].[job_status_exclusion_list] AS [ex] WHERE [ex].[job_name] = [j].[job_name]) AND
[j].[secondary_enabled] = 0
ORDER BY [j].[job_name];

EXEC (@sql);
END

-- If the SP is running at the new-Primary Replica, except for the ones in the exclusion list, disable all jobs which was disabled at the previously Primary Replica.
IF (SELECT [dbo].[fn_hadr_group_is_primary](NULL)) = 1
BEGIN
DECLARE @sql2 NVARCHAR(max) = '';

SELECT 
@sql2 += N'EXEC msdb.dbo.sp_update_job @job_name = ''' + [job_name] + N''', @enabled = 0;' 
FROM [jobs].[job_status] AS [j]
WHERE 
NOT EXISTS(SELECT [job_name] FROM [jobs].[job_status_exclusion_list] AS [ex] WHERE [ex].[job_name] = [j].[job_name]) AND
[j].[primary_enabled] = 0
ORDER BY [j].[job_name];

EXEC (@sql2);
END
END


-- The job that executes the stored procedures above during a failover.

I find it unnecessary to copy/paste the whole script of the job here, it's a simple job consisting of 3 steps.

The name of the job must be "_DBA: Configure SQL Server Agent jobs after a failover", if you do not agree, than please modify the code below accordingly.

REMINDER: Ensure the following code is executed in the correct database where these objects are created.

1. step's code: EXEC [jobs].[enable_jobs_after_failover];
2. step's code: EXEC [jobs].[disable_jobs_after_failover];
3. step's code: EXEC [jobs].[update_job_status_accross_nodes];

A schedule in the type of "Start automatically when SQL Server Agent starts" is needed so that the steps above will be executed at startup in case a replica shuts down unexpectedly.

You also may want to add a notification (Database Mail configuration and an existing operator is needed) so that you'll be informed about a failover.


-- The following alert is triggered when a failover occurs and it is used to execute the job at both of the replicas.

DECLARE @job_id_var uniqueidentifier;
SELECT @job_id_var = job_id FROM msdb..sysjobs WHERE name = '_DBA: Configure SQL Server Agent jobs after a failover'

EXEC msdb.dbo.sp_add_alert
        @name = N'AG Role Change',
        @message_id = 1480,
    @severity = 0,
    @enabled = 1,
    @delay_between_responses = 0,
    @include_event_description_in = 1,
    @category_name=N'[Uncategorized]', 
    @job_id=@job_id_var
GO

REMINDER: Take the following part out if you do not have a SQL Server Agent Operator.

EXEC msdb.dbo.sp_add_notification 
        @alert_name = N'AG Role Change', 
        @operator_name = N'DBA', 
        @notification_method = 1; 

GO

************************** End of the script **************************

After executing the scripts above, the SP "[jobs].[update_job_status_accross_nodes]" needs to be executed at the primary replica at least once to update the "[jobs].[job_status]" table so that the solution will know about the status of your jobs at both of the replicas.

During an AG failover the alert is triggered at the previously-primary (if it's still up) and new-primary and every time it is triggered, it executes the job that is created above. Then job enables and disables the related jobs at both of the replicas. Simple.

Some critical points:
- If you happen to decide to use a different name for the job, then please be careful about the create alert step, because the default job name is used to find the correct job_id from the related system table.
- The job must be enabled all the time and at all replicas. This is vital. Otherwise the alert does not execute it.
- If you want to change the name of the Linked Server, then you must update the script accordingly, otherwise it'll be broken.
- Make sure that your SQL Server Agent service's startup parameter is "Automatic", so that it executes the job at startup and update the status of the jobs accordingly.

As I said from the beginning, most of these code blocks are familiar to almost all of us thanks to my peers' hard work. I guess the only bit I add is during a failover, executing a job by a triggered alert at both replicas and enabling/disabling related jobs this way. If a method exactly like this (obviously I'm unaware) has already been shared by someone else, please let me know so that I can write a note about it.

If you have a suggestion, question or if there's something wrong with the code or method above, please tell me and let's make it better together!

That's it folks! I hope you find this solution useful and practical as I do.

Thanks for reading,
Ekrem Onsoy
Microsoft SQL Server Consultant

16 Ağustos 2016 Salı

Bir Azure SQL Database'i yerel bir Instance'a taşımak

Selam millet,

Bugün bir yazılımcı arkadaş, Azure SQL Database'de bulunan bir veritabanını verileriyle birlikte yerel bir sunucumuza taşıma talebinde bulundu.

Yaptığım işlem çok özetle ilgili SQL Database'i Azure'daki müsait bir Storage'a Export etmek ve sonrasında üretilen *.bacpac dosyasını yerel ortamdaki uygun bir sunucuya indirmek ve daha sonra da Restore/Import edilmesi istenen yerel SQL Server Instance'ına Restore etmek oldu.

Bu yazıda daha ziyade değinmek istediğim şey ise *.bacpac dosyasının marifeti. Azure SQL Database'deki veritabanının versiyonu 12.0.2000.8, yani V12 idi, *.bacpac dosyasını Restore ettiğim Instance'ın versiyonu ise 11.0.5582.0 idi. Deneyimli her SQL Server DBA'in bildiği gibi, üst bir versiyonda oluşturulmuş olan *.bak dosyaları alt bir versiyona Restore edilemez. Daha net olmak gerekirse ve bu örnek üstünden gidersek 12.0.2000.8 versiyonunda olan bir Instance'ta oluşturduğunuz bir *.bak dosyası 11.0.5582.0 versiyonlu bir Instance'a Restore edilemez. Fakat 12.0.2000.8 versiyonunda oluşturulmuş bir *.bacpac dosyası pekala ve başarıyla 11.0.5582.0 versiyonlu bir Instance'a Restore edilebiliyor.

Bununla birlikte, bu Restore (aslında Import) işlemini doğrudan 11.0.5582.0 üstündeki SQL Server Management Studio'dan yapmaya çalıştığımda şöyle bir hata aldım:

TITLE: Microsoft SQL Server Management Studio
------------------------------
Count not load schema model from package. (Microsoft.SqlServer.Dac)
------------------------------
ADDITIONAL INFORMATION:
Internal Error. The database platform service with type Microsoft.Data.Tools.Schema.Sql.SqlAzureV12DatabaseSchemaProvider is not valid. You must make sure the service is loaded, or you must provide the full type name of a valid database platform service. (Microsoft.Data.Tools.Schema.Sql)

Bu sorun *.bacpac dosyasından ziyade SQL Server Management Studio'nun versiyonuyla ilgiliydi. Aynı *.bacpac dosyasını SQL Server Management Studio'nun daha yeni bir versiyonunda Import etmeyi denediğimde hiçbir sorunla karşılaşmadan işlem başarıyla tamamlandı. Eğer olur da biri böyle bir hata ile karşılaşırsa diye burada not etmek istedim.

Sevgiler,
Ekrem Önsoy

12 Ağustos 2016 Cuma

Sorunları donanım ekleyerek sadece bir yere kadar ötelersiniz

Merhabalar,

Çalıştığımız ortamlardan birinde 3 senedir arşivleme yapılmıyordu ve canlı ortamda devreye girmiş  ve henüz kontrolden geçmemiş bazı kodlar vardı.

En son gösterilecek şeyi en önce göstereyim:

CPU kullanım grafiği

Yukarıda grafiğini gördüğünüz şey, bahsini ettiğim bu şirket için en kritik olan veritabanı sunucusuna ait CPU kullanım grafiği.

Tabii bu grafiği CPU kullanım ortalaması zaten düşükmüş olarak yorumlamayın hemen. CPU kullanım oranının ortalama %20-25'lerde görünmesinin nedeni, yoğun ortalamanın bu seviyede oluşu. Yani kısa süreli de olsa çok daha yoğun kullanımlar oluyordu, fakat yukarıdaki grafiği oluşturmak için kullanılan verinin çokluğu ve ortalamanın %20-25'lerde olması nedeniyle grafikte ortalama bu seviyelerde görünüyor. Yani eğer birkaç ay geriye dönük değil de daha kısa zaman dilimlerinde bakılırsa ortalama daha yüksek gözükür.

Bununla birlikte dikkat edilirse ya işlenmesi gereken verinin gitgide artmış olmasından, ya bazı yeni kodların devreye girmesinden vb. CPU kullanımının zamanla yükseldiği de görülüyor. Yani müdahale edilmediğinde ortalama değer daha da artacaktı. Arşivleme ve performansiyileştirme işleri de 28 Temmuz tarihinde başlatıldı.

Bu ortamda arşivlenebilecek 3 senelik veriyi arşivledim ve bazı SP'leri elden geçirdik. Sadece bu çalışmalardan sonra CPU kullanımının yoğunluklu ortalaması %30'lardan %5'lere düştü.

Bunları anlatarak vermek istediğim mesajı daha da netleştirmek gerekirse, canlı sisteminizde olması şart olmayan veya canlı ortamda sadece zaman zaman ulaşılması gereken verilerinizi arşivleyin. Gereksiz veriler için indeks ve istatistik bakımları yapmayın, tablo/index tarama işlemleri yapmayın, sorgulanan veriyi işlemek için hafıza, disk, ağ ve işlemci gibi kaynaklarınızı boşa harcamayın.

Verilerinizi ihtiyacınıza göre ılık şekilde veya soğuk şekilde arşivleyin. Misal sürekli ana veritabanınızda olması gerekmeyen veriyi ayrı bir veritabanına aktarın, gerekirse disk altyapısını da disk/sistem yönetimi takımlarıyla planlayıp ayırın ve ihtiyaca göre tasarlayın. Bu ılık veriyi sadece gereken sorgularda/SP'lerde sorgulatın. Eğer verinin soğuk olarak arşivlenmesi gerekiyorsa planlamanızı yapın ve veriyi örneğin senelere, aylara bölün, sıkıştırarak yedekleyip canlı veritabanından silin. Tabii tüm bu çalışmaların iş bölümüyle, ilgili yazılım bölümleriyle ve yöneticilerle planlanıp uygulanması gerekiyor.

Sevgiler,
Ekrem Önsoy

5 Ağustos 2016 Cuma

Bir Fulltext Index tecrübesi

Selam arkadaşlar,

Son birkaç gündür bayağı yoğunluk oldu. Özellikle sorumlu olduğum ortamlardan birinde yaptığımız bir arşivleme çalışması neticesinde Fulltext Index Population işlemiyle bayağı cebelleştim.

Öncelikle senaryodan bahsedeyim. Çalıştığım sunucu canlı, üretim sunucusu. Burada SQL Server'ın Standard Edition'ı kullanılıyor, yani Table Partitioning, arşivleme için geçerli bir seçenek değil.

Arşivlenen üretim veritabanının adına Galata diyelim, arşiv veritabanının adına da Galata_arsiv. Galata'daki bazı tablolardaki kayıtlar, tarih değerlerine göre Galata_arsiv'e taşınıyor. Tabii ki taşıma, önce ilgili kayıtların Galata_arsiv'deki hedef tabloya kopyalanması, sonra da kaynaktan silinmesi şeklinde yapılıyor. Efendim Galata veritabanındaki kaynak tabloda 2 alan için bir de Fulltext Index tanımlı. Silinecek kayıt sayısı 30 milyon civarında.

Silme işlemini yaptım ve bir sorun yok. Bir süre sonra Ghost Cleanup arkaplanda çalışmaya başladı, gene bir sıkıntı yok. O günlük arşivleme çalışması tamamlandı ve bilgisayarımı kapattım. Fakat birkaç saat sonra CPU uyarı mesajları ve akabinde operasyonda çalışan arkadaşlardan yavaşlık şikayetleri gelmeye başladı. Hemen bağlandım baktım, CPU kullanımı sürekli %95'in üstünde, IO çok yüksek. Felaket!

Önce hemen sorun Windows'taki başka bir uygulamada mı yoksa SQL Server'da mı onu kontrol ettim, sorun SQL Server Instance'ındaydı. Daha sonra çok silme işlemi yaptığım için Ghost Cleanup işleminden şüphelendim. Nedir bu Ghost Cleanup ondan da çok özetle bahsedeyim. SQL Server'daki bir tablodan kayıt sildiğinizde bu kayıtlar birkaç nedenden dolayı hemen silinmezler, silinecek olarak işaretlenirler. Öncelikle bu hem silme işleminin hızlı olmasını sağlar, hem de olur da işlemi iptal etmek ve veriyi geri getirmek isterseniz bu yolla çok daha hızlı olmuş olur. Daha sonra belli bazı şartlar oluştuğunda Ghost Cleanup devreye girer ve bu kayıtları yavaş yavaş siler. Efendim inceledim, baktım ve sorunun Ghost Cleanup olmadığına karar verdim.

Kullanıcı işlemlerinde bir gariplik var mı diye inceledim, özellikle göze çarpan bir işlem görmedim. Peki ne oluyordu bu SQL Server Instance'ına da birden bu kadar çok kaynak kullanmaya başlamıştı?

Biraz daha inceleyince gözüme özellikle bir sistem işlemi çarptı. Çok fazla CPU tüketiyordu. Lastwaittype'ına bakınca "FW CRAWL" ibaresini gördüm. O anda aklıma başımın Fulltext Index ile dertte olabileceği geldi. Hemen silme işlemi yaptığım tabloları kontrol ettim, evet, birinde Fulltext Index vardı ve Population işlemine başlamıştı bile. Yani yapılan milyonlarca kayıt silme işlemini kendi Index'ine yansıtıyordu. Fulltext Index uzmanı değilim, tam olarak ne yapıyor da ne oluyor henüz inceleme şansım olmadı ve şunu da belirtmeliyim ki Fulltext Index konusu başlı başına bir kitap konusudur ki sadece bu konuda yazılmış kitaplar vardır. Fakat başka bazı belirtilere göre de başımın Fulltext Index ile dertte olduğu artık kesindi.

Bu arada, sorunun Fulltext Index olduğundan emin olmadan önce, herhangi bir Bug veya gariplikle karşı karşıya olma ihtimaline karşın SQL Server Instance'ını birkaç kere yeniden başlatmıştım. Servis açılırken Galata_arsiv veritabanının uzun süre In-Recovery durumda kaldığını gördüm. Benim silme işlemlerim biteli çok olmuştu ve Transaction Log dosyasını boşaltmıştım, yani geri alınacak veya sürdürülecek herhangi bir log yoktu içinde. Bu Recovery de neyin nesi diye düşünüyordum. Fulltext Index durumu kafamda netleşince, Recovery'nin de bununla ilgili olduğunu anladım. Veritabanı Recovery durumuna düştüğüne göre ve Recovery'nin 3. fazında 15-20 dakika beklediğine göre bir şeyler (Fulltext Index ile ilgili) loglanıyordu.

Efendim ya henüz ben bulamadım ve bilemedim, ama maalesef bir Fulltext Index Population işleminin tam olarak hangi safhada olduğu, yani mesela yüzde kaçının tamamlandığı ve benzeri bir bilgiyi edinebileceğim herhangi bir sistem kataloğu veya DMV'si yok. Bilen varsa da lütfen paylaşsın, ben de buradan duyurayım. Sadece Fulltext Index'leri ve kataloglarını görüntüleyebiliyoruz, bir de Index'in güncel olmayan durumunu. "Index'in güncel olmayan durumu" derken neyi kastettiğimi de hemen belirteyim, [sys].[dm_fts_index_population] isimli DMV ile bir Fulltext Index'in o anki durumunu ([status_description]) görebiliyorsunuz, fakat benim senaryomda bu alanda "Starting" yazıyordu, halbuki bu işlem başlayalı 2 gün olmuştu zaten! Tabii insan kuşkulanıyor ve akla sorular düşüyor, işlem gerçekten devam ediyor mu, yoksa bir yerde bloke mi oldu, bloke olsa neden bu kadar kaynak tüketiyor, yoksa kaynak tüketen ve henüz tespit edemediğim başka bir işlem mi var? Bu noktada Fulltext Index'in kara kutu olduğunu düşünmeye başlamıştım, ki hala öyle görünüyor.

Bununla birlikte, şöyle sorular soruyor olabilirsiniz:
- Neden Population'ı durdurmadın?
- Neden Fulltext Index'i silmedin veya Disable duruma getirmedin?
- Neden Auto-tracking'i Manuel yapmadın ve daha uygun zamanda devam etmedin Population'a?

Çok güzel sorular ve tabii ki benim de ilk aklıma gelenler oldu. Fakat FW CRAWL işlemini yapan sistem işlemi buna izin vermedi. Yukarıdaki sorular için aksiyon almaya kalktığımda FW CRAWL sistem işleminin o aksiyonu bloke ettiğini gözlemledim. Ayrıca bloke olan sadece benim aksiyon almak için kullandığım işlem değil, arşiv veritabanına gelen diğer tüm kullanıcı işlemleri de o anda bloke oluyordu. Ben aksiyon almak için kullandığım ALTER FULLTEXT INDEX vb komutları çalıştırdığım işlemi sonlandırdığım anda blokasyon çözülüyor ve kullanıcılar işlemine devam edebiliyordu.

Yani öyle bir durum ki, Population'ı durduramıyorum, CPU ve IO kaynaklarım sonuna kadar kullanılıyor, kullanıcılardan sürekli yavaşlık şikayetleri geliyor.

Durum konusundaki bazı noktalar netleşince hemen alternatif bir aksiyon planı hazırladım. O aksiyon planını devreye almadan önce, sorunun şiddetini dindirebilecek önlemleri almak için ilgili birimler arasında küçük toplantılar tertip ettim, alınabilecek küçük, hızlı, anlık sorunları hafife indirgeyecek aksiyonlar aldık ve tüm bunlar konusunda ilgili yöneticileri zaman zaman bilgilendirdim. Eğer Population işlemi T zamanına kadar bitmeseydi, ilgili yöneticilerin onayıyla da alternatif planı devreye alacaktım. Fakat işlem dün akşam nihayet tamamlandı.

Bu yazıdan özellikle almanızı beklediğim şey, bir kriz anında panik yapmadan yapılacak şeyleri düşünmeniz, ilgili yöneticileri her daim bilgilendirmeniz, özellikle de kritik bir aksiyon almadan önce. Yeri geldiğinde tabii ki inisiyatif alın, fakat unutmayın ki siz resmin sadece bir bölümünü görebilirsiniz, ilgili yöneticileriniz resmin daha büyük kısmına hakim, o nedenle kritik bir aksiyon öncesinde muhakkak ilgili birimlerle ve yöneticilerle eşgüdümlü çalışın. Biliyorum kolay değil, ama panik yapmayın. Veritabanı yönetimi, tüm şirketi etkileyen, hatta bir şirketin en hayati kademelerinden biridir. Çok ciddi bir iştir ve büyük sorumluluk ister. Her zaman bunun bilincinde olmalısınız.

Sevgiler,
Ekrem Önsoy