Veri Merkezimizi Yalnızca 8 Günde ve (Neredeyse) Sıfır Kesintiyle Nasıl Taşıdık?

Yönetici Özeti;
Müşterilerimizin hem public hem de local ip’leri sabit kalacak ve herhangi bir veri kaybı olmayacak şekilde, high-available cluster şeklinde tasarlanmış yapılar için SIFIR dakika, bu şekilde tasarlanmamış yapılar için azami 8 dakikalık kesinti ile veri merkezleri arasında yüzlerce sanal sunucuyu başarıyla nasıl taşıdık.

İlk servis noktamız IST1 kodlu veri merkezimizdeki servislerimizi, IST5 kodlu yeni veri merkezimize taşıdık.

Temel hedefimiz, hem müşterilerimizin sistemlerinde hem de kendi sistemlerimizde, WAN ve Local IP adresleri ile ilgili bir değişiklik yapmadan, kesinti ve veri kaybının yaşanmadığı pürüzsüz bir göç gerçekleştirmekti.

Peki bunu nasıl başardık?

TTEN, özgür yazılım ve open-source projelerin aşığı bir ekipten oluşuyor. Bu göçü gerçekleştirmemizi sağlayan ve halihazırda Disaster Recovery hizmetimizin de temelini oluşturan CEPH’in temel nimetlerinden faydalandık.

Kullandığımız altyapı bileşenleri için TL;DR:
1. CEPH
2. KVM
3. VXLAN

Bu dokümanda, altyapı bileşenlerinden veri replikasyon yöntemlerine, VXLAN/IPsec tünellerinden BGP anonslarına kadar, -meraklıları için- faydalanması umuduyla ayrıntılarını paylaşacağız.

IST1 kodlu veri merkezimizin çetelesi kısaca:

  1. Toplam 32 KVM hypervisor 

  2. Her bir hypervisor üzerinde 8’er adet olmak üzere toplam 256 adet NVMe disk

  3. 256 adet OSD üzerinde çalışmakta olan 3 adet CEPH Pool

  4. Ceph Pool’lar üzerinde bulunan 450 TiB veri (3 replica x 150 TiB efektif)

  5. Yüzlerce VM (web sunucusu, veri tabanı kümeleri, firewall sanal sunucuları, vb.)

Tüm bu sistemi 8 gün gibi kısa bir sürede yeni lokasyonumuza taşımayı hedef tahtamıza koyduktan sonra, zaman baskısının nasıl bir his olduğunu kariyerleri boyunca defalarca deneyimlemiş bir ekip ile ilk günümüzün tamamını planlamaya ayırdık ve uçuş planımızı oluşturduk. Sürecin hangi adımında ne yapılacağına dair fikir birliğine vararak operasyonumuza başladık.

Operasyonun ikinci gününde, kendimizi veri merkezine kapattık ve çoğunlukla fiziksel efor gerektiren kurulumları gerçekleştirdik. IST5 veri merkezinde yeni backbone router, switch ve hypervisor’larımızı devreye aldık. Bu yeni altyapı, başlangıçta planlandığı gibi ufak bir küme olarak hayatına başladı.

Geçiş sürecinde internet prefix’lerimizin her iki veri merkezinde de çalışabiliyor olması temel zorunluluk olduğundan IST5’te altyapının devreye alınmasıyla birlikte ilk iş olarak VXLAN yapılandırılmasını gerçekleştirdik.

İnternet prefix’lerimizin bulunduğu VLAN’ımızı internet service sağlayacılarımızın (İSS) desteği ile VXLAN şeklinde uzatıldı.

İnternet trafiğini taşıyan VLAN’ımızın, VXLAN ile uzatılması ile birlikte olası MTU(Maximum Transmission Unit) size sorunlarının yaşanmaması için bu kısmı İSS’lerimizin cihazları üzerinden gerçekleştirilmesini sağladık.

Böylece IP prefix’lerimizi hem IST1 hem de IST5 veri merkezlerimizde aynı anda kullanabilir duruma geldik.

TTEN’in sağlamakta olduğu Sanal Veri Merkezi (SVM) - Virtual Datacenter (VDC) hizmeti ve network katmanı topolojisi sırasıyla:

  1. Her VDC ürünü sanal bir firewall içeriyor.

  2. Firewall WAN bacağında, müşteri ihtiyacı kadar WAN IP adresi bulunuyor.

  3. Firewall LAN bacağı ise VDC’ye özel VLAN bağlı durumda bulunuyor.

  4. Müşterilerimiz, IP NAT ihtiyaçlarını TTEN’in Core Panel’ini kullanarak gerçekleştiriyor.

  5. IP prefix’lerimizin BGP anonslarını /24 olarak yapılıyor.

  6. Müşterilerimizin WAN IP ihtiyaçları, anons edilmekte olan prefix’ler içerisinden seçilen IP adreslerinin müşterilerimizin firewall’larına tanımlanması ile karşılanıyor.

Böylece ilk VDC göçü için hazır duruma geldik ve ilk testlerimize başladık. Başarılı geçen testler sonrasında göç operasyonunu devreye aldık.

Göç için planladığımız adımlar şu şekilde idi:

1. Göçü gerçekleştirilecek VDC ürününe ait sanal sunucuların sanal disklerini seçerek CEPH’in RBD Mirror deamon’ı ile IST1 lokasyonundan IST5’e mirror edilmesini sağlamak.


2. Snapshot mirroring schedule’larını oluşturmak.


3. İlk senkronizasyon sonrası, oluşan fark verilerininin 5 dakikada bir tekrar senkron edilmesini beklemek.

4. Tüm verinin aktarılmasının ardından, fark verilerinin de 5 dakikalık süreç içerisinde aktarılabildiğine emin olduğumuz anda, müşterilerimizden 10 dakikalık bir kesinti için zaman aralığı talebinde bulunmak.

5. VDC’ye ait tüm sanal sunucuların kontrollü bir şekilde power-off etmek.

6. Bir sonraki rbd-mirror işlemi ile tüm fark verisinin aktarılmasını beklemek.

rbd mirror pool status IST1-CEPH1-RBD2 --verbose


7. Fark verisinin aktarımı sonrasında VM konfigürasyon dosyalarını senkron etmek.

8. VDC’yi IST5’te aktif hale getirmek

“rbd mirror pool status IST1-CEPH1-RBD2 --verbose“ çıktısı, insan gözü ile okumaya çok müsait değil. Bunu, ihtiyaç duyduğumuz haliyle parse ederek, CSV formatına çevirmek ve her dakika başı yenilenen bir spreadsheet’e çevirerek okumayı kolaylaştırmak için basit bir bash script geliştirdik:

DIRECTORY="/tmp/ceph-scripts"

rbd mirror pool status IST1-CEPH2-RBD1 --verbose > $DIRECTORY/mirror-status.txt
cat $DIRECTORY/mirror-status.txt | grep "vm-.*-disk-.*" | sed 's/://g' > $DIRECTORY/mirror-disk-list.txt
cat $DIRECTORY/mirror-status.txt |grep -- "-state-" |sed 's/://g' >> $DIRECTORY/mirror-disk-list.txt

for DISK in $(cat $DIRECTORY/mirror-disk-list.txt)
do
	VMID=$(echo $DISK | awk -F "-" '{print $2}')
	VMNAME=$(cat /root/vm-names.db | grep $VMID | awk -F "," '{print $2}')
	DISK_SIZE=$(cat /root/disk-size.db | grep $DISK | awk -F "," '{print $2}')
	cat $DIRECTORY/mirror-status.txt | grep $DISK -A 3 | grep "description:" | sed 's/  description: replaying, //g' | jq > $DIRECTORY/$DISK.jq
	bytes_per_second=$(cat $DIRECTORY/$DISK.jq | jq .bytes_per_second)
	bytes_per_snapshot=$(cat $DIRECTORY/$DISK.jq | jq .bytes_per_snapshot)
	last_snapshot_bytes=$(cat $DIRECTORY/$DISK.jq | jq .last_snapshot_bytes)
	last_snapshot_sync_seconds=$(cat $DIRECTORY/$DISK.jq | jq .last_snapshot_sync_seconds)
	local_snapshot_timestamp=$(cat $DIRECTORY/$DISK.jq | jq -r .local_snapshot_timestamp)
	if [ "$local_snapshot_timestamp" = "null" ] || [ -z "$local_snapshot_timestamp" ]; then
    	local_snapshot_timestamp_hr="NULL"
	else
    	local_snapshot_timestamp_hr=$(date -d @$local_snapshot_timestamp +"%Y-%m-%d %H:%M:%S")
	fi
	remote_snapshot_timestamp=$(cat $DIRECTORY/$DISK.jq | jq -r .remote_snapshot_timestamp)
	if [ "$remote_snapshot_timestamp" = "null" ] || [ -z "$remote_snapshot_timestamp" ]; then
    	remote_snapshot_timestamp_hr="NULL"
	else
    	remote_snapshot_timestamp_hr=$(date -d @$remote_snapshot_timestamp +"%Y-%m-%d %H:%M:%S")
	fi
	replay_state=$(cat $DIRECTORY/$DISK.jq | jq .replay_state)
	seconds_until_synced=$(cat $DIRECTORY/$DISK.jq | jq .seconds_until_synced)
	syncing_percent=$(cat $DIRECTORY/$DISK.jq | jq .syncing_percent)
	syncing_snapshot_timestamp=$(cat $DIRECTORY/$DISK.jq | jq .syncing_snapshot_timestamp)

	if [ "$local_snapshot_timestamp_hr" != "NULL" ]; then
    	local_epoch=$(date -d "$local_snapshot_timestamp_hr" +%s)
    	current_epoch=$(date +%s)
    	diff_minutes=$(( (current_epoch - local_epoch) / 60 ))
	else
    	diff_minutes="NULL"
	fi

	if [ "$local_snapshot_timestamp_hr" != "NULL" ] && [ "$remote_snapshot_timestamp_hr" != "NULL" ]; then
    	local_epoch=$(date -d "$local_snapshot_timestamp_hr" +%s)
    	remote_epoch=$(date -d "$remote_snapshot_timestamp_hr" +%s)
    	diff_seconds=$((remote_epoch - local_epoch))
    	time_diff=$(echo "$diff_seconds / 3600" | bc -l | awk '{printf "%.1f", $0}')
	else
    	time_diff="NULL"
	fi

	echo $VMID,$VMNAME ,$DISK,$DISK_SIZE,$time_diff,$diff_minutes,$syncing_percent,$local_snapshot_timestamp_hr,$remote_snapshot_timestamp_hr

done > $DIRECTORY/ceph-csv-unsorted.txt
LASTRUN=`date +"%Y-%m-%d %H:%M:%S"`
cat $DIRECTORY/ceph-csv-unsorted.txt| sort -t, -k2 > $DIRECTORY/ceph-csv-main.txt

echo VM_ID,VM_NAME $LASTRUN,DISK_ID,DISK_SIZE,TIME_DIFF,TIME_TO_NOW,PERCENTAGE,LOCAL_SNAP_TIME,REMOTE_SNAP_TIME > $DIRECTORY/ceph-sync-status.csv
cat $DIRECTORY/ceph-csv-main.txt >> $DIRECTORY


Google Spreadsheets’in App-Script özelliğini kullanarak, crontab’ler ile oluşturulan bu CSV dosyasının her dakika başında güncellenmesini sağladık.

function importCSVFromWeb() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
 var csvUrl = "https://secret/ceph-sync-status.csv";

 var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
 var csvData = Utilities.parseCsv(csvContent);
  sheet.clear();
 sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}

function refreshDataEveryMinute() {
 ScriptApp.newTrigger("importCSVFromWeb")
   .timeBased()
   .everyMinutes(1)
   .create();
}

Müşterilerimizin VDC ürünleri, IST1 veri merkezinde kapalı hale gelip, IST5 veri merkezinde aktif edildikçe, IST1 lokasyonundaki ihtiyaç duyulan kaynak giderek azalmaya başladı.

IST1’den 10 adet hipervizörü devreden çıkarabileceğimiz kadar sanal sunucuyu IST5’e aktarmamızın ardından, ilgili hipervizörler üzerinde yer alan OSD’leri devre dışı bıraktık.

Bu aşamada yapılması gereken sabırlı bir bekleyişti.

CEPH Placement Group’larının Crush Map’e göre rebalance işlemleri tamamlandıktan sonra, IST1 veri merkezimizden ilgili hipervizörleri teslim aldık ve IST5 veri merkezimizde, yeni hypervisor ve CEPH kümemizin altında çalışacak şekilde yapılandırdık.

Her bir fiziksel işlem sonrasında (eski kümeden hipervizör çıkarılması, yeni kümeye hipervizör eklenmesi) sabırlı bekleyişlerimizi sürdürmemiz gerekiyordu.

Fiziksel taşıma süreçleri için IST1 veri merkezini toplamda 4 kere ziyaret etmemiz gerekti.

Son VDC göçü tamamlanana dek tüm internet prefix’lerimizin IST1 veri merkezimizinden BGP anonsu devam etti. Göçün ardından IST1’in BGP anonsu kapatıldı ve IST5 üzerinden aynı bloklar anons edilmeye başlandı. Anonsun IST1’den kesilerek IST5’ten yapılması için 1 dakikayı bulmayan bir kesinti daha gerekti.

Geçiş sürecinde, HA Cluster ( High Availability - Yüksek Erişilebilirlik) yapıları bulunan müşteri sistemlerinde SIFIR kesinti ile başarılı geçişler mümkün oldu.

Örnek olarak Percona XtraDB Cluster’ı olan müşterilerimizin VLAN’larını da, aynı internet VLAN’ı taşıdığımız gibi VXLAN ile hem IST1 hem de IST5 lokasyonlarında çalıştırdık.

Clustered yapılarda topyekün tek seferde tüm VDC sanal sunucularının göçü yerine, müşterilerimiz ile koordineli bir şekilde, kontrollü olarak VM bazlı göçü gerçekleştirdik ve bu süreçte sıfır kesinti tecrübe eden müşterilerimizde oldu.

Ancak kesinti süresi en uzun olan bir VDC’nin göç operasyonunu düşündüğümüzde, toplamda maksimum 8 dakikalık bir operasyon kesintisi ve 1 dakikalık final BGP anonsunun değişimiyle birlikte gelen kesinti ile tüm süreci müşterilerimize 10 dakikanın altında bir kesinti yaşatarak tamamladık.

Bütün bu işlemleri, 8 gün gibi kısa bir sürede gerçekleştirdik.

Hedeflediğimiz gibi tüm müşterilerimizin WAN ve Local IP adresleri değişikliğe uğramadan göç işlemleri tamamlandı.