原文:談?wù)劵ヂ?lián)網(wǎng)后端基礎(chǔ)設(shè)施
作者颯然hang是ETouch隨身云的架構(gòu)師,中華萬年歷就是其公司作品,專注于JavaEE、系統(tǒng)架構(gòu)、大數(shù)據(jù)等后端技術(shù);在基礎(chǔ)框架、數(shù)據(jù)統(tǒng)計(jì)、推薦系統(tǒng)、DSP、廣告平臺(tái)方面有一定的實(shí)踐經(jīng)驗(yàn); 更多信息可見 http://rowkey.me
獲得作者授權(quán),轉(zhuǎn)載此文,以饗中生代讀者!
對于一個(gè)互聯(lián)網(wǎng)企業(yè),后端服務(wù)是必不可少的一個(gè)組成部分。拋開業(yè)務(wù)應(yīng)用來說,往下的基礎(chǔ)服務(wù)設(shè)施做到哪些才能夠保證業(yè)務(wù)的穩(wěn)定可靠、易維護(hù)、高可用呢?縱觀整個(gè)互聯(lián)網(wǎng)技術(shù)體系再結(jié)合公司的目前狀況,個(gè)人認(rèn)為必不可少或者非常關(guān)鍵的后端基礎(chǔ)技術(shù)/設(shè)施如下圖所示:
Api網(wǎng)關(guān)
業(yè)務(wù)應(yīng)用和后端基礎(chǔ)框架
緩存、數(shù)據(jù)庫、搜索引擎、消息隊(duì)列
文件存儲(chǔ)
統(tǒng)一認(rèn)證中心
單點(diǎn)登錄系統(tǒng)
統(tǒng)一配置中心
服務(wù)治理框架
統(tǒng)一調(diào)度中心
統(tǒng)一日志服務(wù)
數(shù)據(jù)基礎(chǔ)設(shè)施
故障監(jiān)控
這里的后端基礎(chǔ)設(shè)施主要指的是應(yīng)用在線上穩(wěn)定運(yùn)行需要依賴的關(guān)鍵組件/服務(wù)等。開發(fā)或者搭建好以上的后端基礎(chǔ)設(shè)施,一般情況下是能夠支撐很長一段時(shí)間內(nèi)的業(yè)務(wù)的。此外,對于一個(gè)完整的架構(gòu)來說,還有很多應(yīng)用感知不到的系統(tǒng)基礎(chǔ)服務(wù),如負(fù)載均衡、自動(dòng)化部署、系統(tǒng)安全等,并沒有包含在本文的描述范圍內(nèi)。
Api網(wǎng)關(guān)
在移動(dòng)app的開發(fā)過程中,通常后端提供的接口需要以下功能的支持:
負(fù)載均衡
api訪問權(quán)限控制
用戶鑒權(quán)
一般的做法,使用nginx做負(fù)載均衡,然后在每個(gè)業(yè)務(wù)應(yīng)用里做api接口的訪問權(quán)限控制和用戶鑒權(quán),更優(yōu)化一點(diǎn)的方式則是把后兩者做成公共類庫供所有業(yè)務(wù)調(diào)用。但從總體上來看,這三種特性都屬于業(yè)務(wù)的公共需求,更可取的方式則是集成到一起作為一個(gè)服務(wù),既可以動(dòng)態(tài)地修改權(quán)限控制和鑒權(quán)機(jī)制,也可以減少每個(gè)業(yè)務(wù)集成這些機(jī)制的成本。這種服務(wù)就是Api網(wǎng)關(guān)(http://blog.csdn.net/pzxwhc/article/details/49873623),可以選擇自己實(shí)現(xiàn),也可以使用開源軟件實(shí)現(xiàn),如Kong。如下圖所示:
但是以上方案的一個(gè)問題是由于所有api請求都要經(jīng)過網(wǎng)關(guān),它很容易成為系統(tǒng)的性能瓶頸。因此,可以采取的方案是:去掉api網(wǎng)關(guān),讓業(yè)務(wù)應(yīng)用直接對接統(tǒng)一認(rèn)證中心,在基礎(chǔ)框架層面保證每個(gè)api調(diào)用都需要先通過統(tǒng)一認(rèn)證中心的認(rèn)證,這里可以采取緩存認(rèn)證結(jié)果的方式避免對統(tǒng)一認(rèn)證中心產(chǎn)生過大的請求壓力。
業(yè)務(wù)應(yīng)用和后端基礎(chǔ)框架
業(yè)務(wù)應(yīng)用分為:在線業(yè)務(wù)應(yīng)用和內(nèi)部業(yè)務(wù)應(yīng)用。
在線業(yè)務(wù)應(yīng)用:直接面向互聯(lián)網(wǎng)用戶的應(yīng)用、接口等,典型的特點(diǎn)就是:請求量大、高并發(fā)、高可用、對故障的容忍度低。
內(nèi)部業(yè)務(wù)應(yīng)用:這個(gè)是面向公司內(nèi)部的應(yīng)用。比如,內(nèi)部數(shù)據(jù)管理平臺(tái)、廣告投放平臺(tái)等。相比起在線業(yè)務(wù)應(yīng)用,其特點(diǎn): 數(shù)據(jù)保密性高、壓力小、并發(fā)量小、允許故障的發(fā)生。
業(yè)務(wù)應(yīng)用基于后端的基礎(chǔ)框架開發(fā),針對Java后端來說,應(yīng)該有的幾個(gè)框架如下:
MVC框架:從十年前流行的Struts1、2到現(xiàn)在最為推崇的SpringMVC、Jersey以及國人開發(fā)的JFinal、阿里的WebX等等,這些框架尤其是后面流行的這些都是各有千秋的。選型的主要因素是看你的團(tuán)隊(duì)是否有一個(gè)對某框架能夠做二次開發(fā)、定制的人在。很多時(shí)候,針對這些通用的框架,你是需要做一些特定的開發(fā)才能滿足特定的需求的。比如,很多團(tuán)隊(duì)傳遞參數(shù)使用的都是UnderScore的命名法(下劃線連接單詞),但是Java中確是使用LowCamel命名的。對于SpringMVC,可以通過注解的alias來指定,但這樣需要對每一個(gè)參數(shù)都要指定alias有點(diǎn)效率太低,此外ModelAttribute也不支持別名,更好的方式是在框架層面統(tǒng)一對參數(shù)做Camel命名的轉(zhuǎn)換達(dá)到目的。
IOC框架:ioc帶來的好處無須多言。目前Java中最為流行的Spring自誕生就天然支持IOC。
ORM框架:MyBatis是目前最為流行的orm框架。此外,Spring ORM中提供的JdbcTemplate也很不錯(cuò)。當(dāng)然,對于分庫分表、主從分離這些需求,一般就需要實(shí)現(xiàn)自己的ORM框架來支持了,像阿里的tddl。此外,為了在服務(wù)層面統(tǒng)一解決分庫分表、主從分離、主備切換、緩存、故障恢復(fù)等問題,很多公司都是有自己的數(shù)據(jù)庫中間件的,比如阿里的Cobar、360的Atlas、網(wǎng)易的DDB,還有官方提供的MySQL Proxy以及開源的MyCat、kingshard和收費(fèi)的oneproxy。目前,線上有一定規(guī)模使用的應(yīng)該是kingshard,當(dāng)然如果不缺錢也可以上oneproxy。
緩存框架:緩存框架主要指的是對redis、memcached這些緩存服務(wù)器的操作統(tǒng)一封裝,一般使用Spring的RedisTemplate即可,也可以使用jedis做自己的封裝,支持客戶端分布式方案、主從等。
JavaEE應(yīng)用性能檢測框架:對于線上的JavaEE應(yīng)用,需要有一個(gè)統(tǒng)一的框架集成到每一個(gè)業(yè)務(wù)中檢測每一個(gè)請求、方法調(diào)用、jdbc連接、redis連接等的耗時(shí)、狀態(tài)等。jwebap是一個(gè)可以使用的性能檢測工具,但由于其已經(jīng)很多年沒有更新,有可能的話建議基于此項(xiàng)目做二次開發(fā)。
一般來說,以上幾個(gè)框架即可以完成一個(gè)后端應(yīng)用的雛形。
對于這些框架來說,最為關(guān)鍵的是根據(jù)團(tuán)隊(duì)技術(shù)構(gòu)成選擇最合適的,有能力開發(fā)自己的框架則更好。此外,這里需要提供一個(gè)后端應(yīng)用的模板或生成工具(如maven的archetype)給團(tuán)隊(duì)成員使用,可以讓大家在開發(fā)新的應(yīng)用的時(shí)候,迅速的生成雛形應(yīng)用,而無需再做一些框架搭建的重復(fù)性勞動(dòng)。
緩存、數(shù)據(jù)庫、搜索引擎、消息隊(duì)列
緩存、數(shù)據(jù)庫、搜索引擎、消息隊(duì)列這四者都是應(yīng)用依賴的后端基礎(chǔ)服務(wù),他們的性能直接影響到了應(yīng)用的整體性能,有時(shí)候你代碼寫的再好也許就是因?yàn)檫@些服務(wù)導(dǎo)致應(yīng)用性能無法提升上去。
緩存
如緩存五分鐘法則所講:如果一個(gè)數(shù)據(jù)頻繁被訪問,那么就應(yīng)該放內(nèi)存中。這里的緩存就是一種讀寫效率都非常高的存儲(chǔ)方案,能夠應(yīng)對高并發(fā)的訪問請求,通常情況下也不需要持久化的保證。但相對其他存儲(chǔ)來說,緩存一般是基于內(nèi)存的,成本比較昂貴,因此不能濫用。
緩存可以分為:本地緩存和分布式緩存。
本地緩存:主要指的是內(nèi)存中的緩存機(jī)制。在Java中,Google Guava中就提供了本地緩存的實(shí)現(xiàn)機(jī)制。當(dāng)然使用java的ConncurrentHashMap你也可以實(shí)現(xiàn)自己的本地緩存方案。
分布式緩存:指的單獨(dú)的緩存服務(wù)。幾年前比較流行的是memcached,但其只是一個(gè)KV的存儲(chǔ),支持的數(shù)據(jù)結(jié)構(gòu)太少。現(xiàn)在最為流行的就是Redis,能夠支持豐富的數(shù)據(jù)結(jié)構(gòu),基于事件驅(qū)動(dòng)的單線程非阻塞IO也能夠應(yīng)對高并發(fā)的場景。集群方案除了官方的redis cluster, 目前比較流行的還有豌豆莢的codis、twitter的twemproxy。
對于緩存的使用,需要注意以下幾點(diǎn):
緩存的失效機(jī)制:當(dāng)給某一個(gè)key設(shè)置了有效期,那么緩存何時(shí)對此key進(jìn)行刪除呢?一般來說會(huì)有以下幾種方式:
守護(hù)進(jìn)程定時(shí)去掃描key,找到已經(jīng)失效的key,然后刪除
讀取key的時(shí)候先去判斷key是否失效,如果失效則刪除并返回空。
緩存的淘汰機(jī)制:是當(dāng)緩存內(nèi)存達(dá)到上限時(shí)如何刪除緩存中的key。Redis提供了以下數(shù)據(jù)淘汰策略:
對于其具體的實(shí)現(xiàn)機(jī)制,可以參考《Redis設(shè)計(jì)與實(shí)現(xiàn)》一書
volatile-lru:從已設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰
volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰
volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰
allkeys-lru:從數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰
allkeys-random:從數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰
no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)
緩存的更新機(jī)制: 通常來說有四種方式:Cache aside, Read through, Write through, Write behind caching,具體的可見陳皓大神的這篇總結(jié):緩存更新的套路。
緩存的服務(wù)過載保護(hù):緩存的服務(wù)過載指的是由于緩存失效,而引起后端服務(wù)的壓力驟增,進(jìn)一步產(chǎn)生雪崩效應(yīng)。這個(gè)現(xiàn)象和緩存更新是相關(guān)的,采取何種策略在緩存失效的時(shí)候去更新緩存直接決定了服務(wù)過載的保護(hù)機(jī)制。通常的分為客戶端和服務(wù)端的應(yīng)對方案。前者的方案有:基于超時(shí)的簡單模式、基于超時(shí)的常規(guī)模式、基于刷新的簡單模式、基于刷新的常規(guī)模式、基于刷新的續(xù)費(fèi)模式。后者的方案則是很常見的流量控制和服務(wù)降級。具體的可以看美團(tuán)技術(shù)團(tuán)隊(duì)總結(jié)的這篇文章:Cache應(yīng)用中的服務(wù)過載案例研究。
數(shù)據(jù)庫
數(shù)據(jù)庫是后端開發(fā)中非常常見的一個(gè)服務(wù)組件。對于數(shù)據(jù)庫的選型,要根據(jù)業(yè)務(wù)的特點(diǎn)和數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)來決定。
從存儲(chǔ)介質(zhì)上,數(shù)據(jù)庫可以分為:
內(nèi)存數(shù)據(jù)庫: 數(shù)據(jù)主要存儲(chǔ)在內(nèi)存中,同時(shí)也可以采取措施對數(shù)據(jù)進(jìn)行持久化到硬盤中。如Redis、H2DB的內(nèi)存模式。對于這種數(shù)據(jù)庫,由于內(nèi)存成本昂貴,因此一定要做好存儲(chǔ)的量化分析、容量預(yù)估,防止內(nèi)存不足造成服務(wù)不可用。
硬盤數(shù)據(jù)庫:數(shù)據(jù)存儲(chǔ)在硬盤上的這種數(shù)據(jù)庫是最為常見的。MySQL、Oracle、Postgresql、HBASE、H2DB、SqlLite等等都是硬盤數(shù)據(jù)庫。此外,SSDB是基于SSD硬盤的KV數(shù)據(jù)庫,支持的數(shù)據(jù)接口很豐富,是Redis的另外一個(gè)選擇。
從存儲(chǔ)數(shù)據(jù)類型、數(shù)據(jù)模式上,數(shù)據(jù)庫可以分為:
關(guān)系型數(shù)據(jù)庫:MySQL、Oracle、Postgresql都是關(guān)系型數(shù)據(jù)庫的,是采用關(guān)系模型(關(guān)系模型指的就是二維表格模型,而一個(gè)關(guān)系型數(shù)據(jù)庫就是由二維表及其之間的聯(lián)系所組成的一個(gè)數(shù)據(jù)組織)來組織數(shù)據(jù)的數(shù)據(jù)庫。
非關(guān)系型數(shù)據(jù)庫:非關(guān)系型數(shù)據(jù)庫是相對關(guān)系型數(shù)據(jù)庫來講的。以鍵值對存儲(chǔ),且結(jié)構(gòu)不固定,每一個(gè)元組可以有不一樣的字段,每個(gè)元組可以根據(jù)需要增加一些自己的鍵值對,這樣就不會(huì)局限于固定的結(jié)構(gòu),可以減少一些時(shí)間和空間的開銷。但是,其沒有關(guān)系型數(shù)據(jù)庫那種嚴(yán)格的數(shù)據(jù)模式,并不適合復(fù)雜的查詢以及需要強(qiáng)事務(wù)管理的業(yè)務(wù)。非關(guān)系型數(shù)據(jù)庫又可以分為:
KV數(shù)據(jù)庫:主要以(key,value)鍵值對存儲(chǔ)數(shù)據(jù)的數(shù)據(jù)庫。以Redis、RocksDB(levelDB)、SSDB為代表。
文檔數(shù)據(jù)庫:總體形式上也是鍵值對的形式,但是值里面又可以有各種數(shù)據(jù)結(jié)構(gòu):數(shù)組、鍵值對、字符串等等。以mongodb、couchdb為代表。
列數(shù)據(jù)庫:也叫作稀疏大數(shù)據(jù)庫,一般是用來存儲(chǔ)海量數(shù)據(jù)的。相對于行數(shù)據(jù)庫,這種數(shù)據(jù)庫是以列為單位存儲(chǔ)數(shù)據(jù)在介質(zhì)上的。以Hbase、Cassendra為代表。
和數(shù)據(jù)庫相關(guān)的一個(gè)很重要的就是數(shù)據(jù)庫的索引。有一種說法是:“掌握了索引就等于掌握了數(shù)據(jù)庫”。暫且不去評判此說法是否真的準(zhǔn)確,但索引的確關(guān)系著數(shù)據(jù)庫的讀寫性能。需要對數(shù)據(jù)庫的索引原理做到足夠的了解才能更好的使用各種數(shù)據(jù)庫。通常來說,Mysql、Oracle、Mongodb這些都是使用的B樹作為索引,是考慮到傳統(tǒng)硬盤的特點(diǎn)后兼顧了讀寫性能以及范圍查找需求的選擇,而Hbase用得LSM則是為了提高寫性能對讀性能做了犧牲。
搜索引擎
搜索引擎也是后端應(yīng)用中一個(gè)很關(guān)鍵的組件,尤其是對內(nèi)容類、電商類的應(yīng)用,通過關(guān)鍵詞、關(guān)鍵字搜索內(nèi)容、商品是一個(gè)很常見的用戶場景。比較成熟的開源搜索引擎有Solr和Elasticsearch,很多中小型互聯(lián)網(wǎng)公司搜索引擎都是基于這兩個(gè)開源系統(tǒng)搭建的。它們都是基于Lucence來實(shí)現(xiàn)的,不同之處主要在于termIndex的存儲(chǔ)、分布式架構(gòu)的支持等等。
對于搜索引擎的使用,從系統(tǒng)熟悉、服務(wù)搭建、功能定制,需要花費(fèi)較長時(shí)間。在這個(gè)過程中,需要注意以下問題:
搜索引擎與公司現(xiàn)有數(shù)據(jù)系統(tǒng)的集成。現(xiàn)有的持久化、供搜索的數(shù)據(jù)的載體是什么, 如何讓搜索引擎在全量和增量建索引過程中無縫集成原來的數(shù)據(jù)載體,才能發(fā)揮搜索引擎自身的實(shí)時(shí)性, 水平擴(kuò)展性(性能與容量和機(jī)器數(shù)量成正比)等優(yōu)勢。
和數(shù)據(jù)庫一樣,對搜索引擎的索引機(jī)制也需要做到深入的了解。
更為詳細(xì)的對于搜索引擎的工程化實(shí)踐可以參考有贊工程師的這篇文章:有贊搜索引擎實(shí)踐(工程篇)
另外,搜索引擎還可以用在數(shù)據(jù)的多維分析上,就是GrowingIO、MixPanel中的可以任意維度查詢數(shù)據(jù)報(bào)表的功能。當(dāng)然,druid也許是一個(gè)更好的實(shí)現(xiàn)多維分析的方案,官方也有其與es的比較:http://druid.io/docs/latest/comparisons/druid-vs-elasticsearch.html。
消息隊(duì)列
軟件的組織結(jié)構(gòu),從開始的面向組件到SOA、SAAS是一個(gè)逐漸演變的過程。而到了今天微服務(wù)盛行的時(shí)代,你都不好意思說自己的系統(tǒng)只是單一的一個(gè)系統(tǒng)而沒有解耦成一個(gè)個(gè)service。當(dāng)然,小的系統(tǒng)的確沒有拆分的必要性,但一個(gè)復(fù)雜的系統(tǒng)拆成一個(gè)個(gè)service做微服務(wù)架構(gòu)確實(shí)是不得不做的事情。
那么問題就來了,service之間的通信如何來做呢?使用什么協(xié)議?通過什么方式調(diào)用?都是需要考慮的問題。
先拋開協(xié)議不談,service之間的調(diào)用方式可以分為同步調(diào)用以及異步調(diào)用。同步調(diào)用的方式無需多說,那么異步調(diào)用是怎么進(jìn)行的呢?一種很常見的方式就是使用消息隊(duì)列,調(diào)用方把請求放到隊(duì)列中即可返回,然后等待服務(wù)提供方去隊(duì)列中去獲取請求進(jìn)行處理,然后把結(jié)果返回給調(diào)用方即可(可以通過回調(diào))。
異步調(diào)用就是消息中間件一個(gè)非常常見的應(yīng)用場景。此外,消息隊(duì)列的應(yīng)用場景還有以下:
解耦:一個(gè)事務(wù),只關(guān)心核心的流程,需要依賴其他系統(tǒng)但不那么重要的事情,有通知即可,無須等待結(jié)果。
最終一致性:指的是兩個(gè)系統(tǒng)的狀態(tài)保持一致,要么都成功,要么都失敗,可以有一定的延遲,只要最終達(dá)到一致性即可。
廣播:這是消息隊(duì)列最基本的功能。生產(chǎn)者只需要發(fā)布消息,無須關(guān)心有哪些訂閱者來消費(fèi)消息。
錯(cuò)峰與流控:當(dāng)上下游系統(tǒng)處理能力不同的時(shí)候就需要類似消息隊(duì)列的方式做為緩沖區(qū)來隔開兩個(gè)系統(tǒng)。
目前主流的消息隊(duì)列軟件,主要有以下幾種:
ActiveMQ:Java中最為簡單的消息隊(duì)列,是對JMS的實(shí)現(xiàn),沒有規(guī)定消息的順序、安全、重發(fā)等特性。
RabbitMQ:是對AMQP協(xié)議的實(shí)現(xiàn),對于消息的順序性、安全、重發(fā)等都做了很好的支持。比較適合不允許數(shù)據(jù)丟失、有事務(wù)需求的業(yè)務(wù)場景下的消息傳輸。
Kafka:是基于Log的消息隊(duì)列,底層依賴于文件的順序讀取,是append-only的。適合對數(shù)據(jù)丟失不敏感、強(qiáng)調(diào)性能的一些海量日志傳輸場景中。是最近幾年大數(shù)據(jù)領(lǐng)域很火的一個(gè)技術(shù)。
ZeroMQ:是一個(gè)網(wǎng)絡(luò)編程的Pattern庫,將常見的網(wǎng)絡(luò)請求形式(分組管理,鏈接管理,發(fā)布訂閱等)模式化、組件化,簡而言之socket之上、MQ之下。對于MQ來說,網(wǎng)絡(luò)傳輸只是它的一部分,更多需要處理的是消息存儲(chǔ)、路由、Broker服務(wù)發(fā)現(xiàn)和查找、事務(wù)、消費(fèi)模式(ack、重投等)、集群服務(wù)等。
文件存儲(chǔ)
不管是業(yè)務(wù)應(yīng)用、依賴的后端服務(wù)還是其他的各種服務(wù),最終還是要依賴于底層文件存儲(chǔ)的。通常來說,文件存儲(chǔ)需要滿足的特性有:可靠性、容災(zāi)性、穩(wěn)定性,即要保證存儲(chǔ)的數(shù)據(jù)不會(huì)輕易丟失,即使發(fā)生故障也能夠有回滾方案,也要保證高可用率。在底層可以采用傳統(tǒng)的RAID作為解決方案,再上一層,目前hadoop的hdfs則是最為普遍的分布式文件存儲(chǔ)方案,當(dāng)然還有NFS、Samba這種共享文件系統(tǒng)也提供了簡單的分布式存儲(chǔ)的特性。
此外,如果文件存儲(chǔ)確實(shí)成為了應(yīng)用的瓶頸或者必須提高文件存儲(chǔ)的性能從而提升整個(gè)系統(tǒng)的性能時(shí),那么最為直接和簡單的做法就是拋棄傳統(tǒng)機(jī)械硬盤,用SSD硬盤替代。像現(xiàn)在很多公司在解決業(yè)務(wù)性能問題的時(shí)候,最終的關(guān)鍵點(diǎn)往往就是SSD。這也是用錢換取時(shí)間和人力成本最直接和最有效的方式。在數(shù)據(jù)庫部分描述的SSDB就是對LevelDB封裝之后,利用SSDB的特性的一種高性能KV數(shù)據(jù)庫。
至于HDFS,如果要使用上面的數(shù)據(jù),是需要通過hadoop的。類似xx on yarn的一些技術(shù)就是將非hadoop技術(shù)跑在hdfs上的解決方案(當(dāng)然也是為了使用MR)。
統(tǒng)一認(rèn)證中心
統(tǒng)一認(rèn)證中心,主要是對app用戶、內(nèi)部用戶、app等的認(rèn)證服務(wù),包括
用戶的注冊、登錄驗(yàn)證、token鑒權(quán)
內(nèi)部信息系統(tǒng)用戶的管理和登錄鑒權(quán)
App的管理,包括app的secret生成,app信息的驗(yàn)證(如驗(yàn)證接口簽名)等。
之所以需要統(tǒng)一認(rèn)證中心,就是為了能夠集中對這些所有app都會(huì)用到的信息進(jìn)行管理,也給所有應(yīng)用提供統(tǒng)一的認(rèn)證服務(wù)。尤其是在有很多業(yè)務(wù)需要共享用戶數(shù)據(jù)的時(shí)候,構(gòu)建一個(gè)統(tǒng)一認(rèn)證中心是非常必要的。此外,通過統(tǒng)一認(rèn)證中心構(gòu)建移動(dòng)app的單點(diǎn)登錄也是水到渠成的事情(模仿web的機(jī)制,將認(rèn)證后的信息加密存儲(chǔ)到本地磁盤中供多個(gè)app使用)。
單點(diǎn)登錄系統(tǒng)
目前很多大的在線web網(wǎng)站都是有單點(diǎn)登錄系統(tǒng)的,通俗的來說就是只需要一次用戶登錄,就能夠進(jìn)入多個(gè)業(yè)務(wù)應(yīng)用(權(quán)限可以不相同),非常方便用戶的操作。而在移動(dòng)互聯(lián)網(wǎng)公司中,內(nèi)部的各種管理、信息系統(tǒng)同樣也需要單點(diǎn)登錄系統(tǒng)。目前,比較成熟的、用的最多的單點(diǎn)登錄系統(tǒng)應(yīng)該是耶魯大學(xué)開源的CAS, 可以基于https://github.com/apereo/cas/tree/master/cas-server-webapp來定制開發(fā)的。此外,國人開源的kisso的這個(gè)也不錯(cuò)。基本上,單點(diǎn)登錄的原理都類似下圖所示:
統(tǒng)一配置中心
在Java后端應(yīng)用中,一種讀寫配置比較通用的方式就是將配置文件寫在propeties、yaml、HCON文件中,修改的時(shí)候只需要更新文件重新部署即可,可以做到不牽扯代碼層面改動(dòng)的目的。統(tǒng)一配置中心,則是基于這種方式之上的統(tǒng)一對所有業(yè)務(wù)或者基礎(chǔ)后端服務(wù)的相關(guān)配置文件進(jìn)行管理的統(tǒng)一服務(wù), 具有以下特性:
能夠在線動(dòng)態(tài)修改配置文件并生效
配置文件可以區(qū)分環(huán)境(開發(fā)、測試、生產(chǎn)等)
使用方便: 在java中可以通過注解、xml配置的方式引入相關(guān)配置
disconf是可以在生產(chǎn)環(huán)境使用的一個(gè)方案,也可能根據(jù)自己的需求開發(fā)自己的配置中心(可以選擇zookeeper作為配置存儲(chǔ))。
服務(wù)治理框架
對于外部API調(diào)用或者客戶端對后端api的訪問,可以使用http協(xié)議或者說restful(當(dāng)然也可以直接通過最原始的socket來調(diào)用)。但對于內(nèi)部服務(wù)間的調(diào)用,一般都是通過RPC機(jī)制來調(diào)用的。目前主流的RPC協(xié)議有:
RMI
Hessian
Thrift
Dubbo
這些RPC協(xié)議各有優(yōu)劣點(diǎn),需要針對業(yè)務(wù)需求做出相應(yīng)的最好的選擇。
這樣,當(dāng)你的系統(tǒng)服務(wù)在逐漸增多,RPC調(diào)用鏈越來越復(fù)雜,很多情況下,需要不停的更新文檔來維護(hù)這些調(diào)用關(guān)系。一個(gè)對這些服務(wù)進(jìn)行管理的框架可以大大節(jié)省因此帶來的繁瑣的人力工作。
傳統(tǒng)的ESB(企業(yè)服務(wù)總線)本質(zhì)就是一個(gè)服務(wù)治理方案,但esb作為一種proxy的角色存在于client和server之間,所有請求都需要經(jīng)過esb,使得esb很容易成為性能瓶頸。因此,基于傳統(tǒng)的esb,更好的一種設(shè)計(jì)如下圖所示:
如圖,以配置中心為樞紐,調(diào)用關(guān)系只存在于client和提供服務(wù)的server之間,就避免了傳統(tǒng)esb的性能瓶頸問題。對于這種設(shè)計(jì),esb應(yīng)該支持的特性如下:
服務(wù)提供方的注冊、管理
服務(wù)消費(fèi)者的注冊、管理
服務(wù)的版本管理、負(fù)載均衡、流量控制、服務(wù)降級等
服務(wù)的容錯(cuò)、熔斷等
阿里開源的dubbo則對以上做了很好的實(shí)現(xiàn),也是目前很多公司都在使用的方案。但由于某些原因,dubbo現(xiàn)已不再維護(hù),推薦大家使用當(dāng)當(dāng)后來維護(hù)的dubbox。
統(tǒng)一調(diào)度中心
在很多業(yè)務(wù)中,定時(shí)調(diào)度是一個(gè)非常普遍的場景,比如定時(shí)去抓取數(shù)據(jù)、定時(shí)刷新訂單的狀態(tài)等。通常的做法就是針對各自的業(yè)務(wù)依賴Linux的cron機(jī)制或者java中的quartz。統(tǒng)一調(diào)度中心則是對所有的調(diào)度任務(wù)進(jìn)行管理,這樣能夠統(tǒng)一對調(diào)度集群進(jìn)行調(diào)優(yōu)、擴(kuò)展、任務(wù)管理等。azkaban和oozie是hadoop的流式工作管理引擎,也可以作為統(tǒng)一調(diào)度中心來使用。當(dāng)然,你也可以使用cron或者quartz來實(shí)現(xiàn)自己的統(tǒng)一調(diào)度中心。
根據(jù)cron表達(dá)式調(diào)度任務(wù)
動(dòng)態(tài)修改、停止、刪除任務(wù)
支持任務(wù)工作流:比如一個(gè)任務(wù)完成之后再執(zhí)行下一個(gè)任務(wù)
任務(wù)支持腳本、代碼、url等多種形式
任務(wù)執(zhí)行的日志記錄、故障報(bào)警
對于Java的quartz這里需要說明一下:這個(gè)quartz需要和spring quartz區(qū)分,后者是spring對quartz框架的簡單實(shí)現(xiàn)也是目前使用的最多的一種調(diào)度方式。但是,其并沒有做高可用集群的支持。而quartz雖然有集群的支持,但是配置起來非常復(fù)雜。現(xiàn)在很多方案都是使用zookeeper來實(shí)現(xiàn)spring quartz集群的。這里有一個(gè)國人開源的uncode-shcedule對此實(shí)現(xiàn)的還不錯(cuò),可以根據(jù)自己的業(yè)務(wù)需求做二次開發(fā)。
統(tǒng)一日志服務(wù)
日志是開發(fā)過程必不可少的東西。有時(shí)候,打印日志的時(shí)機(jī)、技巧是很能體現(xiàn)出工程師編碼水平的。畢竟,日志是線上服務(wù)能夠定位、排查異常最為直接的信息。
通常的,將日志分散在各個(gè)業(yè)務(wù)中非常不方便對問題的管理和排查。統(tǒng)一日志服務(wù)則使用單獨(dú)的日志服務(wù)器記錄日志,各個(gè)業(yè)務(wù)通過統(tǒng)一的日志框架將日志輸出到日志服務(wù)器上。
可以通過實(shí)現(xiàn)log4j后者logback的appender來實(shí)現(xiàn)統(tǒng)一日志框架,然后通過RPC調(diào)用將日志打印到日志服務(wù)器上。
數(shù)據(jù)基礎(chǔ)設(shè)施
數(shù)據(jù)是最近幾年非常火的一個(gè)領(lǐng)域。從《精益數(shù)據(jù)分析》到《增長黑客》,都是在強(qiáng)調(diào)數(shù)據(jù)的非凡作用。很多公司也都在通過數(shù)據(jù)推動(dòng)產(chǎn)品設(shè)計(jì)、市場運(yùn)營、研發(fā)等。詳細(xì)的可見之前的一篇《數(shù)據(jù)雜談》,對數(shù)據(jù)相關(guān)的東西做過一些總結(jié)。這里需要說明的一點(diǎn)是,只有當(dāng)你的數(shù)據(jù)規(guī)模真的到了單機(jī)無法處理的規(guī)模才應(yīng)該上大數(shù)據(jù)相關(guān)技術(shù),千萬不要為了大數(shù)據(jù)而大數(shù)據(jù)。很多情況下使用單機(jī)程序+mysql就能解決的問題非得上hadoop即浪費(fèi)時(shí)間又浪費(fèi)人力。
這里需要補(bǔ)充一點(diǎn)的是,對于很多公司,尤其是離線業(yè)務(wù)并沒有那么密集的公司,在很多情況下大數(shù)據(jù)集群的資源是被浪費(fèi)的。因此誕生了xx on yarn一系列技術(shù)讓非hadoop系的技術(shù)可以利用大數(shù)據(jù)集群的資源,能夠大大提高資源的利用率,如Docker on yarn(Hulu的VoidBox)。
數(shù)據(jù)高速公路
接著上面講的統(tǒng)一日志服務(wù),其輸出的日志最終是變成數(shù)據(jù)到數(shù)據(jù)高速公路上供后續(xù)的數(shù)據(jù)處理程序消費(fèi)的。這中間的過程包括日志的收集、傳輸。
收集:統(tǒng)一日志服務(wù)將日志打印在日志服務(wù)上之后,需要日志收集機(jī)制將其集中起來。目前,常見的日志收集方案有:scribe、Chukwa、Kakfa和Flume。對比如下圖所示:
傳輸:通過消息隊(duì)列將數(shù)據(jù)傳輸?shù)綌?shù)據(jù)處理服務(wù)中。對于日志來說,通常選擇kafka這種消息隊(duì)列即可。
此外,這里還有一個(gè)關(guān)鍵的技術(shù)就是數(shù)據(jù)庫和數(shù)據(jù)倉庫間的數(shù)據(jù)同步問題,即將需要分析的數(shù)據(jù)從數(shù)據(jù)庫中同步到諸如hive這種數(shù)據(jù)倉庫時(shí)使用的方案。比較簡單的、用的也比較多的可以使用sqoop進(jìn)行基于時(shí)間戳的數(shù)據(jù)同步,此外,阿里開源的canal實(shí)現(xiàn)了基于binlog增量同步,更加適合通用的同步場景,但是基于canal你還是需要做不少的業(yè)務(wù)開發(fā)工作的。推薦另一款國人開源的MySQL-Binlog,原理和canal類似,默認(rèn)提供了任務(wù)的后臺(tái)管理功能,只需要實(shí)現(xiàn)接收到binlog后的處理邏輯即可。
離線數(shù)據(jù)分析
離線數(shù)據(jù)分析是可以有延遲的,一般針對是非實(shí)時(shí)需求的數(shù)據(jù)分析工作,產(chǎn)生的也是T-1的報(bào)表。目前最常用的離線數(shù)據(jù)分析技術(shù)除了hadoop還有spark。相比hadoop,spark性能上有很大優(yōu)勢,當(dāng)然對硬件資源要求也高。
對于hadoop,傳統(tǒng)的MR編寫很復(fù)雜,也不利于維護(hù),可以選擇使用hive來用sql替代編寫mr,但是前提務(wù)必要對hive的原理做到了解。可以參見美團(tuán)的這篇博文來學(xué)習(xí):Hive SQL的編譯過程。而對于spark,也有類似hive的spark sql。
此外,對于離線數(shù)據(jù)分析,還有一個(gè)很關(guān)鍵的就是數(shù)據(jù)傾斜問題。所謂數(shù)據(jù)傾斜指的是region數(shù)據(jù)分布不均,造成有的結(jié)點(diǎn)負(fù)載很低,而有些卻負(fù)載很高,從而影響整體的性能。因此,處理好數(shù)據(jù)傾斜問題對于數(shù)據(jù)處理是很關(guān)鍵的。對于hive的數(shù)據(jù)傾斜,可見:hive大數(shù)據(jù)傾斜總結(jié)。對于spark的傾斜問題,可見:Spark性能優(yōu)化指南——高級篇。
實(shí)時(shí)數(shù)據(jù)分析
相對于離線數(shù)據(jù)分析,實(shí)時(shí)數(shù)據(jù)分析也叫在線數(shù)據(jù)分析,針對的是對數(shù)據(jù)有實(shí)時(shí)要求的業(yè)務(wù)場景,如廣告結(jié)算、訂單結(jié)算等。目前,比較成熟的實(shí)時(shí)技術(shù)有storm和spark streaming。相比起storm,spark streaming其實(shí)本質(zhì)上還是基于批量計(jì)算的。如果是對延遲很敏感的場景,還是應(yīng)該使用storm。
對于實(shí)時(shí)數(shù)據(jù)分析,需要注意的就是實(shí)時(shí)數(shù)據(jù)處理結(jié)果寫入存儲(chǔ)的時(shí)候,要考慮并發(fā)的問題,雖然對于storm的bolt程序來說不會(huì)有并發(fā)的問題,但是寫入的存儲(chǔ)介質(zhì)是會(huì)面臨多任務(wù)同時(shí)讀寫的。通常采用的方案就是采用時(shí)間窗口的方式對數(shù)據(jù)做緩沖后批量寫入。
此外,實(shí)時(shí)數(shù)據(jù)處理一般情況下都是基于增量處理的,相對于離線來說并非可靠的,一旦出現(xiàn)故障(如集群崩潰)或者數(shù)據(jù)處理失敗,是很難對數(shù)據(jù)恢復(fù)或者修復(fù)異常數(shù)據(jù)的。因此結(jié)合離線+實(shí)時(shí)是目前最普遍采用的數(shù)據(jù)處理方案。Lambda架構(gòu)就是一個(gè)結(jié)合離線和實(shí)時(shí)數(shù)據(jù)處理的架構(gòu)方案。
數(shù)據(jù)即席分析
離線和實(shí)時(shí)數(shù)據(jù)分析產(chǎn)生的一些報(bào)表是給數(shù)據(jù)分析師、產(chǎn)品經(jīng)理參考使用的,但是很多情況下,線上的程序并不能滿足這些需求方的需求。這時(shí)候就需要需求方自己對數(shù)據(jù)倉庫進(jìn)行查詢統(tǒng)計(jì)。針對這些需求方,SQL上手容易、易描述等特點(diǎn)決定了其可能是一個(gè)最為合適的方式。因此提供一個(gè)SQL的即席查詢工具能夠大大提高數(shù)據(jù)分析師、產(chǎn)品經(jīng)理的工作效率。Presto、Impala、Hive都是這種工具。如果想進(jìn)一步提供給需求方更加直觀的ui操作界面,可以搭建內(nèi)部的Hue。
故障監(jiān)控
對于面向用戶的線上服務(wù),發(fā)生故障是一件很嚴(yán)重的事情。因此,做好線上服務(wù)的故障檢測告警是一件非常重要的事情。可以將故障監(jiān)控分為以下兩個(gè)層面的監(jiān)控:
系統(tǒng)監(jiān)控:主要指的對主機(jī)的帶寬、cpu、內(nèi)存、硬盤、io等硬件資源的監(jiān)控。這可以使用開源的nagios、cacti等開源軟件進(jìn)行監(jiān)控。目前,市面上也有很多第三方服務(wù)能夠提供對于主機(jī)資源的監(jiān)控,如監(jiān)控寶等。對于分布式服務(wù)集群(如hadoop、storm、kafka、flume等集群)的監(jiān)控則可以使用ganglia。此外,小米開源的OpenFalcon也很不錯(cuò),涵蓋了系統(tǒng)監(jiān)控、JVM監(jiān)控等,也支持自定義的監(jiān)控機(jī)制。
業(yè)務(wù)監(jiān)控:是在主機(jī)資源層面以上的監(jiān)控,比如app的pv、uv數(shù)據(jù)異常、交易失敗等。需要業(yè)務(wù)中加入相關(guān)的監(jiān)控代碼,比如在異常拋出的地方,加一段日志記錄。
監(jiān)控還有一個(gè)關(guān)鍵的步驟就是告警。告警的方式有很多種:郵件、im、短信等。考慮到故障的重要性不同、告警的合理性、便于定位問題等因素,有以下建議:
告警日志要記錄發(fā)生故障的機(jī)器id,尤其是在集群服務(wù)中,如果沒有記錄機(jī)器id,那么對于后續(xù)的問題定位會(huì)很困難。
要對告警做聚合,不要每一個(gè)故障都單獨(dú)進(jìn)行告警,這樣會(huì)對工程師造成極大的困擾。
要對告警做等級劃分,不能對所有告警都做同樣的優(yōu)先級處理。
使用微信做為告警軟件,能夠在節(jié)省短信成本的情況下,保證告警的到達(dá)率。
故障告警之后,那么最最關(guān)鍵的就是應(yīng)對了。對于創(chuàng)業(yè)公司來說,24小時(shí)待命是必備的素質(zhì),當(dāng)遇到告警的時(shí)候,需要盡快對故障做出反應(yīng),找到問題所在,并能在可控時(shí)間內(nèi)解決問題。對于故障問題的排查,基本上都是依賴于日志的。只要日志打的合理,一般情況下是能夠很快定位到問題所在的,但是如果是分布式服務(wù),并且日志數(shù)據(jù)量特別大的情況下,如何定位日志就成為了難題。這里有幾個(gè)方案:
建立ELK(Elastic+Logstash+Kibana)日志集中分析平臺(tái),便于快速搜索、定位日志。對于ELK的介紹,可以見:使用Elasticsearch + Logstash + Kibana搭建日志集中分析平臺(tái)實(shí)踐
建立分布式請求追蹤系統(tǒng)(也可以叫全鏈路監(jiān)測系統(tǒng)),對于分布式系統(tǒng)尤其是微服務(wù)架構(gòu),能夠極大的方便在海量調(diào)用中快速定位并收集單個(gè)異常請求信息,也能快速定位一條請求鏈路的性能瓶頸。Google的Dapper、唯品會(huì)的Mercury、阿里的鷹眼、新浪的WatchMan都是類似的思路。此外,騰訊的染色日志機(jī)制本質(zhì)上也是在鏈路追蹤之上根據(jù)響應(yīng)信息做了染色機(jī)制。
以上是本人實(shí)踐的一些經(jīng)驗(yàn)。由于知識有限,難免有紕漏,敬請指出。
http://www.rowkey.me/blog/2016/08/27/server-basic-tech-stack/