Coğrafi olarak dağıtık sistemler inşa etmek artık bir lüks değil; bir zorunluluktur. İster düzenleyici uyumluluk, ister gecikme optimizasyonu, isterse felaket kurtarma olsun, ekipler giderek daha fazla uygulamalarını birden fazla AWS bölgesi veya Google Cloud bölgesine dağıtıyor. Ancak, verileri bölgeler arasında taşımak temel bir zorluğu ortaya çıkarır: performansı kabul edilebilir seviyede tutarken güçlü tutarlılık garantilerini korumak. Bu yazıda, önde gelen iki yönetilen veritabanı hizmeti olan Google Cloud Spanner ve Amazon DynamoDB kullanarak doğrusallaştırılabilir okumaları nasıl uygulayacağımızı inceleyeceğiz.
Neden Doğrusallaştırılabilirlik Önemlidir
Doğrusallaştırılabilirlik (Linearizability), hiyerarşideki en güçlü tutarlılık modeli seviyesidir. Her okumanın, en son tamamlanan yazma işlemi tarafından yazılan değeri döndürdüğünü ve her yazma işleminin sistem genelinde atomik olarak uygulandığını garanti eder. Çok bölgeli bir bağlamda bunu başarmak zordur çünkü ağ bölünmeleri yaygındır ve fiziksel mesafe önemli bir gecikme (latency) getirir. Doğrusallaştırılabilirlik olmadan, kullanıcılar bir yazma işleminden sonra eski (stale) verilerle karşılaşabilir; bu da finansal işlemlerde, envanter yönetiminde veya oturum durumlarında kritik hatalara yol açabilir. Uygulamanızdaki kritik yollar için doğrusallaştırılabilir okumalar, nihai tutarlılık (eventual consistency) modellerinin sağlayamayacağı bir güvenlik ağı sunar.
Google Cloud Spanner: Gerçek Doğrusallaştırılabilirlik
Spanner, küresel ölçekte güçlü tutarlılık sağlamak için sıfırdan tasarlanmıştır. Birden fazla veri merkezi arasındaki saat belirsizliğini yönetmek için "TrueTime" adlı bir teknik kullanır. Spanner'da bir okuma yaptığınızda, doğrusallaştırılabilirliği sağlamak için yalıtım seviyesini (isolation level) belirleyebilirsiniz. Varsayılan olarak Spanner okumaları serileştirilebilir (serializable)dir; bu, doğrusallaştırılabilirlikten bile daha güçlüdür, ancak belirli kullanım senaryoları için yalıtım seviyelerinizi ayarlayabilirsiniz.
from google.cloud import spanner
def get_account_balance(client, account_id):
with client.snapshot(
read_timestamp=None, # Varsayılan olarak güçlü tutarlılık kullanır
staleness=None,
min_read_timestamp=None,
max_staleness=None
) as snapshot:
sql = "SELECT balance FROM Accounts WHERE id = @id"
params = {"id": account_id}
param_types = {"id": spanner.param_types.INT64}
result = snapshot.execute_sql(sql, params=params, param_types=param_types)
for row in result:
return row[0]
Snapshot'ta read_timestamp=None kullanımına dikkat edin. Bu, okumanın doğrusallaştırılabilir olduğunu garanti etmek için saatin beklenmesini gerektiren güçlü bir okuma olduğunu gösterir. Bu, saat belirsizliği nedeniyle küçük bir gecikmeye neden olsa da, daha yeni bir yazma işlemi tarafından geçersiz kılınmış bir değeri asla okumadığınızı garanti eder. Hafif bir gecikmenin kabul edilebilir olduğu gecikmeye duyarlı okumalar için, Spanner'ın mimarisi tutarlılık ve hızı etkili bir şekilde dengelemenize olanak tanır.
Amazon DynamoDB: Koşullu Okumalarla Doğrusallaştırılabilirlik Sağlama
DynamoDB temel olarak nihai tutarlı bir depolama alanıdır, ancak "güçlü tutarlı" (strongly consistent) bir okuma seçeneği sunar. Okuma isteğinizde ConsistentRead=True ayarlayarak, okumanın en son yazma işlemini yansıttığından emin olursunuz. Ancak, DynamoDB Global Tables kullanan çok bölgeli bir kurulumda gerçek doğrusallaştırılabilirliği elde etmek, sürümleme (versioning) ve koşullu güncellemelerin dikkatli yönetilmesini gerektirir.
DynamoDB Global Tables varsayılan olarak son yazar kazanır (last-writer-wins) çakışma çözüm stratejisini kullanır. Doğrusallaştırılabilir davranışı elde etmek için, uygulama katmanınızda bir sürüm vektörü (version vector) veya mantıksal saat (logical clock) uygulamanız gerekir. Bir yazma işlemi gerçekleştiğinde, bir sürüm numarası artırılır. Okuma sırasında, okumanın tüm bölgelerdeki en son sürümle tutarlı olduğundan emin olursunuz.
import boto3
dynamodb = boto3.client('dynamodb', region_name='us-east-1')
def get_item_strongly_consistent(table_name, key):
response = dynamodb.get_item(
TableName=table_name,
Key=key,
ConsistentRead=True
)
return response.get('Item')
ConsistentRead bir bölge içinde güçlü tutarlılık sağlasa da, bölge arası doğrusallaştırılabilirlik ek mantık gerektirir. Pratik bir kalıp, "yazma sonrası okuma" (read-after-write) belirteci kullanmaktır. Bir yazma işleminden sonra, istemci benzersiz bir yazma kimliği alır. Ardışık okumalar, henüz en son yazma işlemini senkronize etmemiş farklı bir bölgeden eski veri döndürülmesini önlemek için bu kimliği içerebilir. Bu yaklaşım, uygulama seviyesinde doğrusallaştırılabilirliği taklit eder ve kullanıcıların her zaman en son durumu gördüğünden emin olur.
Uygulama İçin Pratik Kalıplar
Sisteminizi tasarlarken aşağıdaki kalıpları göz önünde bulundurun:
- Hibrit Tutarlılık: Doğrusallaştırılabilir okumaları yalnızca finansal işlemler veya oturum kimlik doğrulama gibi kritik veri yollarında kullanın. Günlükler veya analitik gibi diğer veriler için nihai tutarlılık yeterlidir ve daha maliyet-etkindir.
- Tutarlılık Belirteçli Okuma Kopyaları: DynamoDB'de, okumanın en son yazma işlemini yansıttığından emin olmak için sürüm numaralarıyla koşullu okumalar kullanın. Spanner'da, manuel sürümleme yapmaktan kaçınmak için yerleşik tutarlılık modellerinden yararlanın.
- Gecikme Farkındalığı: Doğrusallaştırılabilir okumalar ek gecikme getirir. API'nizi bunu zarif bir şekilde ele alacak şekilde tasarlayın; istemcinin başarıyı varsaydığı ve daha sonra sunucuyla uzlaştığı iyimser UI güncellemeleri kullanmak gibi.
Sonuç
Çok bölgeli sistemlerde doğrusallaştırılabilir okumaları uygulamak karmaşık ama yapılabilir bir görevdir. Google Cloud Spanner, güçlü tutarlılık için yerleşik destek sağlayarak, tutarlılığı her şeyin önünde tutan ekipler için doğrudan bir seçim haline gelir. Amazon DynamoDB, güçlü tutarlı okumaları ve uygulama seviyesi sürümleme yoluyla esneklik sunarak, geliştiricilerin tutarlılık modellerini belirli ihtiyaçlara göre uyarlamasına olanak tanır. Takasları (trade-offs) anlayarak ve doğru araçları kullanarak, performansı feda etmeden veri bütünlüğünü koruyan sağlam, çok bölgeli sistemler inşa edebilirsiniz. Sisteminiz ölendikçe, tutarlılığın bir spektrum olduğunu ve her veri yolu için doğru seviyeyi seçmenin başarılı bir mimarinin anahtarı olduğunu unutmayın.