php 开源 编程 java Ubuntu Firefox shell linux nginx Android 程序员 centos 微软 apache Windows Python mysql google 云计算 wordpress

DockOne微信分享(九十七):現有系統實施微服務架構改進經驗分享

本文講的是DockOne微信分享(九十七):現有系統實施微服務架構改進經驗分享【編者的話】微服務是最近非常熱門的話題了,它帶來的好處吸引不少互聯網公司對現有項目進行微服務架構改進。 本次分享是博主根據自身的項目經驗,介紹如何對現有架構進行調整,總結這過程中的相關技術選型,以及如何實施技改,並分享最終取得的非常讓人意外的成果。

大家好,我是鳳凰牌老熊,很高興能有機會和大家交流關於微服務系統建設相關的話題。 近期和微服務相關的話題非常地火,大家看到的各種開發技術網站,微服務都是一個熱門的話題。 今天我也來湊湊熱鬧吧。 將要和大家分享的是我已經做過的一個項目和正在做的一個項目。這兩個項目都是對現有系統進行微服務改造,我將重點介紹具體技術改造的內容,為後來者提供借鑒參考。 一些關於微服務的高大上的理論內容,比如微服務的意義、為什麽要微服務、限流熔斷的理論依據和實現框架等等內容,大家可以參看以前專家的分享。

先介紹第一個項目的技術改造。這是一個數據倉庫的建倉項目。 公司的業務數據的讀寫往往都會分布在多個項目中,這給前端數據展示以及數據分析造成困難。拿視頻數據來說,其元數據,如作者、演員等信息,一般會由內容管理系統來生產;而視頻流數據,如編碼、時長等,是由編碼系統來產生的。視頻的觀看人數、點擊數等,又是由統計系統來提供。 而在頁面展示的時候,這些內容都要同時顯示出來。這就需要一個數據倉庫作為中介,將所有數據收集起來,並提供給前端使用。 這個數據倉庫系統基本上會對接公司所有的業務系統,提供數據讀、寫和分析支持。 

我在2014年接手這個項目的時候,已經有一個比較穩定運行的系統。實際技改工作是2015年初開始,2015年底完成。成果主要包括:
數據讀寫的性能大幅提升。高峰期讀的QPS 由 50次/分鐘,提升到 2萬/秒,日訪問量也從2萬左右,提升到接近20億。並可以輕易橫向擴展。數據寫入能力,也從30TPS/秒,提升到3000TPS/秒。
從單機房服務,擴展到異地三機房同時提供服務。讓大部分業務訪問都能夠在同機房內部完成。跨機房數據同步,正常情況下,在1s內可以完成。
新接口開發投入的effort縮短,從原有的1-2天,進一步縮短到2小時即可上線。

在這過程中,我們在對原有系統做技術升級的同時,也引入了微服務框架來做實現。作為技改項目,我們的原則是:小步快跑,積小勝為大勝。在保證線上系統穩定運行的同時,逐步改進原有系統。 這是一個核心系統,一旦出問題,公司整個業務都會受到影響。技術改造是一個高風險的工作。 除非是上級領導明確要求並同意把這個工作作為考核指標來激勵團隊,否則很難以推進。 另外也要得到團隊成員的支持。 我們啟動這個工作前有半年的準備期,其中很大一部分工作是在爭取大家的支持。最後也是認可這個架構的人才參與系統改進工作,確保整個工作是按照預定設計逐步推進。

這個項目我們進行的還比較順利,原來的系統的基礎還算比較好。 老項目有三個大工程,實現數據讀、寫、同步。對外提供的是RPC接口,使用Apache Thrift作為RPC框架和服務器。 數據同時寫入到MongoDB和HBase中。MongoDB主要用來支持數據讀取,而HBase用來支持數據寫入。 

主要問題在於:
雖然原項目設計打算用Mongodb和HBase來做讀寫分離,實際實現的時候並未達到這個目標。數據是同時寫入MongoDB和Hbase的。這經常導致數據不一致,在高峰期寫入時,由於MongoDB的特性,經常發生寫入失敗的情況。
項目規模大,維護困難。幾個核心類,每個類規模都超過2000行。新員工入職後,沒有半年的熟悉時間,都不敢動核心代碼。
開發進展慢。由於這個項目提供的是後臺數據功能,一般產品規劃時很容易漏掉這裏的工作。當想起來需要支持的時候,給的開發時間都不多。

需要我們在架構和流程上做調整。具體來說,在微服務化的層面,我們做了如下工作: 
1. 建立服務網關

這是一個很重要的工作,有了網關的支持,我們就可以根據需要把流量在新老系統之間切換。我們采用的是zookeeper和網關服務來實現。所有服務註冊到zookeeper上,網關服務根據zookeeper的註冊項來將用戶請求按比例打到具體的工作機上。這比直接訪問工作機會增加1ms左右的開銷。在網關上使用Netflix Hystrix來實現熔斷和限流。
2. 細分業務,讀寫分離

一提到讀寫分離,很多人直觀概念是使用主從的方式來實現。 實現上還需要根據業務情況來詳細分析。 這個項目中,我們將數據寫入場景做了詳細的分析,按場景來拆分原有數據讀寫接口。 在寫入上,我們按照場景拆分為如下接口:
高速寫入。主要用於離線分析結果入庫。 采取的方案是分析數據通過MapReduce、Spark等框架寫入到Kafka中,我們接受Kafka的數據,灌入到HBase中。 每天變更數據在千萬量級,1小時左右時間完成寫入。這些數據變更無需實時通知業務方。
中速寫入。主要用於支持線上數據的入庫。數據通過RPC服務接口直接入庫到Hbase中,支持每秒在3000TPS左右的寫入。
低速可靠寫入。主要用於支持人工生產數據入庫。數據也是通過RPC接口來寫到HBase中。數據寫入後,通過消息機制來通知各業務方相關的改動。

在讀取功能上,我們也拆分為兩類工作:
可靠讀取,主要用於支持數據生產工作。同一條數據會有不同業務方來通過工作流來寫入,後寫入者需要通過上一個寫入者的數據來確定寫的內容。這種情況,要求能夠隨時讀取到可靠的數據。 對於這些讀取,我們是直接將請求打到持久化庫中(Hbase)。
高速讀取,主要用於支持線上數據查看。這類操作一般對數據的實時性要求不高。我們采用Couchbase來做緩存,支持線上讀取。 廢棄早期的MongoDB。我們一個Couchbase可以輕松支持線上上萬的QPS。

這就涉及到數據同步問題了:
讀寫庫之間的數據同步,我們通過MQ(Apache ActiveMQ,橋接)來實現。 數據寫入到HBase時,發出Message。讀庫接收到Message之後,更新自己的數據。
跨機房數據同步,我們也是走的MQ。相對來說,MQ對網絡不像數據庫內部同步機制這麽敏感。 在網絡出問題的時候,MQ能夠盡快恢復。同時監控起來也方便。

這裏有一個小細節,實際上跨機房的Couchbase數據同步,我們也是走的MQ。在每個機房接受MQ之後更新Couchbase的數據。 我們的Couchbase定位於緩存,僅保存熱數據。從實踐中發現,不同地域的人,關註的數據還是不一樣的。這導致Couchbase的內容差異不少。
3. 接口拆分,微服務化

有了網關的支持,明確拆分目標和架構後,我們就可以將原項目中龐大的實現類做拆分,按照服務來切分,建立Project。每個Project僅實現不會超過5個接口,這些接口都是高內聚的、同功能的,僅僅是參數略有不同。 拆分之後,每個項目中的實現類都很少,不會超過10個,而且每個類的規模也很小,代碼行數不會超過300行。 新員工入職後,都能夠立即上手。
4. 完善基礎設施

在微服務環境上,我們采用Git做版本控制,GitLab做代碼審核, Jenkins來支持自動發布和上線。正在小規模試用Spring Cloud,效果還不錯,後續會繼續推廣。

這是第一個項目的情況。第二個項目是我當前正在做的。這是一個支付系統,面臨的情況比第一個項目復雜多了,也是更典型的一個項目。原系統是ssh框架,很難想象支付系統會采用這個技術選型。不過大部分現存的web系統也都是采用這個框架,這個改造可以為大家提供更相似的實戰經驗。老系統規模龐大,每個項目都有超過1000個類,最大的一個項目有3000多個類。由於項目正在進行中,可以分享的內容還不多。項目完成後,爭取有機會和大家一些再做交流。 目前可以分享的要點主要有:
這個項目我們采用Spring Cloud來作為微服務的框架。
我們將系統拆分2個大層,不包括前端系統。一層是對外提供的Web服務,采用http/json。 一層是業務邏輯層,供Web服務層調用,采用RPC來實現。
Web層采用Spring Boot來實現;
RPC層采用Apache Thrift 來實現。
服務網關使用Nginx + Lua實現Load Balance、限流、服務自動發現。
基礎設施上,仍然是Git + GitLab + Jenkins。

關於這個項目的進展,以及項目開發中的一些想法和設計,大家可以關註我的公眾號“鳳凰牌老熊”,或者訪問個人博客,謝謝。
Q & A

Q:服務網關使用Nginx + Lua 方案有考慮過嗎?
A:有,我第二個項目就用這個方案來做,正在做。
Q:我想問個問題,微服務後分布式事務如何處理的?
A:非常好的問題。第一個項目沒有這方面的問題。第二個項目,支付項目,事務處理問題就很突出。 網上有不少分享,關於如何使用MQ來做分布式事務的。不過我們用的方式比較簡單粗暴。 那就是去掉分布式事務,追求最終一致。 從實際情況來看,這已經能夠滿足絕大部分的場景需求了。
Q:關於ZooKeeper / Curator+ 自己實現的發現服務來做服務的自動註冊和發現,能否詳細一點說明?
A:Apache Curator是對ZooKeeper API的一個封裝,支持事件處理和重試,和Spring Framework也集成得很好。在服務註冊實現上,我們是在服務提供方通過Curator API來寫入到ZooKeeper上,服務消費者從ZooKeeper上來發現所需要的服務。
Q:1-5個內聚的接口一個project。 能在詳細下麽?
A:內聚的接口,指這些接口功能相同,主要是輸入參數不一樣。比如檢索的接口,有按關鍵字檢索,有按作者 + 時間的檢索。這樣的接口,可以放在同一個項目裏面。但是根據ID來讀取的接口,和這個檢索接口,就是不同的項目。 這樣控制項目規模不會太龐大,也便於維護。
Q:我有個問題,你們這個項目一定有很多微服務的jar包,這是jar包在服務器上是怎麽分布的?
A:對Web接口類型的微服務,其實和普通的項目一樣,每個項目就管自己的jar包以及它所依賴的jar包。 也有人會把所有的jar包匯總起來打成一個大jar包,這種方式,容易出現資源文件被覆蓋的情況,也不容易更新,不推薦。
Q:RPC為什麽不用國產Dubbo啊?
A:這是個好問題,我們經常被問這個問題。 Dubbo是個不錯的框架,相對微服務來說,還是太重了。 而且,性能上,比Thrift 還是要差不少。 所以我們就直接上Thrift了。
Q:支付的這個需要對接多個銀行麽?
A:需要,我們現在對接了快10個銀行,還在對接更多的銀行。除了銀行,第三方支付、外卡等,也都在接。
Q:服務網關重點需要關註那些點?
A:我們實際有兩個網關,一個是對外的Web接口服務網關,關註的是Load Balance以及可靠性。 特別是服務重啟的時候,網關要提前解除註冊,重啟之後,網關要延後註冊上。 這有不少成熟的組件可以用,不一定像我們這樣自己開發。 RPC網關,也是要註意穩定性和性能,以及網關決不能和業務耦合。
Q:微服務是按表來拆分的,那麽是一個服務自己連一個數據庫還是有統一得數據層呢?
A:RPC層的微服務,基本是按表來拆分了,自己連一個數據庫。這裏實際也分兩層,數據訪問層和業務邏輯層。如果業務邏輯很薄,就合並成一層了。
Q:用 Thrift 做 RPC,服務發現也是自己做的嗎?
A:是的,這個用Apache Curator比較容易實現,我們就自己搞一個。
Q:Hbase和mongo讀寫分離這塊能具體說一下嘛? 和mongo副本集比較有啥優勢麽?
A:這個問題就是涉及到如何使用數據庫的問題。每個數據庫都有自己的優勢,比如HBase寫入性能極好,上萬的TPC都沒問題,但是讀取的性能就差了,就小幾千。 Couchbase讀取的性能極佳,但是寫入就很一般。 Redis讀寫都很不錯,就是不能支持太大粒度的數據,以及容量有限制。 MongoDB似乎比較尷尬,功能很全面,但是讀寫都一般。
Q:Couchbase通過MQ實現跨機房同步是怎麽實現的?
A:在主流程中,數據修改的時候會發出一個Message,監聽程序接收到這個消息後,去更新couchbase中的數據。 采用MQ的原因,在於它對網絡波動不像數據庫直接同步那麽敏感。
以上內容根據2016年11月29日晚微信群分享內容整理。分享人李雄峰,程序員 & 架構師,來自中科大的本科,研究生在軟件所學習。先後在中科輔龍、三星(中國)研究院和國內一些大型的互聯網公司呆過。在中科輔龍公司負責電子政務內容管理系統建設,負責研發龍馭系列產品的研發,這款產品最終實施到2000多個電子政務網站上,期間也參與了一些支付反洗錢以及支付系統的建設。之後在三星中國研究院,負責自然語言處理(NLP)以及智能家居相關項目。智能家居項目在2014CES消費電子展上作為三星重點項目推介。2014年開始加入愛奇藝公司,負責數據倉庫和支付系統的建設。 DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加微信:liyingjiesz,進群參與,您有想聽的話題或者想分享的話題都可以給我們留言。

延伸阅读

    评论