今天要來講系統架構,一路從 mono 玩到 distribute、漸進式長大、小怪打到菁英 BOSS 的過程。不過先講結論,這種東西不是挑最大最強的來用就是最好,每一個狀況下都有他適合的架構,拿著大刀砍小雞不但砍不著,你可能還會累個半死。
所有的電商巨頭或者是高流量的系統,一開始都是從單體開始長,並且隨著量的增加逐漸調整,今天我們就來過一過幾個常見架構演進歷程。
一台 VM 裡面塞 Application Server、靜態資源和資料庫。簡單而開心,單純而美麗,配個垂直擴展,現代 AP Server 都已經很強壯,到某個量之前你用很好的機器就 OK 的。
當上面那種狀況撐不住的時候就要開始考慮這個,把 Application Server、靜態資源和資料庫放到不同 VM 上。
加上 Cache 來緩存一些熱資料降低 response time,其中又可以分成放在 Application Server 上面的本地緩存和遠端緩存伺服器 (Redis、Memcached),另外可以用它來實現一些額外的功能例如 lock 或 message queue。而值得一提的是由於遠端緩存伺服器資源理論是珍貴的,所以本地緩存其實有一個重要任務是要保護它,如果你放任很大的 QPS 請求直接轟炸你的緩存伺服器,那後果也是可想而知,當然雙邊同步就是一個要處理的議題。
在 Application Server 前面加上一個負載平衡器,其實手法很多,例如 DNS、Reverse Proxy、Hardware Solution、Linux Solution、Cloud Solution 等等。也就是說在這個層面上我們專注在控制流量跟路由,同時也開始可以實作一些 HA (High Available) 層級的事情。
要知道就算你的 Application Server 一直擴展,它能夠幫你分掉的也只有 CPU 跟 Memory 的壓力,Database 將會是接下來的瓶頸點,所以最基本的手法是主從架構配上讀寫分離,master write / slave read,分離的話可做在資料庫端也可以做在應用層,各有好處。另外主從分離之後,資料庫也會擁有基本的備援能力。
下一個想加快的部份是 Application Server 更前側的部份,把 CDN 加給前端,然後配上 Reverse Proxy Server 來做一些加速還有其他功能 (負載平衡只是 Reverse Proxy 其中一個功能而已)
然後有一天你發現你的靜態資源跟資料庫容量不夠擺了,需要在加大,於是你便開始採用分布式的結構,並且獲得更好的 HA。
回頭檢視你的系統,資料可能分成不同的類型來儲存會更合理,NoSQL 也是應這波風潮而生,不過必須這邊走到這步其實很少,現代資料庫真的太成熟強壯。但是如果是特殊需求而使用就會合理的多,這個還是要看情境來決定。
當你上面都沒招了,重新審視你的業務是會有流量上跟重要程度上的差別,所以根據業務來拆分 Application 是這階段的作法。另外這時候通常會有跨 Instance 溝通的需求,我們引入 Message Middelware 作為中間件來處理這個需求 (Kafka、RabbitMQ、RocketMQ 等等),引入也會帶來一些好的化學反應,有了 Message Queue,系統設計上更靈活。
先不論你的表結構設計的如何,單表幾 G 基本上就已經是很大的量,要是繼續大下去,再成熟強壯的資料庫也有其極限,所以分表是個無法避免的手段,分的方式最常見的是時間,by 日或 by 月之類的。另外一部分是根據業務來分庫,因為業務量有輕重的議題,配合上一個階段的業務拆分來實作也可以得到一個更好的效果。
微服務架構,這個我就不用多說了,這個火紅的程度其實 Google 都講的比我好。只是我想提的是微服務架構會讓本來一些簡單的事情變得複雜,連日誌跟設定檔這麼小的事情都會出來搗亂,可以參考 Day 9 設定檔與日誌這件小事。另外監控議題也會變得十分麻煩,監控議題我們會留到後面有一天再講,記得準時收看 (拖稿是想被毆飛!?)
如果上面您很有耐心的看完,這個我就不會在增加你的負擔了,請把剛剛上面的東西全部變成雲服務。AWS、GCP 和 Azure 通通站出來!
最後請聽小弟一句話,即時你習得絕世好劍的製作方法及用法 (步驚雲:),但根據情況來選擇工具才是最實際的。你的工具箱固然是越多工具越好,但請千萬不要在必須拿出+9美工刀的時候拿出屠龍刀,切記切記。
About Me
Jian-Min Huang
wide range skill set backend engineer
Research, Architecture, Coding, DB, Ops, Infra.
mainly write Java but also ❤️ Scala, Kotlin and Go