Performance အတွက် စဥ်းစားရမယ့် အဓိက ၁၁ ချက်
Web service တွေရေးတဲ့အခါ performance ဘယ်လောက်မြန်ဖို့လိုအပ်လဲလို့မေးရင် ကျွန်တော် ပုံမှန်ဖြေနေကျ အဖြေက response time 50 ms အောက်ဆိုရင် user ရဲ့အမြင်မှာ မြန်တဲ့ Website လို့ခံစားရတာ ဖြစ်တဲ့အတွက် 50-100 ms ထက်တော့ ပိုမကျော်သင့်ဘူးလို့ ဖြေဖြစ်တယ်။ ဒါပေမယ့် ဒီ 50-100 ms ဆိုတာ application မှာပဲတာဝန်ရှိတာမဟုတ်ဘူး။ application ဖက်က user ရဲ့ request တခုကို process မလုပ်ရသေးခင် လမ်းမှာ အဲဒီ request ဖြတ်ခဲ့ရတဲ့ အလွှာတွေ အများကြီးရှိတယ်။
လမ်းတလျှောက် ရေအောက် fibre ကြိုးတွေ နောက် router တွေကို အဆင့်ဆင့် ခုန်ရတယ်။ နောက် ရုံးတက်ရုံးဆင်းချိန်တွေ ကားပိတ်သလိုပဲ network ကြပ်တဲ့အချိန် congestion ဖြစ်တဲ့အချိန်တွေမှာ request တခုက ခါတိုင်းထက် လမ်းမှာအချိန်ပိုကုန်မှာပဲ။
ကျွန်တော်တို့ HTTP request တခုပို့ချင်တဲ့အခါ ဥပမာဆိုပါတော့ http.Get("some-url") လို့ run လိုက်ရင် ကျွန်တော်တို့ရဲ့ client library က OS ကို socket တခုလှမ်းဖွင့်ခိုင်းတယ်။ ပြီးရင် စောစောက request ကို byte sequence ချိန်းပစ်ပြီး OS ကိုလှမ်းရေးတယ်။ OS ပေါ်မှာ network driver ကအဲဒီ byte sequence တွေကို packet တွေအဖြစ် ပိုင်းပြီး internet ကွန်ယက်ကြီးကို ဖြတ်ပြီးပို့တယ်။ ပို့တဲ့အခါမှာ packet တိုင်း တဖက်က လက်ခံမယ့်သူဆီကို ရောက်ဖို့လိုအပ်တယ်၊ နည်းနည်းလေးမှ အမှားအယွင်းမခံဘူးဆိုတဲ့အခါကျ အချိန်းအချက်တွေလုပ်ရပြန် တယ်။
ဘာနဲ့တူလဲဆို delivery လာပို့သလိုပဲ။ ပစ္စည်းဘယ်နှခုလာပို့ဖို့ရှိတယ်။ တခုနဲ့တခု ဘယ်လောက်ခြားမယ်။ ပစ္စည်းတခုရဲ့ size ဘယ်လောက်ရှိမယ် မင်းသဘောတူလား ငါသဘောတူတယ်တွေ လုပ်ရတယ်။ TCP handshake ပေါ့။ နောက် ပို့နေရင်းနဲ့ကလည်း ပစ္စည်းမရဘူး၊ တခုပျောက်သွားတယ်ဆိုရင် ပြန်ပို့ဖို့ လုပ်ရတယ်။ ဒါတွေကလည်း အချိန်ကို ထပ်ကြာစေတာပဲ။ ပြီးတော့ ပို့ရမယ့်ပစ္စည်းကို စိတ်ချရတဲ့ နေရာ ပို့လိုက်မိတာ သေချာစေချင်တယ်။ လမ်းမှာ လူတွေဖွင့်ကြည့်မှာလည်း မကြိုက်ဘူးဆိုရင် certificate တွေ key တွေပါ အလဲအလှယ်လုပ်ပြီး data ကို encrypt လုပ်ပေးဖို့ ညှိရသေးတယ်။ SSL/TLS ပေါ့လေ။
နောက်ဆုံး တဖက်က လက်ခံမယ့်သူဆီ packet တွေအကုန် ရှောရှောရှူရှူ ရောက်သွားပြီ ဆိုပါတော့။ အဲ packet တွေကို encrypt လုပ်ထားရင် decrypt ပြန်လုပ်ဖို့လိုမယ်။ ဒါကို SSL termination လို့ခေါ်တယ်။ SSL termination လုပ်ပြီး ရလာမယ့် packet တွေကို အစီအစဥ်တကျပြန်စီ byte sequence တွေကို parse ပြီးမူရင်း request ဖြစ်အောင်တည်ဆောက်ရတယ်။
ဒါပေမယ့် Web system တွေရဲ့ security design အရဆိုရင် application server ကိုဘယ်တော့မှ ဒီလိုတိုက်ရိုက် expose မလုပ်ကြဘူး။ အဲဒီတော့ ကြားထဲ proxy တဆင့်ထပ်ခံသေးတယ်။ proxy ကလည်း Network proxy ဆိုရင် packet တွေရဲ့လာရာနဲ့ လားရာကိုပဲ စစ်တာ။ application proxy တွေဆိုရင် အပေါ်မှာ ပြောခဲ့သလို packet တွေကို deserialize လုပ်ပြီး ဘယ် endpoint လဲဆိုတာကိုပါစစ်တာ။ အဲသလို ကြည့်နိုင်ဖို့ cost ကမသေးဘူး။ CPU time ပေးရတယ်။
ပို့လိုက်တဲ့ request က ဒါတွေအကုန်ဖြတ်ပြီး နောက်ဆုံးကျမှ NodeJS တို့ Django တို့ Laravel တို့လို Web App တွေဆီရောက်တယ်။ အဲဒီတော့ website တခု လေးကန်ကန် ဖြစ်မနေဖို့ optimize လုပ်မယ်လို့တွေးရင် အခုပြောသွားတဲ့ အဆင့်တွေ အကုန်လုံးကို ထည့်စဥ်းစားဖို့လိုတယ်။
1) လမ်းတလျှောက် fibre ကွန်ယက်ကြီးကို ဖြတ်ပြီးလာရတဲ့အချိန်ကို တတ်နိုင်သမျှ တိုစေဖို့ user တွေနဲ့ သိပ်မဝေးတဲ့ဆီမှာ server ကိုထားရမယ်။ ဥပမာ user အများစုက မြန်မာမှာဆိုရင် server ကို အမေရိကမှာ သွားမထားရဘူး။
2) request တွေကို serialize နဲ့ deserialize လုပ်တဲ့အခါမှာ protobuf လိုမျိုး static ကိုသုံးရင် json ထက် 5 ဆလောက်ပိုမြန်မယ်။ နို့မို့ဆို payload ကြီးရင်ကြီးသလောက် 0.5 ms ကနေ 1 ms လောက်ထိကုန်တယ်။ အဲဒါကြောင့် မဖြစ်မနေ json သုံးဖို့လိုတယ်ဆိုရင်တောင် runtime reflection မပါမယ့်ပုံစံမျိုး compile time မှာကတည်းက static serializer ထုတ်ထားတာမျိုးဆို အများကြီး penalty လျော့မယ်။
3) Web page တခု load ဖို့ request တွေ တခုထက်မက ပို့ရမယ်ဆိုရင် အကုန်လုံးကို အပြိုင်ပို့တာက စုစုပေါင်း ကြာချိန်ကို သိသိသာသာ လျှော့ချပစ်နိုင်တယ်။ json over HTTP မှာ HTTP 1.1 ကိုသုံးထားတာဖြစ်လို့ request တွေအပြိုင်ပို့ချင်ရင် connection အသစ်တွေ ထပ်ဖွင့်ရလို့ အချိန်ပိုကုန်မယ်။ gRPC လို HTTP 2.0 နဲ့ဆိုရင်တော့ connection တကြောင်းတည်းပေါ်မှာပဲ အပြိုင်ပို့လို့ရတယ်။
4) static asset တွေဖြစ်တဲ့ ဓာတ်ပုံနဲ့ဗီဒီယိုတွေ client side JavaScript ဖိုင်တွေ cachable API response တွေကို အနီးဆုံး cache server ကနေ ပြန်ပေးနိုင်ဖို့ CDN သုံးရမယ်။
5) application နဲ့ infra ကြားထဲက proxy အရေအတွက်ကို ဂရုစိုက်ဖို့လိုတယ်။ ဥပမာ Load Balancer တွေ၊ Gateway တွေ၊ Multi Broker တွေ နောက်ပြီး Kubernetes ပေါ်ဆိုရင် source nat, sidecar စသဖြင့် ဒါမျိုးကြားက component တွေကိုလည်း ထည့်စဥ်းစားရမယ်။
6) application ကို lambda လိုဟာမျိုးသုံးထားရင် WASM လိုဟာမျိုး သုံးထားရင် ဒါမှမဟုတ် request ရောက်မှ app ကိုစ run မယ့်ဘယ်လို service မျိုးကိုမဆို သုံးထားခဲ့မိရင် ကျွန်တော်တို့ cold start လို့ခေါ်တဲ့ ကြာချိန်ကိုလည်းထည့်တွက်ဖို့လိုမယ်။
7) application က peer တွေခွဲပြီး အလုပ်လုပ်ရမယ်ဆိုရင် လုပ်ရမယ့်ယူနစ် (ဥပမာ Kubernetes Pod, EC2 instance) စတာတွေကို region တခုတည်းမှာ ဖြစ်နိုင်ရင် data center တခုတည်းမှာ အတူတူ အနီးကပ် ပူးတွဲထားဖို့လုပ်ရမယ်။
8) application အတွက် language ကိုလည်း binary အဖြစ် compile ထားလို့ရတဲ့၊ ကြားထဲမှာ interpreter မခံတဲ့ဟာကို သုံးသင့်တယ် ဥပမာ Go တို့ Rust တို့။ တကယ်လို့ ဒီထက်ပိုပြီး resource ကျပ်တည်းတယ်ဆိုရင် GC pause လုံးဝ မပါမယ့် Rust လိုမျိုးကို ရွေးနိုင်တယ်။
9) Data structure နဲ့ Algorithm တွေသေချာရွေးဖို့လိုမယ်။ random access နဲ့ write အဓိက လိုတာလား။ array, hash map သုံးမယ်။ sorted access လိုတာလား။ binary tree ရှိမယ်။ အနီးဆုံး နောက် node ကိုရှာနိုင်ဖို့လိုတာလား spatial tree ရှိမယ် စသဖြင့်။ မှန်ကန်တဲ့မေးခွန်းတွေမေးပြီး အသင့်တော်ဆုံးဖြစ်မယ့် data structure နဲ့ algorithm တွေကို သုံးနိုင်ဖို့ အရေးကြီးတယ်။
10) application design မှာလိုအပ်ရင် concurrent သွားနိုင်ဖို့နဲ့ asynchronous ဖြစ်အောင် ရေးထားဖို့လိုမယ်။ request တခုမှာ အလုပ် ၅ ခုလုပ်ရမယ်ဆိုရင် ရှိသမျှ core တွေမှာ ခွဲလုပ်နိုင်ဖို့ parallelized task တွေလုပ်ထားရမယ်။
11) application က external dependency ဖြစ်တဲ့ ပြင်ပက API တွေ၊ Database တွေ (Mysql, Postgres, MongoDb) နဲ့ Cache Database (Redis, Memcached), Object storage (S3) တို့လိုဟာတွေ၊ နောက် service to service တွေနဲ့ ဆက်သွယ် အလုပ်လုပ်ရတယ်ဆိုရင် အဲဒီ downstream service တွေဆီက latency ကိုပါထည့်စဥ်းစားဖို့လိုမယ်။ Database query တွေကို optimized ဖြစ်အောင်လည်း ရေးဖို့လိုတယ်။