SDTR
Published in

SDTR

Distributed Lock Nedir?

Herkese Selamlar,

Bugün sizlerle distributed lock konusu hakkında konuşacağız.

Bir süredir bir yazılım dili/framework üzerinde kendimi geliştirmek yerine buna biraz ara vermiş, yazılım dünyasında sıklıkla duyduğumuz ve kullandığımız, teknoloji bağımsız konseptler-yaklaşımlar üzerinde kendimi geliştirmekteyim. Ele aldığım konseptlerden biri ise distributed lock idi, bu konuda araştırmalar yaptım ve kendi projelerime implementasyonunu gerçekleştirdim.

Bu makalede distributed lock nedir konusu üzerine olacak. Ancak herhangi bir implementasyon örneği bulunmayacak. Amacım tamamen dil ve framework bağımsız olarak bu konseptin mantığını ve amacını anlatabilmek olacak.

Distributed lock üzerine konuştuktan sonra, bu tarz bir mekanizmayı en basit düzeyde nasıl kurabiliriz, bunun üzerinde duracağım. Ardından her aşamada karşılaştığımız sorunları ele alarak, bu sorunun çözümü olacak olan bir sonraki aşamaya geçeceğim. Makalenin sonunda ise, hemen hemen yaşadığımız tüm sorunları çözen “redlock” algoritmasına değineceğim.

Ayrıca başlamadan önce belirtmeliyim ki, redisin resmi sitesinde redlock algoritması ile ilgili çok güzel bir döküman bulunmakta. Bu dökümanı bir kaç kez incelemiş biri olarak, buradaki ana ilerleyiş redlock dökümanına benzer olacak. Yani bu makaleyi, redis redlock dökümanını da içeren (elbette kendi cümlelerimle), ve kendimden de bir şeyler katmaya çalıştığım bir içerik olarak düşünebilirsiniz.

Daha fazla uzatmadan başlayalım. 😊

Lock Konsepti

Yazılım dünyasında bir çok farklı yerde ve farklı yapıda kilitleme konseptleri ve mekanizmaları mevcuttur. İlişkisel veritabanları üzerinde kullanılan transaction lock, redlock gibi algoritmaların kullanıldığı distributed lock, vb. şeklinde sıralayabiliriz.

Günümüzde geliştirdiğimiz sistemler genellikle multi-thread bir yapıya sahiptir. Bu, eş zamanlı olarak birbirinden farklı thread’ler üzerinde farklı operasyonların gerçekleştirebileceği anlamına gelir.

Sistemimizde yer alan bazı operasyonlar, ortak veriler üzerinden işlemleri gerçekleştiriyor olabilir. Bu durumda, ilgili operasyonların bu veri kaynaklarına erişimi tamamen düzensiz olacaktır. Her operasyon, bir t zamanında sadece kendisi çalışarak paylaşılan veri kaynağına ulaşıp işlemini gerçekleştirebilir, veya Aynı anda tetiklenen istekler sonucu birden fazla thread üzerinde birbirinden farklı veya aynı operasyonların, paylaşılan veri kaynağına erişerek çalışması söz konusu olabilir.

Yukarıda bahsettiğim ikinci senaryoda, paylaşılan veri üzerinde sadece okuma işlemi yapılmakta ve ilgili operasyonlar bu okuma işleminden sonra gerçekleşiyorsa, bir sıkıntıdan bahsedemeyiz. Peki ya paylaşımlı veri üzerinde hem okuma hem yazma işlemleri yapılıyorsa?

Paralel veya eşzamanlı olarak çalışan birden fazla thread’in paylaşımlı veri kaynağına erişerek okuma işlemi gerçekleştirdiğini, sonrasında bir thread’in bu veri kaynağı üzerinde bir yazma işlemi yaptığını varsayalım. Diğer tüm thread’ler, ilk başta okuduğu değer üzerinden işlemlerini gerçekleştireceklerinden dolayı, hatalı işlem yapılmış olur. Bu duruma yazılım dünyasında “race condition” diyoruz. Aşağıdaki görselde bir race condition örneği görebilirsiniz.

Bu durumda, paylaşımlı verinin bir veritabanı üzerinde tutulduğunu düşünürsek, race condition sorununu transaction lock mekanizmalarını kullanarak çözebiliriz. Konumuz veritabanı olmadığı için transaction lock konusuna detaylıca değinmeyeceğim, ancak genel olarak iki çeşit lock tipi mevcuttur, pesimistic ve optimistic lock. Eğer optimistic lock uygulamak isterseniz, “Isolation Level” adını verdiğiniz lock seviyelerine göre mekanizmanın davranışı farklılık gösterecektir.

Tam bu noktada, kendimize iki kritik soru sorabiliriz.

Birincisi, ya paylaşımlı olarak kullanılan veri, bir veritabanı üzerinde saklanmıyorsa?

İkincisi, Veritabanı seviyesinde değil de, daha üst seviye bir kilitleme mekanizması uygulamak istiyorsak?

Eğer bir projede lock mekanizması ihtiyacı duyuyorsanız, ve kendinize bu soruları soruyorsanız, distributed lock yapısı sizin için çözüm olabilir.

Distributed Lock

Distributed lock , bir sistem üzerinde bazı operasyonlar gerçekleştiren ve eş zamanlı çalışabilen işlemlerin, paylaşımlı veri kaynaklarına erişimini denetim altına almak için kullanılan mekanizmadır.

Distributed lock mekanizması sayesinde, yukarı kısımda sorduğumuz 2 sorunu çözebilmekteyiz. Öncelikle, veritabanına bir bağımlılığımız bulunmadığı için, herhangi bir paylaşımlı veriye olan erişimi denetim altına alabilmekteyiz. Ayrıca istediğimiz seviyede bir lock mekanizması oluşturabiliriz.

Örneğin, içerisinde kullanıcılar ile ilgili operasyonların bulunduğu bir proje geliştirdiğimizi düşünelim. İki ayrı operasyon olan kullanıcı güncelleme ve kullanıcı silme operasyonlarının aynı anda tetiklendiğini düşünelim.

İki process’in de ilgili kullanıcıya eriştiğini, ancak ilk operasyon kullanıcıyı güncellemeden ikinci operasyonun kullanıcıyı sistemden sildiğini düşünürsek, bu durumda istenmeyen ve veri tutarlılığını olumsuz etkileyen bir senaryo gerçekleşmiş olur.

Şimdi bu senaryo üzerinden karşılaştığımız sorunu çözecek bir distributed lock mekanizması tasarlayalım. Ardından tasarladığımız mekanizmanın sorunlarını inceleyip, bu sorunu çözen yeni bir tasarıma geçelim. Bu şekilde en başarılı distributed lock yapısına ulaşmaya çalışacağız.

Distributed Lock With Redis

Redis veritabanı kullanarak bir distributed lock mekanizması kurabiliriz. Paylaşımlı bir veriye erişmek isteyen process, redis üzerinde “Acquire Lock” dediğimiz, ilgili veri ile ilgili bir lock objesi oluşturmaya çalışır. Burada key değeri olarak üzerine lock alınan obje ile ilgili bir değer, value değeri olarak ise lock alan thread’in numarası kullanılabilir. Yukarıdaki örnek üzerinden gidecek olursak, 1 idli kullanıcı için bir güncelleme işlemi yapılacak ise, ilk thread redis üzerinde “user_1_lock” key değerinde bir lock objesi oluşturur. Sonrasında kullanıcı güncelleme işlemini gerçekleştirir. Ardından operasyon tamamlandığında, redis üzerindeki lock objesini kaldırmak için “Release Lock” isteği yapar.

Redis üzerinde “user_1_lock” key değerinde bir kayıt olduğu sürece, Bu kullanıcıyı güncellemek veya silmek isteyen bir thread acquire lock aşamasında başarılı olamayacağı için, bu verinin locklandığını anlayacak, ve işlemi gerçekleştirmeden geriye response dönecektir.

Kurmuş olduğumuz yapının sorunu nedir ? sorusuna cevap olarak, sektörde sıklıkla duyduğumuz “single point of failure” sorunu diyebiliriz. Distributed lock objelerini tuttuğumuz redis instance’i down olursa, tüm mekanizma devre dışı kalacaktır.

Distributed Lock With Redis (Master-Slave)

Single point of failure sorununu çözebilmek adına, bir adet master redis ve bir veya daha fazla slave redis kullanabiliriz. Master redis, kendisi üzerinde yapılan her değişikliği slave redislere yansıtarak, senkronizasyonu sağlamaktadır.

Yukarıda verilen örnek için, master redis down olursa, slave redislerden birisi yeni master olacak, ve mekanizma çalışmaya devam edecektir. Bu şekilde single point of failure sorununu çözdük. Peki şuanki sorunumuz ne?

Bir veri kaynağı üzerine lock işlemi gerçekleştirmek için, tüm threadler sabit bir key değeri kullanıyor (“user_1_lock” gibi). Bir threadin 1 numaralı user için lock alıp güncelleme işlemine başladığını düşünelim. Alınan bu lock objesi, master redis üzerine yazılacaktır. Peki ya master redis, kendisi ile diğer slave redisleri senkron edemeden down olursa? Yeni master olan redisde, az önce alınan lock objesi bulunmayacaktır.

Bu senaryoda ikinci bir thread gelip lock almaya çalışırsa, başarılı bir şekilde alabilecektir. Ancak aslında ilk thread işlemine devam etmekte. İlk thread veri üzerindeki lock objesini kaldırmaya çalıştığında, aslında ikinci thread’in aldığı lock objesini kaldırmış olur. Eğer üçüncü bir thread de gelirse bu zincirleme bir hataya yol açar, ve tüm threadler kendinden sonra gelen threadin lock objesini kaldırmaya devam eder. Peki bu sorunu nasıl çözebiliriz?

Buradaki sorunun kaynağı, tüm threadlerin aynı key değerini kullanmasından kaynaklanıyor. Her thread için, o thread’e özel bir key değeri kullanılırsa, threadler sadece kendi key değerlerine sahip lock objesini release etmek isteyecektir. Böylece birbirlerinin lock objelerini kaldırmayacaklardır. Örneğin, key değeri olarak threadId değerini de ekleyerek her thread için unique bir key değeri elde edebiliriz.

“user_1_{threadId}_Lock”

Zincirleme hata sorununu da çözdük ancak hala, master redisin kendini diğer slave redisler ile senkron edemeden down olduğunda, yeni master’da ilk threadin oluşturmuş olduğu lock objesinin bulunmaması sorununu çözemedik. Yani zincirleme hata oluşmayacak olsa da, ikinci thread hala lock yokmuş gibi işlemi gerçekleştirmeye devam edecektir. Bu son sorunun da çözümünü, redlock algoritması kullanarak çözebiliriz.

Redlock

Redlock, redis resmi sitesindeki dökümanda da anlatıldığı gibi bir distributed lock algoritmasıdır. Yukarıdaki tüm adımların özet bir anlatımını bu dökümanda bulabilirsiniz, redlock algoritması tüm bu sorunları çözümlemek için yukarıdaki çözümleri kullanır.

Redlock algoritması, single point of failure sorununu çözmek için cluster yapıyı kullanır. Kullanılan redis instance’lar master-slave yapısında değil, her biri diğerlerinden bağımsız bir instancedır. Her thread’in oluşturduğu lock objesini ayırt edebilmek amacıyla, eşsiz bir redis key değeri kullanır.

Redlock algoritması, lock alınabilmesi için redis instance’ların %50 sinden fazlasına lock objesinin yazılması şartını koşar. Örneğin 5 adet redis instance var ise, bunlardan en az 3 tanesine lock objesinin yazılabilmesi gerekir. Lock objesi kaldırılırken ise, lock objesinin yazılmış olan tüm redis instance’lardan silinmesi işlemi gerçekleştirilir.

Redlock algoritması ile lock alma işleminin başarısız olması demek, ilgili veri üzerinde zaten bir lock olduğu anlamına gelir. Bu durumda, redlock algoritması kısa bir süre (milisaniyeler bazında) beklenilmesini, ve tekrardan lock alınmaya çalışılmasını tavsiye eder. Eğer bir kaç denemede hala lock objesi alınamamışsa, işlemin gerçekleştirilemediğine dair response dönülür.

Böylece redlock algoritması ile birlikte, distributed lock makalemizin sonuna gelmiş olduk. Elimden geldiğince distributed lock nedir, en temel düzey bir lock mekanizmasından daha ileri seviye yapılar nasıl geliştirilir bunlar üzerinde durmaya çalıştım. Umarım faydalı olmuştur.

Redlock algoritması hakkında daha detaylı bilgiye ulaşmak isterseniz, buradan redis üzreindeki dökümanı inceleyebilirsiniz. Bir başka makalede görüşmek üzere, kendinize iyi bakın. 😊

--

--

Yetenekli ve bilgili geliştiricilerden oluşan bir topluluk!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store