DBA Günlükleri #15 : Couchbase üzerinde Veri Dışındaki Nesnelerin Yedeklenmesi

Hüseyin Demir
3 min readMay 2, 2020

--

Merhabalar, bu yazımda geçen yazımda incelediğim bir konunun 2. çalışması ile devam edeceğim. Daha öncesinde Couchbase’in sunmuş olduğu cloud-native endpointler üzerinden cluster discovery işlemleri ve bunların bize sağladığı operasyonel kolaylıklar hakkında tartışıp sonuçlarına bakmıştık. O çalışmayı temel alarak bugün, Couchbase üzerindeki kullanıcıların ve indexlerin nasıl iskelet şeklinde yedeklendiğinden bahsedeceğiz.

Couchbase üzerinde yedekleme konusu alışık olduğumuz yedekleme dinamiklerinden biraz daha farklı olabiliyor. Bizim yapımızda, sadece verinin kendisi yedeklenmektedir. Bu nedenle veri dışındaki index ve user bilgileri yedeğe dahil değildir. Bu durumu daha efektif bir şekilde çözmek için yine Couchbase’in sağladığı endpointleri kullandık. Ek olarak, zaman zaman(umarım hiç yaşanmaz bu:)) kullanıcı ya da index için restore dönmemizi gerektiren durumlar olabilir. Restore işleminde her zaman veri de restore edildiği için gereksiz nesnelerin de restore olmasını bekliyoruz. Bu da production-outgage diye tabir ettiğimiz durumlarda servis kalitemizi olumsuz yönde etkiliyor. Tüm bunların önüne geçmek için, Couchbase’in sunmuş olduğu endpointler üzerinden biz de kendi çözümümüzü geliştirdik. Bu sayede, kullanıcı ve index seviyesinde yaşanan sorunlarda sadece ihtiyacımız olan kullanıcıyı ya da indexi sisteme restore etmek için bir yapı oluşturduk.

Couchbase Metadata Yedekleme Mimarimiz

Bu yapıda, ilk olarak Couchbase’in sunmuş olduğu endpointler üzerinden veriler Powershell kullanılarak GET isteği ile elde edilmiştir. Sonrasında, Powershell içerisinde veriler SQL Server üzerindeki bir veritabanında bulunan tabloya bu veriler INSERT olacak şekilde formatlanmıştır. Bu işlemden sonra yine Powershell ile formatlanan veriler veritabanına kaydedilmiştir. Bu işlem günlük olarak yapılmaktadır ve her gün bir önceki güne ait kayıtları temizlemektedir.

Kullanıcı ve index iskeletlerini toplayıp parse ederek veritabanına kayıt eden Powershell örneğini aşağıda bulayanibilirsiniz.

Ancak yine de, fonksiyonun bir kısmını burada incelemek adına burada da bazı kısımlarını yazmakta fayda var.

function insertIndexDefintionstoDb {
param (
[Parameter(ValueFromPipeline = $true)]
[string]
$listPath
)
$hostListFromServer = Get-Content -Path $listPath

# Truncate Database Table
Write-host "Clean Table"
Invoke-DbaQuery -SqlInstance "sql_sunucu_ismi" -Database CouchbaseMeta -Query "DELETE FROM IndexDefinitions"

Write-host "Cleaned Table"
foreach ($singleNode in $hostListFromServer) {
$nodeName = $singleNode.ToString()
#$nodeName
[Uri]$urlForNodeInfo = "http://" + $nodeName + ":9102/getIndexStatement"
[Uri]$urlForBucketInfo = "http://" + $nodeName + ":8091/pools/default/buckets"
[Uri]$urlForUserInfo = "http://" + $nodeName + ":8091/settings/rbac/users"
#$urlForNodeInfo
try {
$getContentofNode = Invoke-WebRequest -Method Get -Uri $urlForNodeInfo -Headers @{"Authorization" = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("kullanıcı_ismi:şifre")); "Content-Type" = "application/json" } -UseBasicParsing
$getBucketsofNode = Invoke-WebRequest -Method Get -Uri $urlForBucketInfo -Headers @{"Authorization" = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("kullanıcı_ismi:şifre")); "Content-Type" = "application/json" } -UseBasicParsing
$getClusterUser = Invoke-WebRequest -Method Get -Uri $urlForUserInfo -Headers @{"Authorization" = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("kullanıcı_ismi:şifre")); "Content-Type" = "application/json" } -UseBasicParsing

$indexList = $getContentofNode.Content | ConvertFrom-Json
$bucketList = $getBucketsofNode.Content | ConvertFrom-Json
$userList = $getClusterUser.Content | ConvertFrom-Json
foreach ($index in $indexList) {
# Prepare Bucket List for New Record
$bucketsForRecors = ""
foreach ($bucket in $bucketList) {
$bucketsForRecors += $bucket.name + ','
}
$bucketsForRecors = $bucketsForRecors.substring(0, $bucketsForRecors.length - 1)
# Prepapre Bucket List Tasks is Done

# Set Fields of Database Records
$bucketsForRecors
$indexDefinition = $index
$indexNodeIP = $nodeName
# Insert New Record to Database
Invoke-DbaQuery -SqlInstance "sql_sunucu_ismi" -Database CouchbaseMeta -Query "INSERT INTO dbo.IndexDefinitions(buckets,definitions,nodeaddress) VALUES(@buckets,@definitions,@nodeaddress)" -SqlParameters @{ buckets = $bucketsForRecors; definitions=$indexDefinition ;nodeaddress= $indexNodeIP}
}

}
catch {
Write-Host "Failed for host: " $nodeName
}
finally {
}


}
}

Bu fonksiyonda sırası ile aşağıdaki işlemler yapılmaktadır.

  • Eski kayıtlar SQL Server tablosundan silinir.
  • Sunucuların endpoint URL’leri oluşturulur.
  • Endpointler üzerinden elde edilen bilgilerden index tanımları,bucket isimleri ve sunucu adresleri ile ilgili veriler convert edilir.
  • Convert edilen veriler metadata veritabanına yazılır ve yedeklenir.

Bu süreç, bizde periyodik olarak çalışmakta ve veritabanına kayıtlarımızı yazıyoruz. Daha sonrasında, veritabanından kayıtlara baktığımızda bu şekilde kayıtların güncellediğini görürüz.

Bu çalışma ve geliştirdiğimiz çözüm sayesinde elde ettiğimiz kazanımlar aşağıdaki gibidir.

  • Kullanıcı ya da index kayıplarında restore gereken durumlarda tekrardan recover etmek için gerekli süreyi minimize ettik sadece sorun yaşanan kullanıcı ya da index’in restore süresi kadar bir işlem süremiz oldu. Önceki versiyonda restore gereken durumlarda tüm veriyi restore etmemiz gerekiyordu.
  • Uygulama ekiplerinin ya da son kullanıcıların şifre dışındaki kullanıcı bilgileri ve yetki matrisleri bu şekilde servis edilmiş oldu.
  • Kullanıcı ya da index seviyesinde problem olmaksızın, uygulama ekipleri için gereken değişiklikler için yine buradan alacakları iskelet bilgileri ile bu nesneleri oluşturabilmeleri sağlandı.

Sevgiler,

Demir.

--

--

No responses yet