Microservices တွေအတွက် Resilient Networking

Microservice Architecture မှာ monolithic တုန်းက ပေါင်းရေးခဲ့ကြတဲ့ feature (service) တွေကိုသီးခြား application တွေအဖြစ် ခွဲရေးကြတယ်။ ဒါကြောင့်လည်း microservice လို့ခေါ်တာပေါ့လေ။ Laravel project တခုပဲ ဆိုပါတော့။ သူ့ဆီမှာ UserController, CartController စသဖြင့်ရေးခဲ့ကြတဲ့ feature တွေကို Microservice နဲ့ဆိုရင် users service, cart service ဆိုပြီး သီးသန့် micro app လေးတွေအဖြစ် ခွဲထုတ်လိုက်ကြတယ်။

အဲဒီ micro app တွေက binary level မှာသီးခြားစီဖြစ်လို့ တခုနဲ့တခု programming language တွေ၊ framework တွေတူဖို့လည်း မလိုပါဘူး။ ဥပမာ users app ကို Python FastAPI သုံးပြီး cart service အတွက် JavaScript ExpressJS နဲ့ရေးလို့ရပါတယ်။ ဒီလိုပဲ။ warehouse, catalog နဲ့ throttler စသဖြင့်နောက်ထပ် app တွေကိုလည်း Rust, Go, C# အဆင်ပြေသလို ရွေးချယ်ခွင့်နိုင်တယ်။

ဒါက application layer မှာတင်မဟုတ်ပဲ data layer မှာပါခွဲတယ်။ ဆိုလိုချင်တာက users service မှာသူပိုင်တဲ့ MySQL Database server ရှိမယ်။ cart service ကလည်း သူ့ဟာသူ MySQL သုံးရင်သုံးမယ်။ Postgresql သုံးချင်သုံးမယ်။ ဒါမှမဟုတ် NoSQL က cart ပစ္စည်းတွေသိမ်းဖို့အတွက် ပိုပြီးသင့်တော်တယ်လို့ယူဆရင် MongoDB ဖြစ်ချင်လည်းဖြစ်မယ်ပေါ့။

ဒီလို data layer မှာပါခွဲထားဖို့မဖြစ်မနေ လိုအပ်တာ မဟုတ်ပေမယ့် ဒါက Microservice ရဲ့ best practice တခုအဖြစ်ရှိနေတယ်။ အခုလို data layer separation လုပ်လိုက်ခြင်းက database server update တွေ schema migration နောက် scaling နဲ့ sharding တွေလုပ်ရတဲ့အခါတခြား service တွေတိုက်ရိုက်ထိခိုက်မှာကို ထည့်စဥ်းစားစရာ မလိုတော့ဘူး။

ဒါပေမယ့် application တခုအလုပ်လုပ်နိုင်ဖို့ ဒီ့ပြင် domain ထဲက data တွေလိုအပ်တတ်တာက သဘာဝပဲ။ ဆိုပါတော့။ cart service က cart ထဲမှာ ဝိုင်၊ ဘီယာပါနေတဲ့အခါ check out ပေးမလုပ်ခင် စျေးဝယ်သူက အသက်ပြည့်ရဲ့လားလို့အရင်စစ်ချင်တယ်။ ဒါပေမယ့် စျေးဝယ်သူရဲ့ data က cart ရဲ့ database ထဲမရှိပါဘူး။ users database မှာပဲရှိပါတယ်။

ဒီတော့ cart service က users service ဆီကို network ပေါ်ကဆက်သွယ်ပြီး data တောင်းဖို့လိုလာပြီ။ application မှာ network ပါလာရင် ကျိန်းသေဖြစ်မှာတခုက error တက်တာလို့ပြောလို့ရတယ်။ microservice architecture သုံးထားတဲ့ system မျိုးမှာ click ကလေးတချက် API request လေးတခုက အနည်းဆုံး service လေးငါးခုလောက်ကို ဖြန့်ပြီး လုပ်သွားဖို့ လိုနိုင်တယ်။ ဒါကြောင့် microservice တွေရေးရင် ဒီအချက်ကို ထည့်တွက်ရတယ်။

ဘာကြောင့်လဲဆိုတော့ network communication က 100% reliable ဘယ်တော့မှ မဖြစ်ဘူး။ OSI 7 layer လို့ပြောကြတာမှာ အဲဒီ ၇ လွှာရဲ့ ဘယ် layer မှာမဆို တနည်းမဟုတ်တနည်း error တက်ပြီး service ၂ ခုကြားက communication ပျက်သွားနိုင်ချေက အများကြီး။

အရင် monolith မှာတော့ ဒီပြဿနာက သိပ်မသိသာခဲ့ဘူး။ ဘာလို့လဲဆိုရင် monolith မှာတုန်းက ဒီ့ပြင် domain တွေရဲ့ data လိုချင်ရင် database layer မှာတင် join တွေသုံးလိုက်လို့ရတယ်။ database server တခုတည်းရဲ့နောက်မှာ table တွေအကုန် ရှိတာမို့ data consistency နဲ့ပတ်သက်ပြီးတော့လည်း သိပ်ခေါင်းစားဖို့မလိုဘူး။

တကယ်လို့ data layer မှာ join မသုံးဘူး။ users service ကိုပဲ dependency အနေနဲ့ inject ထားလိုက်မယ်ဆိုလည်းရတာပဲ။ service ရဲ့ method တွေကို ခေါ်တာက local procedure (local function call) တွေဖြစ်လို့ သူ့မှာ network မပါဘူး။

ဆိုပါတော့။ Controller ထဲ userService: UserService တခုကို dependency အဖြစ် inject လုပ်ထားမယ်။ checkout မလုပ်ခင် userService.getUserByID(userID) လို့ခေါ်မယ်။ ရလာတဲ့ user ရဲ့အသက်ကိုစစ်ပြီးမှ ဆက်သွားမယ်ပေါ့။ အဲဒီတော့ monolith မှာ network ကြောင့်နဲ့ fail မယ်ဆို fail စရာနေရာ သိပ်များများစားစား မရှိဘူး။ external service လှမ်းခေါ်ရင်း fail တာ၊ database operation မှာ fail တာ၊ server နဲ့ client (React) ကြား fail တာ ဒါမျိုးတွေပဲရှိလိမ့်မယ်။

ဒါပေမယ့် microservice လို east-west traffic များလွန်းတဲ့ architecture မျိုးမှာဆိုရင်တော့ ခု​ပြောတဲ့ network failure ဖြစ်နိုင်ချေက အဆပေါင်းများစွာ ပိုများတာပေါ့။ ဒါကြောင့် Microservice တွေရေးတဲ့အခါ ဒီအချက်ကို ထည့်စဥ်းစားဖို့ လိုတယ်။ (east-west traffic ဆိုတာက service တွေအချင်းချင်းကြားက traffic မျိုးကိုခေါ်တာဖြစ်ပြီးတော့ သူနဲ့ဆန့်ကျင်ဖက်ဖြစ်တဲ့ north-south ဆိုတာကကျ ပြင်ပ destination တွေဆီ ဦးတည်တဲ့ traffic ကိုခေါ်တာဖြစ်တယ်)

Microservice တွေတည်ဆောက်တဲ့အခါ network ကြောင့်ဖြစ်တဲ့ ပြဿနာတွေကို လျှော့ချဖို့ အခြေခံကျတဲ့ concept လေးခုလိုအပ်တယ်။

နံပါတ် ၁ က client-side load balancing လို့ခေါ်တယ်။ သမရိုးကျ load balancer setup တွေမှာ ကျွန်တော်တို့ လုပ်ခဲ့ကြတာက server-side load balancing ဆိုတာပေါ့။ ဒီနေရာမှာ load balancer ဆိုတာ ဒီတိုင်း proxy software တခုပါပဲ။ ဒီ proxy software မှာ backend server တွေကို register သွားလုပ်ထားလို့ရတယ်။ client ဆီက request ရောက်လာတဲ့အခါ algorithm တမျိုးမျိုးသုံးပြီး register လုပ်ထားတဲ့ server တွေဆီကို အလှည့်ကျ request တွေဖြန့်ပေးမှာပေါ့။ အဲတော့ backend server တွေကြား မျှမျှတတဖြစ်အောင် ဖြန့်ပေးနိုင်မယ့် control ကကိုယ့်လက်ထဲမှာရှိတယ်။

client-side load balancing ဆိုတာက ပြောင်းပြန်။ ဒီပုံစံမှာ client ကသူဆက်သွယ်လို့ရမယ့် server စာရင်းကိုသိတယ်။ အဲဒီစာရင်းထဲက အကောင်းဆုံးဖြစ်မယ့် server (ဆိုပါတော့ latency အနည်းဆုံးဖြစ်တဲ့) backend ဆီ request ရွေးပို့နိုင်တယ်။ ဒီပုံစံရဲ့အဓိကအားနည်းချက်က centralized control မရှိတဲ့အတွက် client တွေက server တခုတည်းဆီပဲ request တွေစုပြုံပို့ပြီး အဲ backend server ကျသွားအောင် လုပ်နိုင်မယ်။ ဒါပေမယ့် အားသာချက်က client တယောက်ချင်းစီတိုင်းမှာ သူတို့အတွက် performance အကောင်းဆုံးဖြစ်မယ့် server ကိုရွေးခွင့်ရှိတယ်။

ဒီတော့ load balancing ကလည်း JavaEE Enterprise App တွေရဲ့ logging, compressing တို့လိုပဲ microservice တွေရဲ့ cross cutting (technical concern) တခုဖြစ်လာတယ်။ ကျွန်တော် ဆိုလိုချင်တာက Web Application တခု log တွေ ထုတ်တယ်ဆိုတာ business feature တခုမဟုတ်ဘူး။ စျေးရောင်းဖို့၊ checkout ဖို့၊ ဓာတ်ပုံတွေပြဖို့အတွက် ဘာ log မှမလိုဘူး။ ကျွန်တော်တို့ system ကောင်းကောင်းလည်ပတ်နိုင်အောင် maintain ဖို့၊ troubleshoot ဖို့၊ debug ဖို့အတွက်သာ log ထုတ်ကြတာ။ ဒီလိုမျိုး functionality တွေကို business မဟုတ်တဲ့ technical concern လို့ခေါ်ကြတယ်။

သမိုင်းအစဥ်အဆက်မှာ ကျွန်တော်တို့ဒီ technical concern တွေကို ဖြေရှင်းခဲ့တဲ့နည်းကတော့ reusable code တွေတခါတည်း ရေးထားလိုက်တာပါပဲ။ Microservice တွေမှာလည်း ဒီ pattern ကိုပဲထပ်သုံးတယ်။ Ribbon ဆိုတာက Netflix ရဲ့နာမည်ကြီး client-side load balancing လုပ်ဖို့သုံးတဲ့ Java library ပေါ့။

နံပါတ် ၂ concept က circuit breaking လို့ခေါ်တယ်။ အိမ်တွေမှာ breaker လေးတွေတပ်ကြတယ်။ သူအလုပ်လုပ်တဲ့ သဘောက လျှပ်စစ်ပစ္စည်းတခုခုမှာ အပူရှော့ဖြစ်ပြီး စီးရမယ့် လျှပ်စစ်က သူ့ပတ်လမ်းအတိုင်းမစီးပဲနဲ့ resistance နိမ့်တဲ့နေရာက ဖြတ်စီးနေပြီဆိုရင် breaker ကျပြီး current ကိုဖြတ်ပလိုက်တယ်။ အဲဒီတော့ အပူလွန်ကဲပြီး မီးလောင်တာတွေ မဖြစ်တော့ဘူးပေါ့။ Microservice တွေရေးတဲ့အခါမှာလည်း ခုလို breaker လေးတွေလိုအပ်တယ်။

cart service က users service ဆီကို HTTP GET request တခု လှမ်းပို့ပြီး data တောင်းတယ်။ REST api မှမဟုတ်ပါဘူး gRPC လည်းရတယ်။ ဒီနေရာမှာ protocol ကအရေးမကြီးဘူး အရေးကြီးတာက request fail သွားခဲ့ရင် ဘာလုပ်မှာလဲဆိုတာပါပဲ။ retry မယ် ထပ်ပို့မယ်ပေါ့ဗျာ ဟုတ်လား။ ဘယ်နှကြိမ်ကြိုးစားကြည့်မှာလဲ limit တခုရှိရပါမယ်။

၄ ကြိမ်​က limit မို့လို့ ၄ ကြိမ်ထိ ကြိုးစားကြည့်လို့မှမရသေးရင် breaker trip ရပါမယ်။ ဘာမှမထူးတာကို ဆက်ပို့နေရင် တဖက် server က အဲဒီပြုံ​​ရောက်လာတဲ့ request တွေကနေ ဘယ်လိုမှရုန်းမထွက်နိုင်အောင် ဖြစ်သွားလိမ့်မယ်။ အဲတော့ circuit break လိုက်ပြီဆိုပါတော့။ ဘယ်လောက်ထိကြာကြာ break မလဲဆိုတဲ့ ကြာချိန် ရှိရမယ်။ circuit timeout လို့ခေါ်တယ်။ အဲကာလကျော်ရင်တော့ request ပမာဏနည်းနည်း လွှတ်ပေးပြီး breaker ကိုပြန်ပိတ်ချသင့်မသင့် ဆုံးဖြတ်ရပါတယ်။

circuit breaker ကျနေတုန်းအချိန်မှာ cache ထဲရှိတာကိုပြန်ပေးတာဖြစ်ဖြစ် default value တခုခုပြန်ပေးတာဖြစ်ဖြစ်က ကောင်းတဲ့ practice ပါ။ အရေးကြီးတဲ့အချက်က ကိုယ်ခေါ်တဲ့ downstream service ကိုမရမှန်းသိသိနဲ့ ဆက်မခေါ်ဖို့ပါပဲ။ အဲဒါကြောင့် ဘယ် error code တွေကိုပဲ retry မယ်ဆိုတဲ့အချက်ကလည်း အရေးကြီးပါတယ်။ ဥပမာ HTTP status 500 ကို retry တာမျိုးကဖြစ်သင့်ပေမယ့် 404 ကြီးပြန် try ရမှာကျ သိပ်အဓိပ္ပါယ်မရှိတော့ဘူး။ circuit breaker အတွက် Netflix ရဲ့ Hystrix ဆိုတဲ့ Java library ကနာမည်ကြီးတယ်။

နံပါတ် ၃ သိထားရမယ့် concept က service discovery ပါ။ service discovery ဆိုတာက လမ်းညွှန်စာအုပ် တအုပ်လိုပဲ။ ဘယ် service ဘယ်မှာရှိတယ်ဆိုတဲ့ အချက်အလက်တွေကို query လို့ရမယ့် software တခုဖြစ်တယ်။

Monolith ခေတ်မှာတုန်းက traffic volume များလာတဲ့အခါ ပိုကြီးတဲ့ server တခုပေါ် ကိုယ့် application ကိုပြောင်း run ခိုင်းတဲ့နည်းနဲ့ ဖြေရှင်းခဲ့ကြတယ်။ နဂို CPU 4 core ကနေ 6 core ကိုတင်ပြီး memory 4GB ရှိရင် 8GB တိုးပြီး scale တဲ့ ဒီပုံစံကို vertical scaling လုပ်တယ်လို့ခေါ်တယ်။

သူရဲ့ပြောင်း​ပြန်ပုံစံ horizontal scaling လို့ခေါ်တဲ့ instance တွေပွားထုတ်ပြီး အလုပ်လုပ်စေတဲ့ပုံစံကိုလည်း သုံးခဲ့ကြပေမယ့် monolith ဆိုတာ single binary ဖြစ်တဲ့အတွက် လိုအပ်တဲ့ feature တခုကိုပဲ ကွက် scale လို့မရပဲ application တခုလုံးကို run ရတာဖြစ်လို့ startup နဲ့ teardown cost ရှိတယ်။ နောက်တချက်က session, cache စသဖြင့်တွေကို local မှာ သိမ်းထားတဲ့ stateful design အတွက် horizontal scaling ကအဆင်မပြေခဲ့ဘူး။

ဒါပေမယ့် microservice တွေနဲ့အတူ cloud native ဖြစ်ဖို့ ဦးစားပေးလာတဲ့ခေတ်မှာ stateless design ကိုပဲပိုသုံးလာကြတယ်။ horizontal scaling လုပ်ဖို့ ပိုကောင်းသွားစေပေမယ့် အားနည်းချက်က ip address တွေ port တွေအတည်တကျ မရှိတော့တာပါပဲ။ အခု users service အတွက် server 10 ခုရှိပေမယ့် ခဏနေ 5 ခုပဲ ကျန်တော့တာလည်း ဖြစ်နိုင်တယ်။

ဒါကို ဖြေရှင်းတဲ့နည်းက instance တွေကို လမ်းညွှန် server မှာ register လုပ်စေပြီး သူ့ကို ဆက်သွယ်ချင်တဲ့ upstream service တွေက ဒီလမ်းညွှန် server (service discovery) ဆီ​မှာ endpoint တွေသွား query လို့ရမယ်။ ဆိုပါတော့။ users service replica 4 ခုက service discovery နဲ့ register ထားတယ်ပေါ့။ cart အနေနဲ့ users service ကိုဆက်သွယ်ချင်တဲ့အခါ service discovery ဆီ query လိုက်ရင် endpoint ၄ ခုရလာလိမ့်မယ်။ ဒီသဘောပါပဲ။ Netflix ကထုတ်တဲ့ Eureka က service discovery အတွက် သုံးနိုင်တဲ့ Java library ဖြစ်တယ်။

နံပါတ် ၄ က API Gateway ဖြစ်တယ်။ microservice တခုစီက သူတို့ဆီရောက်လာမယ့် request တွေကို validate လုပ်ဖို့ လိုအပ်တယ်။ application layer (Layer 7) မှာ JWT သုံးပြီးစစ်တာဖြစ်စေ၊ transport layer (Layer 4) မှာ SSL/TLS နဲ့ပဲဖြစ်စေ request တွေရဲ့ identity ကို validate လုပ်နိုင်တယ်။ ဒါ့အပြင် throttling လို့ခေါ်တဲ့ rate limiting လည်းလုပ်ထားဖို့လိုတယ်။

ဒါတွေက inbound အတွက်ပဲမဟုတ်ပဲ outbound မှာလည်း ဒီလို check တွေလိုအပ်တယ်။ ကိုယ်ဆက်သွယ်မယ့် server ကစိတ်ချရလား identity စစ်ရပါမယ်။ rate limit ရှိတယ်ဆိုရင် သူ့ limit ကိုလိုက်နာပြီး ပိုမခေါ်မိဖို့ ဂရုစိုက်ရမယ်။ SSL termination လုပ်ဖို့ လိုအပ်မယ်။ ဒီအတွက် Zuul ဆိုတဲ့ API gateway ရှိတယ်။ သူလည်း Netflix ကရေးတဲ့ Java library ပါပဲ။

အဲဒီတော့ microservice တွေတိုင်းမှာ network failure တွေကိုလျှော့ချဖို့အတွက် ဒီလိုမျိုး library တွေသုံးရတယ်ဆိုရင် business နဲ့ technical concern အတွက် code တွေရောနေလိမ့်မယ်။ ဒီလို couple ဖြစ်နေခြင်းရဲ့ အားနည်းချက်က တပိုင်းပိုင်းမှာ အပြောင်းအလဲရှိတိုင်း အစအဆုံး ပြန်ပြီး build ရ၊ test ရ၊ release ရပါတယ်။ နောက်တခုက app အတွက် ကိုယ်သုံးထားတဲ့ language မှာ လိုချင်တဲ့ library မရှိဘူးဆိုရင်လည်း ခက်ပြန်တယ်။ ဥပမာ သုံးထားတာက C# ဖြစ်ပေမယ့် ကိုယ်သုံးချင်တဲ့ service discovery library က Java နဲ့ပဲရှိပြီး C# မှာမရှိဘူးဆိုတာမျိုး။

ဒီပြဿနာကို ဖြေရှင်းဖို့နည်းက အပေါ်မှာပြောခဲ့တဲ့ feature တွေကို သီးသန့် application တခုအဖြစ် ရေးပြီး main app နဲ့တွဲပေးလိုက်တာပါပဲ။ အဲဒီ application ကို proxy လို့ခေါ်ပြီး main app ရဲ့ traffic အဝင်အထွက်ကို proxy ကတဆင့် ဖြတ်သွားစေတယ်။ proxy app က ကျွန်တော်တို့ လိုအပ်တဲ့ service discovery, client side load balancing, circuit breaker, ratelimiting, တွေအပြင် system maintainence အတွက် အရေးကြီးတဲ့ service metric တွေဖြစ်တဲ့ request ပမာဏ ဘယ်လောက်ရှိလဲ။ ပျှမ်းမျှ latency ဘယ်လောက်ရှိလဲ။ request ဘယ်နှရာခိုင်နှုန်းလောက်က fail နေလဲ။ ဒါမျိုး metric တွေပါပေးနိုင်တယ်။

ဒီနေရာမှာ app ရဲ့ traffic က proxy ကတဆင့် ဘယ်လိုဖြတ်သွားလဲဆိုတာကို အကြမ်းဖျင်း နားလည်ထားစေချင်တယ်။ ဆိုပါတော့။ ကိုယ့် app ထဲကနေ HTTP GET request တခုပို့မယ်ပေါ့။ အဲ request ပို့ဖို့အတွက် HTTP client တခုလိုအပ်တယ်။ HTTP client က destination ဆီကို TCP socket တခုဖွင့်ပြီး HTTP request ကို byte တွေပြောင်း၊ နောက် write တို့ send တို့လို system call တွေသုံးပြီး OS ကတဆင့် TCP stream တခုရေးလိုက်တယ်။ ဒါပေမယ့် iptable တွေက အဲ traffic ကို proxy ဆီကို route ပေးဖို့ rule တွေထည့်ရေးထားရင် တကယ်တမ်းရောက်သွားတာက လိုချင်တဲ့ destination ဆီမဟုတ်ပဲ proxy ဖြစ်လိမ့်မယ်။

proxy က သူ့ဆီရောက်လာတဲ့ byte တွေကို ဖတ်ပြီး HTTP 1 လား 2 လား စသဖြင့်သိရအောင် protocol ဖမ်းပါတယ်။ ​ပြီးရင် destination endpoint တွေရအောင် service discovery ရဲ့ registry ကို query တယ်။ ရလာတဲ့ထဲက load balancing algorithm သုံးပြီး endpoint တခုရွေးမယ်။ circuit break ဖို့လိုအပ်ရင် break တယ်။ နောက် TLS handshake စပြီး TLS encryption နဲ့ decryption လုပ်တယ်။ retry ဖို့လိုရင် budget ရှိသလောက် try မယ်။ ပြန်ရလာတဲ့ response ကို main app က စောင့်နေတဲ့ port ဆီ TCP stream အဖြစ် ပြန်ပို့ပေးမယ်။ အကြမ်းဖျင်းက ဒါပါပဲ။

တကယ်တော့ အခုဖတ်လိုက်ရတာတွေက တခြားမဟုတ်ပါဘူး။ service mesh ရဲ့သဘောတရားတွေ ဖြစ်တယ်။ Istio, Linkerd စတဲ့ software တွေကဒီ feature တွေကိုလက်တွေ့လုပ်ပေးနိုင်တဲ့ software တွေပါပဲ။ Istio ကစစချင်းမှာ Google, IBM နဲ့ Lyft ကုမ္ပဏီ ၃ ခုပေါင်းရေးတဲ့ project ဖြစ်ပြီး အခုချိန်မှာ အသုံးအများဆုံး mesh project ဖြစ်တယ်။ Linkerd ကကျ သူနဲ့စာရင် အများကြီးပိုသေးတယ်။ lightweight လည်းဖြစ်တယ်။ ကျွန်တော်တော့ Linkerd ပိုသုံးပါတယ်။ ခုပြောသွားတဲ့ concept တွေကိုသာ နားလည်ပြီဆိုရင် Istio ဖြစ်ဖြစ် Linkerd ဖြစ်ဖြစ် လေ့လာဖို့ မခက်ခဲပါဘူးခင်ဗျာ။

Bonus: For Geeks

မေးသင့်တဲ့ မေးခွန်းတခုက proxy ဆိုတဲ့ Hop အပိုပါလာတဲ့အတွက် performance ဘယ်အတိုင်းအတာထိ ထိခိုက်နိုင်မလဲဆိုတာပါ။ TCP connection state ကို application container မှာရော၊ proxy container မှာပါထိန်းရဖို့ဖြစ်လာမယ်။ kernel buffer ၂ စုံစာလိုမယ်။ နှစ်ကြိမ် parse လုပ်ရမယ်။ Network stack ကိုနှစ်ခါဖြတ်ရမယ်။ လိုအပ်ရင် app နဲ့ proxy ကြား packet reassembly ပြန်လုပ်ရမယ်။ ဒါတွေအပြင် တခြား ကျန်တာတွေ ရှိသေးတယ်။ ဒီဟာတွေက latency ဖက်ကကြည့်ရင် request တခုကို ms 2-3 ဝန်းကျင်လောက်တော့ ပိုတိုးသွားစေမှာပေမယ့် ကောင်းတဲ့အချ​က်က kube-proxy ကတဆင့် nat လုပ်စရာမလိုပဲ by pass လို့ရသွားမယ်။ နောက်ပြီး proxy ရဲ့ performance ကိုလည်း baremetal နီးနီးရအောင် garbage collector မပါတဲ့ C, C++, Rust တို့လို system language တွေကို ရွေးချယ်သုံးသင့်တယ်။ Istio ရဲ့ proxy က Envoy မှာ C++ ကိုသုံးထားပြီး Linkerd က Rust သုံးထားပါတယ်။ proxy ရဲ့ Memory နဲ့ CPU usage ကိုမျှတအောင် ထိန်းနိုင်ဖို့အတွက် ရလာတဲ့ endpoint တွေကိုသင့်သလို cache ထားဖို့လည်းလိုမယ်။ Traffic နဲ့ Network Policy ပမာဏ သင့်တင့်ပြီး Pod 100 လောက်ရှိတဲ့ cluster မှာမှန်းခြေ vCPU 2-10 နဲ့ memory 2-8G လောက် သုံးရနိုင်တယ်လို့ တွက်ထားရမယ်။ Istio မှာတော့ Ambient Mesh ဆိုတာ daemon set တွေသုံးပြီး shared proxy သဘောနဲ့ resource usage ကိုလျှော့ချဖို့ ကြိုးစားလာတာတွေ့ရတယ်။ ဒါပေမယ့် ဒါက security ဖက်ကို အားနည်းသွားစေပြန်တယ်။