任何一個App都須要一個Server,咱們認爲,移動開發者(或組織)不該該把精力放在這些事情上面:java
搭建後端Server服務。git
編寫後端Server代碼。github
設計Server底層數據存儲架構。web
關注Server的高可用、可擴展、負載均衡、高性能等諸多繁瑣問題。redis
這些事情可能會耗掉你80%以上的時間和精力,結果服務可用性、穩定性、可擴展性等均可能不盡人意。spring
咱們還認爲,你應該把更多的精力聚焦在業務和App開發上面,這樣不只節約了時間和金錢,更重要的是你能把全部精力都放在業務自己上面,讓你的應用在競爭中脫穎而出,領先競爭對手。數據庫
簡單來說就是針對App開發者提供的統一的後端對象數據存儲服務,讓用戶再也不關心Server端數據存儲的問題,CloudData具備關係型、半結構化、json格式及單個對象具備事務性等特色,採用MongoDB 3做爲存儲系統,至於CloudData更多細節請參考MaxLeap CloudData相關文檔。編程
CloudData架構很是的簡單,從上往下看,包括API Server、數據訪問邏輯處理層和底層數據存儲層,下面,咱們分別介紹三個模塊的具體實現原理。json
在Api Server層面,咱們的語言採用的是java,針對java,當前比較流行的方式多是:選擇一個web 框架,多是spring mvc,使用java servlet,而後選擇一款 java web 容器,多是tomcat或者jetty等,但咱們並無採用這樣方式,由於,在咱們看來,這種方式有幾個缺點:架構顯得有些笨拙,每次啓動都須要部署到java web 容器中,不夠輕量、同步通訊,併發上不去,性能較低。所以,經過綜合考量,咱們選擇了vert.x web框架,vert.x 基於事件驅動、非阻塞通訊機制,這意味着,只須要不多的線程就能應付大量的併發,同時它也更加的輕量,擁有更高的性能,啓動vert.x web服務只須要幾十毫秒到幾百毫秒之間,使用也是異常的簡單,只要你稍稍懂一點http協議及網絡編程幾乎能夠說是零學習成本:後端
HttpServer server = vertx.createHttpServer(); Router router = Router.router(vertx); router.route("/index").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response.putHeader("content-type", "text/plain"); // Write to the response and end it response.end("Hello World Maxleap!"); }); server.requestHandler(router::accept).listen(10086);
須要注意的是,vert.x web基於EventLoop單線程模式,因此,在寫web服務的時候,不能寫同步處理邏輯,不然會阻塞主線程,致使其餘請求不能獲得響應;另外,有異步編程經驗的同窗必定感覺到這樣的痛苦:callback方法氾濫成災,大量的flatMap方法調用致使也致使代碼的可讀性差,除此以外,咱們實在是找不到vert.x web框架的任何缺點。固然,這些缺點也並非不能夠避免,基於此,咱們對vert.x web,稍稍加了一點東西,改變了一些實現策略:咱們在邏輯處理階段將異步變成同步,在框架後面,咱們在變成異步,而且增長了對JAX-RS 部分規範支持,若是以前你以爲,基於vert.x web寫rest接口還有一點點的學習成本,但如今基於咱們改變以後的vert.x web寫rest接口,你會發現跟之前並無兩樣:
@GET @Path(":className/:objectId") public void get(RoutingContext context) { func(context, (ctx, cloudCode, appId, className, principal) -> { LASObject doc = lasDataEntityManager.get(appId, className, principal, new ObjectId(context.request().getParam("objectId"))); if (doc == null) { ctx.response().end("{}"); } else { ctx.response().end(MongoJsons.serialize(doc)); } }); }
更多的Api Server相關細節請參考Maxleap的開源BaaS系統實現 https://github.com/MaxLeap/MyBaaS
這一層包含了CloudData的核心邏輯實現,相對來說,是CloudData設計中最複雜的一層,固然,僅僅只是相對,全部的邏輯處理都在這一層,而Pandora是其具體實現,因此,咱們重點會講一講Pandora的設計思路
Pandora是古希臘神話中最美的女人,她充滿誘惑,攜帶危險來到人間,固然,在咱們看來,危險與誘惑跟美麗的女人無關,若是說美麗的人會讓你身處危險之中,那就請讓我萬劫不復吧。
扯遠了,Pandora是Maxleap統一數據訪問層的實現,主要是針對mongo數據的操做,因此,不只僅是用在CloudData中,在Maxleap中全部應用中,須要訪問mongo數據庫的都是經過Pandora來進行的,而且提供了異步和同步兩種接口
Pandora主要實現了兩種模式的數據訪問,CloudData和NativeData。
Clouddata是Maxleap App數據的訪問,凡是訪問應用的數據,都是經過這個模塊,CloudData數據的訪問稍顯複雜一些,包含Pointer、Relation等自定義數據結構的實現;數據ACL的實現;自定義操做指令如$relationTo等
NativeData是對mongo指令友好的封裝,與mongo原生指令並無兩樣。
Pandora最爲核心的功能是實現了資源限制和數據庫訪問的路由策略,這對數據庫進行平滑的動態擴展及遷移提供了可能性,固然,目前Maxleap也實現了這一點,當用戶的應用由於數據量、訪問量上升須要升級後臺mongo數據庫的時候,這一切都是無感知的,不會影響你的線上服務照常運行,固然,某些特殊狀況下,可能須要短暫的停頓服務幾分鐘,而且僅僅是寫停頓,讀不受影響。
在Maxleap項目中,使用Pandora最大的好處是,開發人員無需關心後臺mongo的架構,數據一致性、mongo服務升級降級等諸多繁瑣問題,固然,你甚至連數據存儲在那個mongo集羣都不要知道,由於,使用Pandora我實在想不到你還須要瞭解數據存儲在哪裏的理由。
若是你對Baas有些許,若是你去Maxleap提供的服務有所瞭解,我想,你必定會關心Cloudapp後端數據存儲架構是怎麼設計的,成千過萬的應用數據咱們是怎麼存儲的、你的應用可用性問題、服務是否有足夠的保障,接下來,咱們正要介紹這一點。
先看一下業界某BaaS服務的Clouddata的設計:
(圖片來自網絡)
在咱們看來,這是一種糟糕的設計,若是咱們沒有理解錯的話,全部的用戶數據都在一個大集羣裏面,後端是一個大的sharded集羣,全部的用戶數據的訪問都會經由一組mongos路由服務(毫無疑問,這絕對是一個風險,試想,若是mongos出了問題,整改後端數據存儲就會down掉),固然,這並非主要問題,主要問題在於:
一、數據在一個龐大的集羣中,出現問題的機率也會大不少,好比有10000個應用,那麼出現問題的機率也會大10000倍,1個應用出現一次問題,那麼整個服務都會由於某一個應用出現問題而受到影響。
二、數據規模大了,運維困難,又如,若是mongo異常down掉,恢復時間絕對的是一個煎熬的過程,而這個時候,整個服務都不可用。
三、穩定性較差,每個應用都有可能發送使人噁心的指令,可能會致使資源搶佔(好比最多見的狀況是沒有索引的查詢,會引發熱數據污染,結果集返回大量數據,搶佔了網絡帶寬等),這個時候,整個集羣都會受到影響,可能致使整個集羣的吞吐量降低,反應到應用層面,可能就是大量應用請求短期超時,讀寫失敗
這是咱們Maxleap其中的一臺產品Mongo Server所表現的性能,固然,你可能會驚訝於數據在磁盤也可以擁有4000/s的吞吐量,固然,這一切得益於咱們使用SSD硬盤所帶來的效果。這張圖也告訴咱們,儘量的當心你的查詢,當服務器趨於吞吐平穩的時候,不要形成內存數據污染,但若是是全部的應用在一個大集羣,這種狀況將不可避免,由於,你永遠都不會知道用戶會寫怎樣的查詢指令,而一旦有這樣的指令,影響將會擴散到整個大集羣其餘的應用。
四、效率低下,須要更多的硬件成本,好比,當你的讀寫壓力變大的時候,你不得不加新的機器去copy集羣的全量數據,形成磁盤和內存的浪費,由於你應用的熱數據在每個mongo節點都有(固然,爲何我列在第四點,可能你以爲這並不重要,硬件歷來都不是問題,更重要的是,你以爲,公司歷來都不缺這點錢)
好了,是時候看看咱們的CloudData的設計了,固然,也是極其的簡單,遵循3個原則:
一、用戶資源隔離(毫無疑問,這點是最重要的)
二、動態可無限擴展(無論你有多少個庫,1萬仍是100萬)
三、分而治之
基於以上3點,咱們的設計是爲每個應用建立一個獨立mongo集羣,是否是太簡單了,有木有,可是,咱們認爲這是最科學的,將大集羣按照應用分解成小集羣,大問題分解成小問題,以大化小,分而治之,無論在哪裏,都是靠譜的,而且還特別有效,最近幾年,火的不要不要的被普遍傳播的軟件架構方式‘微服務’不也是一樣的道理麼?固然,你能夠說,微服務更傾向於‘單一職責’原理,固然,只要你高興,隨你怎麼想。
也許,你可能會質疑這是否會浪費資源,由於,每一個人都會有這樣直觀上的錯覺,可是,事實上,不只沒有浪費資源,還會大大的節約資源,這一點,在上面已經討論到,數據在一個大集羣中,副本集越多,浪費的內存越多,磁盤越多。第二點,起一個mongo集羣,並不會浪費多少內存。
固然更重要的是,咱們並非真正爲每個應用建立一個mongo集羣,畢竟,這樣作,不少時候並無意義,由於,90%的應用可能並無較高的訪問量,50%的以上的應用,可能歷來都不會被頻繁訪問。
因此,咱們的策略是,當用戶第一次註冊Maxleap建立一個應用的時候,用戶的數據放在一個默認的集羣中,在Maxleap中,這個集羣叫User Default Cluster,當你的用戶有必定的訪問量的時候(沒有訪問量也沒有關係,只要你是咱們的付費用戶)咱們會把你公司全部的應用部署在一個單獨的mongo集羣中,再日後,你應用訪問量繼續上升,咱們就把你的應用在單獨升級到一個mongo集羣,固然,這一切的升級過程,都是平滑無縫的進行的,沒有人可以感知的到,包括咱們本身。
So,咱們Maxleap CloudData是這樣子的:
好了,關於Pandora及CloudData咱們先簡單介紹到這裏,更多的細節咱們到時候會專門擰一個細節出來討論。
上面咱們早已經知道,咱們使用的Mongo做爲Clouddata做爲主要存儲系統,更早以前,在咱們mongo還在2.6以前,咱們還使用了redis做爲熱數據緩存,但後來我mongo升級到3.0以後,變去掉了redis,因此,整個底層數據存儲,就只剩下mongo,整個系統設計又進一步變得更加簡單,之因此去掉redis,這不是咱們所要討論的重點,咱們會在相關的文章中進行詳細說明。
這裏,咱們重點介紹mongo的集羣架構設計方案
集羣特色:
每個mongo集羣都是一個複製集:1主1從1投票節點,還有一個備份節點(Norns-backup是咱們自主實現的一個增量實時備份系統)
每個mongo集羣都在一個VPC網絡裏面
每個mongo集羣3個節點都在不一樣的可用區裏面(不一樣的機房,機房是光纖直連,網絡延遲大概咋500us)
部分mongo集羣的數據存儲在LVM上面
每個mongo集羣都使用SSD硬盤
每個mongo集羣咱們都提供瞬時10倍以上的請求峯值
原文做者來自 MaxLeap 團隊 基礎服務及架構組成員:趙靜
關於MaxLeap
MaxLeap移動雲服務平臺爲企業提供一站式的移動研發和運營雲服務,幫助企業快速研發和上線移動應用,平臺提供數據雲存儲,雲引擎,支付管理,IM,數據分析和營銷自動化等服務。
MaxLeap官網連接: https://maxleap.cn
若是您正在學習移動研發和雲服務等方面的訊息,不妨關注咱們的微信服務號MaxLeapSvc,咱們將不按期推送相關乾貨。敬請期待!