GCP Cloud Spanner Kurulum ve Kullanımı
Büyük ölçekli, küresel dağıtık uygulamalar geliştirirken veri tabanı seçimi kritik bir karar noktası haline gelir. Geleneksel ilişkisel veri tabanları ölçeklendirme sorunlarıyla boğuşurken, NoSQL çözümleri ACID uyumluluğundan taviz verir. Google Cloud Spanner ise bu ikilemden çıkmak için tasarlanmış, küresel ölçekte tutarlılık sunan, tam yönetilen bir ilişkisel veri tabanı servisidir. Bu yazıda Cloud Spanner’ı sıfırdan kurup production ortamında nasıl kullanacağınızı, gerçek dünya senaryolarıyla birlikte ele alacağız.
Cloud Spanner Nedir ve Ne Zaman Kullanmalısınız?
Cloud Spanner, Google’ın kendi iç sistemleri için geliştirdiği Spanner teknolojisinin halka açık versiyonudur. SQL sorgularını destekler, ACID transaksiyonları garanti eder ve aynı zamanda yatay olarak ölçeklendirilebilir. Bu kombinasyon normalde “CAP teoremi gereği imkansız” kategorisinde değerlendirilirdi; ancak Spanner, TrueTime API’si sayesinde küresel saat senkronizasyonu yaparak bu denklemi değiştirdi.
Spanner’ı şu durumlarda tercih etmelisiniz:
- Küresel tutarlılık gerektiren finansal uygulamalar (bankacılık, ödeme sistemleri)
- Milisaniye gecikmesiyle dünya genelinde veri erişimi gereken e-ticaret platformları
- Yüksek yazma/okuma hacmi olan ve downtime kaldıramayan sistemler
- Otomatik sharding isteyip manuel partition yönetiminden kaçınmak isteyenler
- Yüksek kullanılabilirlik (99.999% SLA) gerektiren kritik uygulamalar
Bununla birlikte, küçük ölçekli projeler veya saatlik birkaç yüz sorgu yapan uygulamalar için Spanner overkill olacaktır. Minimum maliyeti göz önünde bulundurarak Cloud SQL veya Firestore’u değerlendirmenizi öneririm.
Ön Hazırlık ve Ortam Kurulumu
Başlamadan önce birkaç şeyin hazır olması gerekiyor. GCP projenizin aktif olduğunu ve faturalandırmanın etkinleştirildiğini varsayıyorum.
Önce gcloud CLI aracının güncel olduğundan emin olalım:
# gcloud güncellemesi
gcloud components update
# Aktif hesabı kontrol et
gcloud auth list
# Proje ayarla
gcloud config set project YOUR_PROJECT_ID
# Spanner API'sini etkinleştir
gcloud services enable spanner.googleapis.com
# Etkinleştirmeyi doğrula
gcloud services list --enabled | grep spanner
Eğer Terraform ile infrastructure as code yaklaşımı kullanıyorsanız, google provider’ının en az 4.0 versiyonunda olduğundan emin olun. Servis hesabı için gerekli roller şunlardır:
- roles/spanner.admin: Tam yönetim yetkisi (sadece DevOps ekibi için)
- roles/spanner.databaseAdmin: Veri tabanı oluşturma ve şema yönetimi
- roles/spanner.databaseUser: Veri okuma/yazma (uygulama servis hesabı için)
- roles/spanner.databaseReader: Sadece okuma (raporlama araçları için)
Instance Oluşturma
Cloud Spanner’da hiyerarşi şöyledir: Instance > Database > Table. Instance, hesaplama kapasitesini ve coğrafi dağılımı tanımlar.
# Regional instance oluştur (geliştirme ortamı için uygun)
gcloud spanner instances create my-spanner-dev
--config=regional-europe-west1
--description="Development Instance"
--nodes=1
# Multi-region instance oluştur (production için önerilir)
gcloud spanner instances create my-spanner-prod
--config=nam6
--description="Production Multi-Region Instance"
--nodes=3
# Instance listesini görüntüle
gcloud spanner instances list
# Instance detaylarını incele
gcloud spanner instances describe my-spanner-prod
Instance yapılandırma seçeneklerini anlamak önemlidir:
- regional-europe-west1: Tek bölge, Belçika. Düşük gecikme, tek bölge kapsamı.
- nam6: Kuzey Amerika çoklu bölge. Yüksek kullanılabilirlik.
- eur3: Avrupa çoklu bölge (Hollanda + Belçika). GDPR uyumluluğu için ideal.
- nodes: Hesaplama kapasitesi. Her node yaklaşık 2000 QPS destekler.
Processing Units kullanımı, nodes yerine daha granüler ölçeklendirme sağlar. 1 node = 1000 processing unit. Küçük workload’lar için 100 processing unit ile başlayabilirsiniz:
# Processing units ile daha ekonomik instance
gcloud spanner instances create my-spanner-small
--config=regional-europe-west1
--description="Small Dev Instance"
--processing-units=100
Veri Tabanı ve Şema Oluşturma
Instance hazır olduğunda veri tabanı oluşturabiliriz. Spanner’ın SQL lehçesi Google Standard SQL ve PostgreSQL olmak üzere ikiye ayrılır. PostgreSQL lehçesini kullanmak mevcut uygulamaların Spanner’a geçişini kolaylaştırır.
# PostgreSQL lehçesiyle veri tabanı oluştur
gcloud spanner databases create ecommerce-db
--instance=my-spanner-prod
--database-dialect=POSTGRESQL
# Veya Google Standard SQL lehçesiyle
gcloud spanner databases create ecommerce-db-gsql
--instance=my-spanner-prod
--database-dialect=GOOGLE_STANDARD_SQL
# Veri tabanlarını listele
gcloud spanner databases list --instance=my-spanner-prod
Şimdi şema oluşturalım. Gerçekçi bir e-ticaret senaryosu için tablo yapılarını tanımlıyoruz:
# DDL ile şema oluştur
gcloud spanner databases ddl update ecommerce-db
--instance=my-spanner-prod
--ddl='
CREATE TABLE customers (
customer_id STRING(36) NOT NULL,
email STRING(255) NOT NULL,
full_name STRING(255) NOT NULL,
phone STRING(20),
created_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
updated_at TIMESTAMP OPTIONS (allow_commit_timestamp=true),
is_active BOOL NOT NULL DEFAULT (true)
) PRIMARY KEY (customer_id);
CREATE UNIQUE INDEX idx_customers_email ON customers(email);
CREATE TABLE orders (
order_id STRING(36) NOT NULL,
customer_id STRING(36) NOT NULL,
status STRING(50) NOT NULL,
total_amount NUMERIC NOT NULL,
currency STRING(3) NOT NULL DEFAULT ("TRY"),
created_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
) PRIMARY KEY (order_id),
INTERLEAVE IN PARENT customers ON DELETE CASCADE;
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_orders_status ON orders(status);
'
Burada dikkat çeken birkaç Spanner’a özgü özellik var:
- INTERLEAVE IN PARENT: Parent ve child tabloyu fiziksel olarak yan yana depolar. JOIN sorgularının performansını dramatik şekilde artırır.
- allow_commit_timestamp: Spanner’ın server-side timestamp özelliği. Uygulama katmanında timestamp yönetimine gerek kalmaz.
- STRING(36) PRIMARY KEY: UUID kullanımı için ideal. BYTES(16) de tercih edilebilir.
Veri Okuma ve Yazma
Spanner ile veri işlemlerini hem gcloud CLI üzerinden hem de client library kullanarak yapabilirsiniz. Önce CLI ile test edelim:
# Veri ekle
gcloud spanner rows insert
--instance=my-spanner-prod
--database=ecommerce-db
--table=customers
--data='customer_id=cust-001,[email protected],full_name=Ahmet Yilmaz,created_at=spanner.commit_timestamp()'
# Veri sorgula
gcloud spanner databases execute-sql ecommerce-db
--instance=my-spanner-prod
--sql='SELECT customer_id, email, full_name FROM customers LIMIT 10'
# Parametre ile sorgu (SQL injection güvenliği için her zaman parametreli sorgu kullanın)
gcloud spanner databases execute-sql ecommerce-db
--instance=my-spanner-prod
--sql='SELECT * FROM orders WHERE customer_id = @cust_id AND status = @status'
--params='{"cust_id": "cust-001", "status": "PENDING"}'
--param-types='{"cust_id": "STRING", "status": "STRING"}'
Python client library kullanarak daha kapsamlı bir örnek yapalım. Bu, gerçek uygulama entegrasyonuna daha yakın bir senaryo:
# Python client kütüphanesini kur
pip install google-cloud-spanner
# Servis hesabı kimlik bilgilerini ayarla
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
# Python ile Spanner kullanımı - transaction örneği
python3 << 'EOF'
from google.cloud import spanner
from google.cloud.spanner_v1 import param_types
import uuid
from datetime import datetime
# Client başlat
client = spanner.Client(project="YOUR_PROJECT_ID")
instance = client.instance("my-spanner-prod")
database = instance.database("ecommerce-db")
# Read-Write Transaction ile sipariş oluştur
def create_order(customer_id, items, currency="TRY"):
order_id = str(uuid.uuid4())
def transaction_body(transaction):
# Müşteri varlığını kontrol et
customer_row = transaction.execute_sql(
"SELECT customer_id, is_active FROM customers WHERE customer_id = @cid",
params={"cid": customer_id},
param_types={"cid": param_types.STRING}
)
rows = list(customer_row)
if not rows or not rows[0][1]:
raise ValueError(f"Aktif müşteri bulunamadı: {customer_id}")
total = sum(item["price"] * item["quantity"] for item in items)
# Sipariş oluştur
transaction.insert(
table="orders",
columns=["order_id", "customer_id", "status", "total_amount", "currency", "created_at"],
values=[(order_id, customer_id, "PENDING", total, currency, spanner.COMMIT_TIMESTAMP)]
)
return order_id
result = database.run_in_transaction(transaction_body)
print(f"Sipariş oluşturuldu: {result}")
return result
# Fonksiyonu çağır
create_order("cust-001", [{"price": 150.00, "quantity": 2}])
# Stale read örneği - raporlama için ideal
with database.snapshot(exact_staleness=datetime.timedelta(seconds=15)) as snapshot:
results = snapshot.execute_sql(
"SELECT status, COUNT(*) as cnt, SUM(total_amount) as total "
"FROM orders GROUP BY status"
)
for row in results:
print(f"Durum: {row[0]}, Adet: {row[1]}, Toplam: {row[2]}")
EOF
Performans Optimizasyonu
Spanner’da performans sorunlarının büyük kısmı yanlış şema tasarımından kaynaklanır. Önemli noktalar:
Hotspot problemi: Primary key olarak sıralı değerler (timestamp, auto-increment) kullanmak tüm yazmaları tek bir split’e yönlendirir. UUID veya hash-prefix kullanın.
Index tasarımı: Storing clause ile sık erişilen kolonları index’e ekleyerek full table scan’i önleyebilirsiniz:
# Storing index örneği - order listesi sayfası için
gcloud spanner databases ddl update ecommerce-db
--instance=my-spanner-prod
--ddl='
CREATE INDEX idx_orders_by_customer_date
ON orders(customer_id, created_at DESC)
STORING (status, total_amount, currency);
'
Query Execution Plan inceleme:
# Sorgu planını görüntüle
gcloud spanner databases execute-sql ecommerce-db
--instance=my-spanner-prod
--sql='SELECT o.order_id, o.total_amount, c.full_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.status = "PENDING"
ORDER BY o.created_at DESC
LIMIT 100'
--query-mode=PLAN
Okuma türleri arasındaki farkı anlamak performans açısından kritiktir:
- Strong read: Her zaman güncel veriyi okur. Yazma sonrası hemen okuma gerektiğinde kullanın.
- Stale read: Belirli bir gecikmeyle okur (15 saniye önerilir). Raporlama, dashboard gibi use case’ler için %50’ye kadar performans artışı sağlar.
- Bounded staleness: “En fazla X saniye eski veri kabul edilebilir” anlamına gelir. Coğrafi dağıtık okumalar için idealdir.
Yedekleme ve Geri Yükleme
Production ortamında yedekleme stratejisi hayati önem taşır:
# Manuel yedek al
gcloud spanner backups create ecommerce-backup-$(date +%Y%m%d)
--instance=my-spanner-prod
--database=ecommerce-db
--retention-period=7d
--async
# Yedek listesi
gcloud spanner backups list --instance=my-spanner-prod
# Yedekten geri yükle
gcloud spanner databases restore
--destination-instance=my-spanner-prod
--destination-database=ecommerce-db-restored
--source-instance=my-spanner-prod
--source-backup=ecommerce-backup-20241201
# Otomatik yedekleme politikası tanımla
gcloud spanner databases update ecommerce-db
--instance=my-spanner-prod
--backup-schedule-type=FULL
--full-backup-schedule="0 2 * * *"
--full-backup-retention-duration=168h
Yedekleme konusunda bilmek gerekenler:
- Backup süresi: Veri boyutuna bağlı, küçük veri tabanları için genellikle birkaç dakika
- Point-in-time recovery (PITR): Spanner, varsayılan olarak 7 güne kadar geriye gidebilme imkanı sunar
- Cross-region restore: Yedeği farklı bir bölgedeki instance’a restore edebilirsiniz
İzleme ve Alarm Kurulumu
Spanner’ın sağlığını izlemek için Cloud Monitoring entegrasyonunu mutlaka yapılandırın:
# CPU kullanım alarmı oluştur
gcloud alpha monitoring policies create
--policy-from-file=- << 'EOF'
{
"displayName": "Spanner High CPU Alert",
"conditions": [{
"displayName": "CPU utilization > 65%",
"conditionThreshold": {
"filter": "resource.type="spanner_instance" AND metric.type="spanner.googleapis.com/instance/cpu/utilization"",
"comparison": "COMPARISON_GT",
"thresholdValue": 0.65,
"duration": "300s",
"aggregations": [{
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_MEAN"
}]
}
}],
"alertStrategy": {
"autoClose": "1800s"
},
"notificationChannels": ["projects/YOUR_PROJECT/notificationChannels/YOUR_CHANNEL_ID"]
}
EOF
# Temel metrikleri sorgula
gcloud monitoring metrics list | grep spanner
İzlenmesi gereken kritik metrikler:
- spanner.googleapis.com/instance/cpu/utilization: CPU kullanımı. %65’i aşmamalı, %45 high-priority işlemler için eşik değeri.
- spanner.googleapis.com/instance/storage/used_bytes: Depolama kullanımı
- spanner.googleapis.com/api/request_latencies: API gecikmeleri. p99 latency takibi yapın.
- spanner.googleapis.com/instance/session_count: Aktif session sayısı. Session leak tespiti için önemli.
- spanner.googleapis.com/api/api_request_count: Hata kodlarına göre filtreleyerek anomali tespiti yapın.
Terraform ile Infrastructure as Code
Gerçek üretim ortamlarında Spanner altyapısını Terraform ile yönetmek best practice’tir:
# main.tf dosyası oluştur
cat > spanner.tf << 'EOF'
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
resource "google_spanner_instance" "prod" {
name = "prod-spanner"
config = "eur3"
display_name = "Production Spanner"
num_nodes = 3
labels = {
environment = "production"
team = "backend"
cost-center = "engineering"
}
}
resource "google_spanner_database" "ecommerce" {
instance = google_spanner_instance.prod.name
name = "ecommerce-db"
version_retention_period = "7d"
deletion_protection = true
ddl = [
<<-DDL
CREATE TABLE customers (
customer_id STRING(36) NOT NULL,
email STRING(255) NOT NULL,
full_name STRING(255) NOT NULL,
created_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (customer_id)
DDL
]
}
resource "google_spanner_database_iam_binding" "app_user" {
instance = google_spanner_instance.prod.name
database = google_spanner_database.ecommerce.name
role = "roles/spanner.databaseUser"
members = [
"serviceAccount:app-service-account@YOUR_PROJECT.iam.gserviceaccount.com"
]
}
EOF
# Plan ve apply
terraform init
terraform plan -out=spanner.plan
terraform apply spanner.plan
Maliyet Optimizasyonu
Spanner maliyeti iki ana bileşenden oluşur: hesaplama kapasitesi ve depolama.
Maliyet optimizasyonu için pratik öneriler:
- Geliştirme ortamlarında 100 processing unit kullanın, tam node satın almayın. Bu %90 tasarruf sağlayabilir.
- Stale read’leri agresif şekilde kullanın. Strong read yerine 15 saniyelik stale read, coğrafi dağıtık sistemlerde hem daha hızlı hem daha ucuzdur.
- Bağlantı havuzu kullanın. Her işlemde yeni session açmak pahalıdır. Client library’nin built-in session pooling özelliğini aktifleştirin.
- Otomatik ölçeklendirme için Cloud Spanner Autoscaler open-source çözümünü değerlendirin. CPU %65’i aştığında node ekler, %45’in altına düştüğünde azaltır.
- Backup retention süresini ihtiyaca göre belirleyin. Gereksiz uzun süreli yedekler depolama maliyetini artırır.
Regional instance kullanımı, multi-region’a kıyasla yaklaşık 3 kat daha ucuzdur. Eğer uygulamanızın kullanıcıları tek bölgedeyse regional instance yeterlidir.
Yaygın Sorunlar ve Çözümleri
Session Leaked hatası: Bağlantı havuzu yanlış yapılandırıldığında session’lar serbest bırakılmaz. Python client’ta with database.snapshot() as snapshot: gibi context manager kullanmak bu sorunu çözer.
Mutation limit aşımı: Tek bir transaction’da maksimum 80,000 mutation yapılabilir. Büyük batch işlemler için Dataflow veya Spanner’ın built-in BatchWrite API’sini kullanın.
Deadline Exceeded: Uzun süren transactionlar (10 dakika sınırı) bu hatayı tetikler. İşlemi küçük parçalara bölün veya batch okuma kullanın.
Hotspot tespiti: Cloud Console’dan Key Visualizer aracını açın. Kırmızı renkli alanlar hotspot’ları gösterir. Primary key veya index tasarımınızı gözden geçirin.
Sonuç
Cloud Spanner, küresel ölçekte tutarlılık gerektiren uygulamalar için gerçekten etkileyici bir çözüm. Kurulum süreci düşündüğünüzden daha basit; asıl dikkat gerektiren nokta şema tasarımı ve okuma stratejilerinin doğru belirlenmesi. INTERLEAVE, stale read ve parametreli sorgu gibi Spanner’a özgü kavramları kavradığınızda performansını maksimize etmek oldukça kolaylaşıyor.
Production’a geçmeden önce şu kontrol listesini mutlaka uygulayın: primary key’lerde hotspot kontrolü yapın, kritik sorgular için execution plan inceleyin, monitoring alarm’larını kurun, servis hesabı yetkilerini minimum privilege prensibine göre ayarlayın ve yedekleme politikanızı test edin.
Spanner’ın maliyeti başlangıçta caydırıcı gözükebilir, ancak yönetim yükü, yüksek kullanılabilirlik ve sıfır downtime maintenance gibi faydaları hesaba kattığınızda küçümsenmeyecek bir TCO avantajı sunduğunu göreceksiniz. Küçük projelerle başlamak için 100 processing unit seçeneği artık bu teknolojiyi test etmeyi her zamankinden erişilebilir kılıyor.
