sharding, replication နဲ့ multi-region database
multi-region database ဆိုတာ data operation တွေကို လက်ခံမယ့် database server တွေကို region တခုတည်းမှာ မထားပဲ region ၂ ခု ၃ ခုဖြန့်ထားတာကို ခေါ်တယ်။ multi-region ဖြစ်ရတဲ့ design နှစ်မျိုးရှိတယ်။ ပထမတမျိုးက shard လုပ်လို့ multi-region ဖြစ်တာ။ ဒုတိယတမျိုးက data replication လုပ်ထားတာ။ ဒီ design နှစ်မျိုးကို မဖြစ်မနေ တွဲသုံးရမယ်လို့တော့ မရှိပေမယ့် လက်တွေ့မှာ performance နဲ့ reliability အတွက် sharding နဲ့ replication ကိုပေါင်းသုံးကြတယ်။
sharding လုပ်တယ်ဆိုတာက database ထဲက record တွေ document ကို server ခွဲသိမ်းတာကိုခေါ်တယ်။ အလွယ်ဆုံးက primary key အပေါ်မူတည်ပြီး ခွဲတာ ဆိုပေမယ့် တကယ်တမ်း ကိုယ့် application ရဲ့ nature ကပဲ အဓိကကျတယ်။ ဥပမာ id 1-1000 ကို ဂျပန်မှာရှိတဲ့ server 1 မှာသိမ်းမယ်။ id 1001-2000 ကိုအမေရိကက server 2 မှာသိမ်းမယ်။ ဒါဆိုရင် ဒါက id အပေါ် မူတည်ပြီး shard တာဖြစ်သွားပြီ။ ဒါမှမဟုတ် id ဘယ်လောက်ဖြစ်ဖြစ် acc ဖွင့်တဲ့ region အပေါ် မူတည်ပြီး shard မယ်ဆိုရင် region = "jp" တွေကို server 1 မှာထားမယ်။ region = "us" တွေကိုတော့ server 2 မှာထားမယ်။ ဒါဆို id ဘယ်လောက်ဖြစ်နေနေ acc ရဲ့ region အပေါ် မူတည်ပြီး ဘယ် server ပေါ် data ရောက်မလဲ အဆုံးအဖြတ်ပေးသွားမယ်။ ဘယ် key ကိုသုံးပြီး sharding လုပ်မလဲဆိုတဲ့ option ကိုတော့ database တွေက ပေးထားရတယ်။ sharding လုပ်တာကို partitioning လို့လည်းခေါ်တယ်။ shard လိုက်တဲ့ အစိတ်အပိုင်းတခုစီကို database software အပေါ် မူတည်ပြီး shard, partition, region, segment, tablet, bucket စသဖြင့် ခေါ်ကြတယ်။
sharding ကပြောရရင် အဓိက performance အတွက်ပေါ့။ ဂျပန်မှာရှိတဲ့ user တွေက japan region မှာရှိတဲ့ backend ကတဆင့် database ကို access လုပ်မယ်ဆိုရင် သူတို့ရဲ့ region က "jp" ဖြစ်တဲ့အတွက် japan region က database ကိုသုံးလို့ရမယ်။ ဒီတော့ latency ခပ်နည်းနည်းပဲရှိမယ်။ အမေရိကန်နိုင်ငံသားတယောက် (region = "us") ဂျပန်လာလည်တုန်း application ကိုသုံးတာဆိုရင်တော့ traffic က Global Server Load Balancer (GSLB) နဲ့ Anycast ကြောင့် edge server ကတဆင့် အနီးဆုံးမှာရှိတဲ့ japan က backend ကိုပဲရောက်သွားမယ်။ ဒါပေမယ့် japanese backend က US က database ဆီသွားရနိုင်တယ်။ traffic က continent ဖြတ်ပြီး သွားရတဲ့အတွက် latency ပိုကြီးမယ်။ အဲဒီအကြောင်း အောက်မှာ ဆက်ပြောမယ်။
နောက်တမျိုးက replication ကြောင့် multi-region ဖြစ်ရတာ။ ဒီပုံစံကတော့ data တခုကို ကော်ပီ ၂ ခု ၃ ခု ထားတာမျိုးပေါ့။ ကော်ပီထားဖို့ပဲဆိုရင် backup အဆက်မပြတ် ယူနေရုံနဲ့ မရဘူးလား၊ ဘာလို့ database server လိုက်ကြီး ထားဖို့လိုရတာလဲဆိုရင် တချက်က ခပ်မြန်မြန် failover လုပ်နိုင်ဖို့၊ နောက်တချက်က server တွေက traffic ကိုခွဲ serve ပြီး performance gain ရချင်လို့ဖြစ်တယ်။ ဥပမာ database server တွေကို leader နဲ့ follower (ဒါမှမဟုတ် primary နဲ့ replica) ဆိုပြီး ခွဲထားလို့ရတယ်။ leader/primary ကပဲ write ops တွေကို လက်ခံမယ်၊ follower/replica တွေကတော့ read traffic အတွက်ပဲဆိုတာမျိုး CQRS ရဲ့အခြေခံပုံစံ (separation of endpoints) ပေါ့။ ဒီလို single leader ပုံစံအပြင် ဘယ် node ကဖြစ်ဖြစ် write operation တွေကို လက်ခံနိုင်တဲ့ multi-leader ဒါမှမဟုတ် consensus သုံးပြီး quorum ပြည့်အောင် ရေးရတဲ့ leaderless ပုံစံတွေလည်းရှိတယ်။ ဒါပေမယ့် multi-leader နဲ့ leaderless ပုံစံတွေက strongly consistent မဖြစ်နိုင်၊ ဖြစ်ဖို့ခက်တဲ့အတွက် CAP Theorem မှာ CP ဖြစ်ပြီး performance လည်းကောင်းရမယ့် system တွေက single leader replication ကိုပဲရွေးကြတယ်။
နောက်တခုက replication လုပ်တဲ့အခါမှာ leader ဆီက change log တွေကို follower တွေက sync ယူမလား async ယူမလားဆိုတာလည်း ဆုံးဖြတ်ရမယ်။ sync ဆိုရင် Network RTT ကြောင့် latency ပိုများသွားနိုင်ပေမယ့် reliability အာမခံချက် ပိုရှိမယ်။ async ကတော့ performance ပိုကောင်းမယ်။ ဒါပေမယ့် change log တွေ stream နေတုန်း primary database server ကျသွားလို့ replica ဆီ failover လုပ်လိုက်တဲ့အခါ ကြားထဲမှာ record တွေပြတ်ကျန်ခဲ့နိုင်တယ်။ အဲတော့ reliability အာမခံချက်နည်းမယ်ပေါ့။
ကပ်သပ်ပြောရင်တော့ sharding ရော replication ရောက မဖြစ်မနေ multi-region ဖြစ်ဖို့မလိုပါဘူး။ နှစ်ခုလုံးက region တခုတည်း ဒါမှမဟုတ် Data Center တခုတည်းမှာတောင် လုပ်လို့ရတဲ့ concept တွေပဲ။ ဒါပေမယ့် ဒီကနေ performance အပြင် reliability ကိုပါ ရဖို့အတွက် အတိုင်းအတာအထိ geographically dispersed ဖြစ်အောင် database server တွေကို ဖြန့်ကျက်ထားတာဖြစ်တယ်။ ဒီတော့ မတော်တဆ ကပ်ဘေး အကြီးအကျယ်ဖြစ်လို့ region တခုလုံးမှာရှိတဲ့ Data Center တွေအကုန်ကျသွားရင်တောင်မှ ကိုယ့် system ရပ်မသွားဘူးပေါ့လေ။ ဒီတော့ ကိုယ့် system က business critical data တွေကို သိမ်းဖို့လိုအပ်ပြီး အရမ်းလည်း throughput များတဲ့ အနေအထားဖြစ်လာတဲ့အခါ partitioning ရော replication ပါလုပ်ထားဖို့ စဥ်းစားသင့်ပြီ။
system အတွက် ယူဆချက်တချို့ကို အရင်ပြောမယ်။ business က ဂျပန်၊ အမေရိကနဲ့ ဗြိတိန်နိုင်ငံတွေမှာ အဓိကအခြေစိုက်တာဖြစ်လို့ application ရဲ့ user တွေက အဲဒီ ၃ နိုင်ငံမှာ အများဆုံးနေကြတယ် ဆိုပါစို့။ latency အသက်သာဆုံးဖြစ်အောင် frontend က CDN ပေါ်မှာ၊ API backend ကိုတော့ GSLB နဲ့ Anycast သုံးပြီး AWS ရဲ့ US, UK နဲ့ Japan region တွေမှာ host ထားတယ်။ system ထဲက downstream processor တွေက database technology တခုထက်မက သုံးထားကြပြီး ACID transaction လိုအပ်တဲ့ critical data တွေသိမ်းဖို့အတွက်တော့ relational db ကိုသုံးထားတယ်။ အရေးကြီးဆုံးက strongly consistent ဖြစ်ဖို့နဲ့ regional downtime ရှိခဲ့ရင်တောင်မှ fault tolerant ဖြစ်ဖို့ပဲ။ performance ကလည်း p999 <500 ms အောက်ရှိရမယ်။
ဒီတော့ system အတွက် လိုအပ်တဲ့ correctness ရော၊ reliability ပါရရမယ့်အပြင် user တွေအတွက် performance ကိုလည်း မဆုံးရှုံးရစေဖို့အတွက် database system ကို region 3 ခုလုံးမှာ shard ထားမှဖြစ်မယ်။ ရှေ့မှာပြောခဲ့သလို region key အပေါ်မူတည်ပြီး shard လိုက်တာက မဆိုးလှတဲ့ baseline ပဲ။ ဒါဆို data တွေက region = "jp" အတွက် ဂျပန်မှာရှိမယ်။ region = "us" က အမေရိကမှာရှိပြီး region = "uk" က ဗြိတိန်မှာဖြစ်မယ်ပေါ့။ user တွေက write ops တွေမှာ local database ကိုတိုက်ရိုက်ချိတ်ရတဲ့အတွက် latency နည်းပြီး data ကလည်း strongly consistent လည်းဖြစ်သွားမယ်။ ဒါပေမယ့် ကိုယ့် acc ဖွင့်ခဲ့တဲ့ region မဟုတ်တဲ့ဒေသကို ရောက်နေရင်တော့ မူရင်း region က database ကိုသွားချိတ်ဖို့လိုတယ်။ အဲအခါကျ latency ရှိမယ်။
နောက် database တွေကို replication factor 3 ထားပြီး replicate လုပ်မယ်။ region တခုစီမှာ primary database ရယ်၊ နောက် AZ တခုမှာ သူ့ရဲ့ synchronous replica ရယ်ရှိမယ်။ write ops တခုက သူတို့နှစ်ခုလုံးဆီကနေ confirmed မှ ACK ဖြစ်မယ်။ AWS မှာ regional traffic ကပုံမှန် 1-2 ms range ထဲမှာရှိပြီး upper bound က 3-5 ms လောက်ရှိတဲ့အတွက် ဒါက မပြောပလောက်တဲ့ trade off လို့ဆိုနိုင်တယ်။ ဒီ regional database server နှစ်ခုအပြင် overall reliability အတွက်ရော၊ cross-region query တွေအတွက် performance ကိုစဥ်းစားပြီးတော့ပါ နောက်ထပ် async replica တလုံးကို တခြား region တခုမှာ ထပ်ထားမယ်။ ဂျပန်နဲ့ ဗြိတိန်အတွက်ဆိုရင် ဒါက အမေရိကမှာဖြစ်ပြီး အမေရိကအတွက်ဆိုရင် ဒါက ဂျပန်မှာဖြစ်မယ်။
read query တွေကို active-active ပုံစံ အနီးဆုံး regional database server ကနေ serve မယ်။ continent တွေဖြတ်ပြီး သွားရမယ့် asynchronous replication က lag ရှိမှာမို့လို့ change propagation ဖြစ်နေတုန်းခဏတော့ stale data နဲ့ကြုံရနိုင်တယ်။ ဒါကြောင့် cross-region key အတွက် query တွေကို critical နဲ့ non-critical ခွဲဖို့လိုလိမ့်မယ်။ critical ဖြစ်ရင် မူရင်း regional database ကနေ သွားဖတ်ပြီး critical မဖြစ်ဘူးဆို local database ကပဲ serve မယ်ပေါ့။
write ကတော့ အမြဲတမ်း active-passive ပဲ။ async replica က warm standby အနေနဲ့ failover အတွက် အသင့်ရှိနေမယ်။ ဒီတော့ region တခုလုံးက database နှစ်ခုလုံး ရုတ်တရက် crash သွားတဲ့အနေအထားမှာ async replica ဆီ failover လိုက်ရင် နောက်ဆုံး batch ထားတဲ့ change log တွေနဲ့ in-flight ထဲက change log တချို့ပဲ ဆုံးရှုံးရမယ်။ inter-continent RTT ဟာ 500 ms လောက်ရှိတာဖြစ်လို့ အဲဒီအခြေအနေမှာ RPO က <1 sec ပဲ။ ဒါပေမယ့် အဲဒီမတိုင်ခင်ကတည်းက replication lag ရှိနေခဲ့ရင်တော့ RPO က tens of seconds ဖြစ်သွားမှာပေါ့လေ။ ဒါကြောင့် ဒီအချက်ကို အဓိက monitor လုပ်နေဖို့လိုတယ်။ သူ့အတွက် on-call alert ဆင်ထားပြီး replication lag သိပ်ကြီးလာရင် soft warning လို့သတ်မှတ်ပြီး ဘာဆက်လုပ်ကြမယ်ဆိုတဲ့ runbook ရှိထားဖို့ လိုအပ်တယ်။
နောက် routing အတွက် စဥ်းစားရမယ်။ ဖြစ်နိုင်တဲ့ပုံစံ ၃ ခုအထဲက ပထမတခုက client တွေက partition နဲ့ health-aware ဖြစ်တဲ့ပုံစံ။ ဂျပန်မှာ host ထားတဲ့ backend က region = "*" တိုင်းအတွက် ဘယ် database endpoint ကိုလှမ်းချိတ်ရမလဲ သိတယ်။ ရိုးရှင်းတယ်။ scalable ဖြစ်တယ်။ ဒါပေမယ့် failover တွေမှာ တိုင်ပတ်လိမ့်မယ်။ ကိုယ်က ဥပမာ kubernetes သုံးထားရင် config တွေချက်ချင်းလိုက်ချိန်းပြီး rollout လုပ်ဖို့လိုတယ်။ မြန်ဖို့လိုတယ်။ ဖြစ်နိုင်ရင် စက္ကန့်ပိုင်းအတွင်း react လုပ်နိုင်ဖို့လိုတယ်။ ဒီအတွက် ESO လို poll-based controller တွေအစား MCSO လို event-driven secret controller တွေသုံးသင့်တယ်။ ဒါပေမယ့် ဒါသည် user တွေအတွက်တော့ a hard downtime ပဲ။
ဒုတိယ option က routing layer တခုထားတာ။ အဲဒီ layer က partition-aware ဖြစ်မယ်။ health-aware ဖြစ်မယ်။ backend တွေက ဘာရေးချင်ချင် ဖတ်ချင်ချင် regional endpoint တွေ ဥပမာ database.us.region.internal.com ဆိုတာမျိုးကို ချိတ်ရုံပဲ။ ဘယ် region ကိုသွားရမလဲဆိုတာ routing layer ကဆုံးဖြတ်ပေးသွားမယ်။ centralized ဖြစ်သွားတယ်။ rollout လုပ်စရာမလိုတဲ့အတွက် failover သိပ်မြန်တယ်။ downtime တော်တော်နည်းမယ်။ အဲဒီ layer မှာ metadata propagated ဖြစ်သွားတာနဲ့ရပြီ။ ဒါပေမယ့် တပြိုင်တည်းမှာပဲ ဒီ layer က HA ဖြစ်ဖို့လိုအပ်လာတယ်။ မဟုတ်ရင် Single Point of Failure (SPOF) ဖြစ်သွားမှာ။
နောက်ဆုံး option က ခုနပြောသလိုပဲ အနီးဆုံး database server ကိုလှမ်းချိတ်မယ်၊ ဒါပေမယ့် database server က internal routing လုပ်ပေးမယ်။ ဆိုလိုချင်တာက ရောက်လာတဲ့ write ops တွေကို partition မှန်အောင် forward လုပ်ပေးတာ၊ read query တွေမှာ strongly consistent read တွေအတွက် home server ကို forward လုပ်ပေးတာမျိုးပေါ့။ ဒီ option ကလည်း centralized ဖြစ်တယ်။ rollout လုပ်စရာမလိုတဲ့အတွက် failover အတော်မြန်မယ်။ တခုပဲ။ ကိုယ့် database technology ကဒါကို support ရမယ်။ commercial service တွေမှာတော့ internal routing ကိုအတိုင်းအတာတခုထိ ရကြပါတယ်။
primary database ကို network failure ကြောင့်ဖြစ်ဖြစ် ဘာကြောင့်ပဲဖြစ်ဖြစ် reach out လုပ်လို့မရတော့တဲ့အခါ တစက္ကန့်တခါ heartbeat 2 ခု miss ဖြစ်သွားတာနဲ့ ချက်ချင်း သူ့ရဲ့ hot standby ဆီကို failover လို့ရတယ်။ ဆိုတော့ RTO က single-digit seconds ပဲရှိပြီး RPO ကလုံးဝ zero ပဲ။ တကယ်လို့ region တခုလုံး ကျသွားတဲ့အနေအထားမှာဆိုရင် warm standby ဆီ failover လို့ရတယ်။ ဒီမှာလည်း RPO က tens of seconds ပဲ။ ဒါပေမယ့် RTO ကတော့ asynchronous nature ကြောင့် <0 ဖြစ်ဖို့ ကျိန်းသေပြီးသား။ တခုရှိတာက cross-region failover တွေမှာ RTO ကိုအရမ်း aggressive ဖြစ်ပြီး ဇွတ်မ push ဖို့ပဲ။ false positive ဖြစ်သွားခဲ့လို့ failback လုပ်ရရင် ဒါကလည်း operational cost ရှိတယ်။
အနှစ်ချုပ်ကတော့ အဓိကလိုအပ်ချက်က scalability ဖြစ်တယ်ဆိုရင် sharding-first သွားသင့်တယ်။ data ပမာဏကြီးလို့ single region ဒါမှမဟုတ် server တစ်လုံးနဲ့ မထိန်းနိုင်တဲ့အချိန်၊ data ကိုလည်း region အလိုက် ခွဲထားလို့ရတဲ့အချိန်တွေမှာ sharding ကကွက်တိပဲ။ ဒါပေမယ့် ဒီနေ့ ပြောသွားတဲ့ system မျိုးက geo-locality နဲ့ sharding ကထပ်တူကျသွားတဲ့ အနေအထားမျိုး ဖြစ်လို့သာ ရိုးရှင်းတယ် ထင်ရတာ။ တကယ်လို့ fine-grained sharding လိုချင်တယ်၊ cross-shard (single/multi-region) query တွေမှာ distributed transaction ရှိရမယ်ဆိုရင်တော့ သမရိုးကျ RDBMS တွေ (ဥပမာ MySQL, Postgresql) နဲ့ DIY sharding လုပ်မယ့်အစား distributed SQL datastore project တွေ (ဥပမာ CockroachDB, YugabyteDB, Google Spanner) ကိုကြည့်သင့်တယ်။ တဖက်မှာ ကိုယ့် system အတွက် availability နဲ့ disaster recovery ကအဓိကလိုအပ်ချက်တွေဖြစ်နေပြီး read-heavy workload မျိုးဆိုရင်တော့ replication-first သွားသင့်တယ်။ ဒါပေမယ့် write ops တွေမှာ single leader က bottleneck ဖြစ်ပြီး synchronous replication က latency tax ရှိမယ်။