這些年我對微服務的理解
- 2019 年 12 月 17 日
- 筆記
Monolith、SOA、DDD、The two-pizza rule、分庫分表這些概念跟微服務有啥關係,你知道嗎?這篇文章記錄我的理解,分享給大家。
微服務(micro service),個人感覺也就近幾年才吵起來的概念,記得退回去四五年(2014年),那時候大家還談論SOA(service orentied architecture)比較多。在SOA之前,一個軟件系統大多都是前後端不分離的monolith的架構,通常採用比如說spring mvc、java SSH (spring/structs/hibernate)、.net framework mvc、.net framework web form等技術方案實現。
在計算機這個領域,好像每隔一段時間總會有一些概念被炒作起來,就像近幾年在炒作的微服務、雲原生、人工智能AI、區塊鏈等,大家都在努力抓住這些風口,聽說現在有的大學裏面,學生不發AI相關的論文就不讓畢業,我想這或許是python近兩年在有的語言排行榜超過java成為榜首的原因之一吧。
關於微服務架構的概念,網上有很多介紹,大家可以自行搜索。這裡推薦一個業界比較有名的網址,Martin Fowler的個人網址:https://martinfowler.com/articles/microservices.html。Martin fowler是微服務領域的一個專家,它有很多關於微服務方面的研究,有興趣的童鞋可以去他的個人網址上查閱相關資料。
那麼,如何構建一個微服務架構的應用呢?基於之前的經驗,我的總結如下:
一、掌握好拆分微服務的粒度,使得每個微服務相對獨立,但又是整個業務流程的一部分。怎樣才能掌握好這個粒度呢?我覺得有一種說法挺有道理:從業務角度,可以遵循DDD(domain driven development),即領域建模,按照具體的業務流程來劃分;從團隊組織角度,一個團隊負責一個或多個微服務,團隊大小遵循「The two-pizza rule」。
二、系統的整體設計需要遵循12 factors原則。
三、從系統實現的角度來看,考慮下面這些點:
- API Gateway
- Service Registry and Discovery – Eureka
- Circuit Breaker – Hystrix
- Fault Tolerant – Hystrix
- Message Broker – RabbitMQ
- Database – Postgres
- Logging and Tracing – ELK
- Authorization and Authentication – OpenID/SAML/OAuth/JWT
- Secure Credential Store – Vault
- Security and Audit
- CI/CD – Jenkins
- Monitoring – Grafana
- Container Runtime – Docker/CloudFoundry/Kuberntes
- Scaling – Vertical scaling/Horizontal scaling
- Proxy and Load Balancer – nginx
- Multi-Tenancy
此外,下面是我對微服務相關話題的一些思考:
一、微服務火了之後,業界一直有這樣一個問題:微服務和SOA的區別到底是什麼?
我個人的理解是這樣的,SOA出現的背景大約是前後端不分離的monolith應用時代,為了解決各個應用系統之間的集成,於是就出現了SOA(service oriented architecture),意即面向服務的架構,idea就是把應用系統當成一個服務來設計,這樣外部系統就可以很好的來消費這個服務,記得那時候把服務暴露出來的常用做法就是SOAP;而微服務出現的背景是,SOA本質上大多還是monolith架構,即是單體應用,為了解決單體應用很重的問題,出現了微服務。所以SOA是第一階段,服務主要面向系統外部集成;而微服務則是第二階段,服務不但面向系統外部,同時也面向系統內部。
二、微服務和monolith的比較,下面是我個人的看法:
- 微服務開發效率更高,環境setup簡單,build/checkout/run更快,ut/it 時間更短。各個微服務職責分離,邊界清晰,有利於cross team開發,特別是對於跨location的協作開發,優勢更加明顯。記得之前有一個monolith的項目,代碼總共幾百萬行,從git上拉下來都要幾十分鐘,build也很慢,ut/it需要跑非常長時間,開發效率很低,同時也非常不利於實現CI/CD。
- 從擴展性方面來講,微服務既可以水平擴展,也可以垂直擴展。而monolith只可以水平擴展。
- 有人說monolith可以利用數據庫事務,保證強一致性,而微服務則不能保證強一致性,通常只能保證最終一致性,這是monolith的一個優點。我覺得這個點需要辯證的來看,因為強一致性,有時候也會帶來一些性能問題,比如事務很大且高並發的情況,數據庫容易成為瓶頸,最終導致吞吐量太低。同時,正如我之前寫的一篇文章(關於分佈式系統數據一致性的那些事),現實生活中也不可能有一個大而全的系統可以cover所以的場景,並且用事務保證強一致性。一個典型的例子,銀行轉賬往往需要強一致性,單個銀行系統可以用數據庫事務實現,但是跨銀行系統轉賬就不可能利用單機數據庫事務,因為不同銀行系統都是自己的數據庫,所以即使是銀行系統並不能保證強一致性。之前一個同事說他就親身經歷過一次銀行系統短時不一致的情況:他跨行取錢,錢被扣了,但是錢沒吐出來,最後是去櫃檯人工處理才解決。
三、微服務到底是選擇共享數據庫還是獨立數據庫?下面是我個人的看法:
- 如果是共享數據庫的話,仍然類似於單體設計(數據庫層面的單體設計),數據庫層只能水平擴展, 容易成為瓶頸,比如說鎖資源佔有、死鎖、 DB層面緊耦合導致開發互相影響等。原則上,對於微服務系統,應該只有API是不同微服務之間的contract,如果採用共享數據庫,就又引入了另外一個層面的contract,不容易維護,當有其他團隊的人改了數據庫,容易導致意想不到的錯。
- 有人說採用共享數據庫,做報表更方便。是的,如果是共享數據庫,報表生成可以直接基於數據庫來做join等操作,而如果是獨立數據庫,直接基於數據庫的join就不行。但是,採用共享數據庫也並不意味着報表方便。一般來說報表屬於OLAP操作,而業務邏輯屬於OLTP操作,理論上講,列級數據庫更適合OLAP操作,而行級數據庫更適合OLTP操作,如果報表這類OLAP操作和業務邏輯OLTP操作同用一個數據庫的話,大量的OLAP操作會影響OLTP業務處理,所以,這兩類操作分開用各自合適的數據庫,才能互不影響並且利用不同數據庫的優勢。記得,退回去幾年(2014年),大數據還比較火,大家都在炒作這個概念,Hadoop、HBase、Spark、HANA等就是那時候的產物,其實個人理解大數據就是拿來做OLAP操作的。
四、分庫分表和微服務的關係?
當一個系統數據量上去了,往往都需要考慮分庫分表的事情。因為一旦數據量級上去了,數據庫很容易就成為瓶頸。所以,怎麼實現分庫分表呢?其實,微服務本身就是一個很好的分庫分表的實現。首先,每個微服務獨立數據庫就是一個層面的分庫,不同微服務相關的業務數據存在單獨的數據庫,可以一定程度緩解共享數據庫的瓶頸。其次,一個SaaS系統往往需要考慮多租戶,一種多租戶實現策略就是:每個租戶擁有自己的獨立數據庫,不同租戶的數據就被存在各自獨立的數據庫,這樣又是一個層面的分庫。其實分庫的本質也就是通過一種哈希算法,把數據分散到不同的數據庫實例上,以達到負載均衡的作用。另外,有時候通過分庫仍然會存在一些表數據量太大的問題,比如訂單表,當數據量太大的時候,其讀寫操作的性能往往會急劇下降,這時候就需要做分表了。其實,個人覺得分庫某些時候也是一種分表,除此之外,還有一些其它策略,比如說,我們可以把比較老的數據存到另外一張表去,就像一些電商平台,用戶默認只能看最近三個月的訂單等。 五、遷移monolith應用到微服務架構
如果我們開發一個系統,一開始選型就是微服務,這樣很容易。但是,有時候我們需要把一個非常龐大的monolith應用遷移到微服務架構,這往往不是一件容易的事情。一般怎麼做呢?我們需要從多個層面考慮:技術層面,首先需要仔細思考怎麼拆分微服務,有時候這會很難,因為對於一個龐大的monolith應用,之前的實現各個模塊之間往往耦合得非常緊;其次需要把之前的數據褲拆分為每個微服務獨立的數據庫,這也會很難,因為怎麼實現數據遷移需要仔細考慮,可以參考我之前寫過的一篇文章(如何不宕機實現數據庫遷移)。另外,團隊層面也需要考慮很多,比如說團隊的組織結構可能需要調整、團隊成員的mindset需要buildup等。 最後,最近各大雲廠商都在大力炒作cloud native,我查看了一些關於相關介紹,感覺其實它和微服務就是換湯不換藥,其實就是基於微服務的概念,然後加了一些容器編排的概念。See https://jimmysong.io/kubernetes-handbook/cloud-native/cloud-native-definition.html。 References
- https://martinfowler.com/articles/microservices.html#HowBigIsAMicroservice
- https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice
- https://12factor.net/
- https://jimmysong.io/kubernetes-handbook/cloud-native/cloud-native-definition.html
- https://www.oreilly.com/library/view/microservices-antipatterns-and/9781492042716/ch04.html