10.18 Python後端架構演進

做了3年的後端開發, 經歷一款SaaS產品從0到10(還沒有到100, 哈哈哈)的過程, 3年間後端的架構逐步演變, 在微服務的實踐過程中遇到的問題也越來越多, 在這裡總結下.

產品是一款服務於人力資源的SaaS在線服務, 面向HR有Web Android/iOS 小程序多個客戶端, 後端採用RESTful風格API來提供服務. 主要使用Python語言, 方便快速迭代.

架構的演進經歷了4個大的階段: 1. MVC 2. 服務拆分 3. 微服務架構 4. 領域驅動設計.

Python後端架構演進


1. MVC

項目剛開始的時候, 後端同事不超過5個, 這個階段主要的工作是實現產品的原型, 沒有太多的考慮架構, 使用Django來快速實現功能, DB的表結構設計好之後, 抽象出功能View, 由於產品設計也很不完善, 後端需要很多的預留設計, 避免產品邏輯的變更帶來整個表結構的變動, 在這個階段代碼上最重要的是確定適合團隊的代碼規範, 代碼檢查規則.

Python後端架構演進


整體上架構如上圖, Nginx負責負載均衡, 分發流量到多個Django服務, Django處理邏輯, 需要異步任務就交給Celery, 然後數據量比較大的地方使用Redis做緩存. 同時還有實時消息通知的需要使用了Nginx Push Module.

問題與優化方式:

Django併發性能差 使用uWSGI Master+Worker 配合 gevent 攜程支持高併發

Redis連接數過多 使用redis-py自帶的連接池來實現連接複用

MySQL連接數過多 使用djorm-ext-pool連接池複用連接

Celery配置gevent支持併發任務

隨著開發的功能越來越多, Django下的app也越來越多, 這就帶了發佈上的不方便, 每次發佈版本都需要重啟所有的Django服務, 如果發佈遇到問題, 只能加班解決了. 而且單個Django工程下的代碼量也越來越多, 不好維護.

2. 服務拆分

隨著後端團隊的壯大, 分給每個同事的需求也越來越細, 如果繼續在一個工程裡面開發所有的代碼, 維護起來的代價太高, 而我們的上一個架構中在Django裡面已經按模塊劃分了一個個app, app內高類聚, app之間低耦合, 這就為服務的拆分帶來了便利. 拆分的過程沒有遇到太大的問題, 初期的拆分只是代碼的分離, 把公用的代碼抽離出來實現一個公用的Python庫, 數據庫, Redis還是共用, 隨著負載的增加, 數據庫也做了多實例.

Python後端架構演進


如上圖, 服務之間儘量避免相互調用, 需要交互的地方採用http請求的方式, 內網的調用使用hosts指向內網地址.

問題與優化方式:

Nginx Push Module由於長時間沒有維護, 長連接最大數量不夠, 使用Tornado + ZeroMQ實現了tormq服務來支撐消息通知

服務之間的調用採用http的方式, 並且要求有依賴的服務主機配置hosts指向被調用的地址, 這樣帶來的維護上的不方便. 以及在調用鏈的過程中沒有重試, 錯誤處理, 限流等等的策略, 導致服務可用性差. 隨著業務拆分, 繼續使用Nginx維護配置非常麻煩, 經常因為修改Nginx的配置引發調用錯誤. 每一個服務都有一個完整的認證過程, 認證又依賴於用戶中心的數據庫, 修改認證時需要重新發布多個服務.

3. 微服務架構


Python後端架構演進


首先是在接入層引入了基於OpenResty的Kong API Gateway, 定製實現了認證, 限流等插件. 在接入層承接並剝離了應用層公共的認證, 限流等功能. 在發佈新的服務時, 發佈腳本中調用Kong admin api註冊服務地址到Kong, 並加載api需要使用插件.

為了解決相互調用的問題, 維護了一個基於gevent+msgpack的RPC服務框架doge, 藉助於etcd做服務治理, 並在rpc客戶端實現了限流, 高可用, 負載均衡這些功能.

在這個階段最難的技術選型, 開源的API網關大多用Golang與OpenResty(lua)實現, 為了應對我們業務的需要還要做定製. 前期花了1個月時間學習OpenResty與Golang, 並使用OpenResty實現了一個短網址服務shorturl用在業務中. 最終選擇Kong是基於Lua發佈的便利性, Kong的開箱即用以及插件開發比較容易. 性能的考量倒不是最重要的, 為了支撐更多的併發, 還使用了雲平臺提供的LB服務分發流量到2臺Kong服務器組成的集群. 集群之間自動同步配置.

餓了麼維護一個純Python實現的thrift協議框架thriftpy, 並提供很多配套的工具, 如果團隊足夠大, 這一套RPC方案其實是合適的, 但是我們的團隊人手不足, 水平參差不齊, 很難推廣這一整套學習成本高昂的方案. 最終我們開發了類Duboo的RPC框架doge, 代碼主要參考了weibo開源的motan.

4. 領域驅動設計


Python後端架構演進


在這一架構中我們嘗試從應用服務中抽離出數據服務層, 每一個數據服務包含一個或多個界限上下文, 界限上下文類只有一個聚合根來暴露出RPC調用的方法. 數據服務不依賴於應用服務, 應用服務可以依賴多個數據服務. 有了數據服務層, 應用就解耦了相互之間的依賴, 高層服務只依賴於底層服務.

在我離職時領域驅動設計還在學習設計階段, 還沒有落地, 但是我相信前公司的後端架構一定會往這個方向繼續演進.

總結

架構的設計, 技術的選型, 不能完全按照流行的技術走, 最終還是服務於產品, 服務於客戶的需求. 設計過程中由於團隊, 人員的結構問題, 有很多的妥協之處, 如何在妥協中找到最優解才是最大的挑戰.

最後,小編想說:我是一名python開發工程師,整理了一套最新的python系統學習教程,想要這些資料的可以關注私信小編“01”即可,希望能對你有所幫助


分享到:


相關文章: