陳皓:我做系統(tǒng)架構(gòu)的一些原則
工作 20 多年了,這 20 來(lái)年看到了很多公司系統(tǒng)架構(gòu),也看到了很多問(wèn)題,在跟這些公司進(jìn)行交流和討論的時(shí)候,包括進(jìn)行實(shí)施和方案比較的時(shí)候,都有很多各種方案的比較和妥協(xié),因?yàn)橄嚓P(guān)的經(jīng)歷越來(lái)越多,所以,逐漸形成了自己的邏輯和方法論。今天,想寫(xiě)下這篇文章,把我的這些個(gè)人的經(jīng)驗(yàn)和想法總結(jié)下來(lái),希望能夠讓更多的人可以參考和借鑒,并能夠做出更好的架構(gòu)來(lái)。另外,我的這些思維方式和原則都針對(duì)于現(xiàn)有市面上眾多不合理的架構(gòu)和方案,所以,也算是一種“糾正”……(注意,這篇文章所說(shuō)的這些架構(gòu)上的原則,一般適用于相對(duì)比較復(fù)雜的業(yè)務(wù),如果只是一些簡(jiǎn)單和訪問(wèn)量不大的應(yīng)用,那么你可能會(huì)得出相反的結(jié)論)
目錄
- 原則一:關(guān)注于真正的收益而不是技術(shù)本身
- 原則二:以應(yīng)用服務(wù)和 API 為視角,而不是以資源和技術(shù)為視角
- 原則三:選擇最主流和成熟的技術(shù)
- 原則四:完備性會(huì)比性能更重要
- 原則五:制定并遵循符從標(biāo)準(zhǔn)、規(guī)范和最佳實(shí)踐
- 原則六:重視架構(gòu)擴(kuò)展性和可運(yùn)維性
- 原則七:對(duì)控制邏輯進(jìn)行全面收口
- 原則八:不要遷就老舊系統(tǒng)的技術(shù)債務(wù)
- 原則九:不要依賴自己的經(jīng)驗(yàn),要依賴于數(shù)據(jù)和學(xué)習(xí)
- 原則十:千萬(wàn)要小心 X – Y 問(wèn)題,要追問(wèn)最初的原因
- 原則十一:激進(jìn)勝于保守,創(chuàng)新與實(shí)用并不沖突
原則一:關(guān)注于真正的收益而不是技術(shù)本身
對(duì)于軟件架構(gòu)來(lái)說(shuō),我覺(jué)得第一重要的是架構(gòu)的收益,如果不說(shuō)收益,只是為了技術(shù)而技術(shù),而沒(méi)有任何意義。對(duì)于技術(shù)收益來(lái)說(shuō),我覺(jué)得下面這幾個(gè)收益是非常重要的:
- 是否可以降低技術(shù)門檻加快整個(gè)團(tuán)隊(duì)的開(kāi)發(fā)流程。能夠加快整個(gè)團(tuán)隊(duì)的工程流程,快速發(fā)布,是軟件工程一直在解決的問(wèn)題,所以,系統(tǒng)架構(gòu)需要能夠進(jìn)行并行開(kāi)發(fā),并行上線和并行運(yùn)維,而不會(huì)讓某個(gè)團(tuán)隊(duì)成為瓶頸點(diǎn)。(注:就算拖累團(tuán)隊(duì)的原因是組織構(gòu)架,也不妨礙我們做出并行的系統(tǒng)架構(gòu)設(shè)計(jì))
- 是否可以讓整個(gè)系統(tǒng)可以運(yùn)行的更穩(wěn)定。要讓整個(gè)系統(tǒng)可以運(yùn)行的更為的穩(wěn)定,提升整個(gè)系統(tǒng)的 SLA,就需要對(duì)有計(jì)劃和無(wú)計(jì)劃的停機(jī)做相應(yīng)的解決方案(參看《關(guān)于高可用的架構(gòu)》)
- 是否可以通過(guò)簡(jiǎn)化和自動(dòng)化降低成本。最高優(yōu)化的成本是人力成本,人的成本除了慢和貴,還有經(jīng)常不斷的 human error。如果不能降低人力成本,反而需要更多的人,那么這個(gè)架構(gòu)設(shè)計(jì)一定是失敗的。除此之外,是時(shí)間成本,資金成本。
如果一個(gè)系統(tǒng)架構(gòu)不能在上面三個(gè)事上起到作用,那就沒(méi)有意義了。
原則二:以應(yīng)用服務(wù)和 API 為視角,而不是以資源和技術(shù)為視角
國(guó)內(nèi)很多公司都會(huì)有很多分工,基本上都會(huì)分成運(yùn)維和開(kāi)發(fā),運(yùn)維又會(huì)分成基礎(chǔ)運(yùn)維和應(yīng)用運(yùn)維,開(kāi)發(fā)則會(huì)分成基礎(chǔ)核心開(kāi)發(fā)和業(yè)務(wù)開(kāi)發(fā)。不同的分工會(huì)導(dǎo)致完全不同的視角和出發(fā)點(diǎn)。比如,基礎(chǔ)運(yùn)維和開(kāi)發(fā)的同學(xué)更多的只是關(guān)注資源的利用率和性能,而應(yīng)用運(yùn)維和業(yè)務(wù)開(kāi)發(fā)則更多關(guān)注的是應(yīng)用和服務(wù)上的東西。這兩者本來(lái)相關(guān)無(wú)事,但是因?yàn)榉植际郊軜?gòu)的演進(jìn),導(dǎo)致有一些系統(tǒng)已經(jīng)說(shuō)不清楚是基礎(chǔ)層的還是應(yīng)用層的了,比如像服務(wù)治理上的東西,里面即有底層基礎(chǔ)技術(shù),也需要業(yè)務(wù)的同學(xué)來(lái)配合,包括 k8s 也樣,里面即有底層的如網(wǎng)絡(luò)這樣的技術(shù),也有需要業(yè)務(wù)配合的 readniess 和 liveness 這樣的健康檢查,以及業(yè)務(wù)應(yīng)用需要 configMap 等等 ……
這些東西都讓我感覺(jué)到所謂 DevOps,其實(shí)就是因?yàn)楹芏嗉夹g(shù)和組件已經(jīng)分不清是 Dev 還是 Ops 的了,所以,需要合并 Dev 和 Ops。而且,整個(gè)組織和架構(gòu)的優(yōu)化,已經(jīng)不能通過(guò)調(diào)優(yōu)單一分工或是單一組件能夠有很大提升的了。其需要有一種自頂向下的,整體規(guī)劃,統(tǒng)一設(shè)計(jì)的方式,才能做到整體的提升(可以試想一下城市交通的優(yōu)化,當(dāng)城市規(guī)模到一定程度的時(shí)候,整體的性能你是無(wú)法通過(guò)優(yōu)化幾條路或是幾條街區(qū)來(lái)完成的,你需要對(duì)整個(gè)城市做整體的功能體的規(guī)劃才可能達(dá)到整體效率的提升)。而為了做到整體的提升,需要所有的人都要有一個(gè)統(tǒng)一的視角和目標(biāo),這幾年來(lái),我覺(jué)得這個(gè)目標(biāo)就是——要站在服務(wù)和對(duì)外 API 的視角來(lái)看問(wèn)題,而不是技術(shù)和底層的角度。
原則三:選擇最主流和成熟的技術(shù)
技術(shù)選型是一件很重要的事,技術(shù)一旦選錯(cuò),那會(huì)導(dǎo)致整個(gè)架構(gòu)需要做調(diào)整,而對(duì)架構(gòu)的調(diào)整重來(lái)都不是一件簡(jiǎn)單的事,我在過(guò)去幾年內(nèi),當(dāng)系統(tǒng)越來(lái)越復(fù)雜的時(shí)候,用戶把他們的 PHP,Python, .NET,或 Node.js 的架構(gòu)完全都遷移到 Java + Go 的架構(gòu)上來(lái)的案例不斷的發(fā)生。這個(gè)過(guò)程還是非常痛苦的,但是你沒(méi)有辦法,當(dāng)你的系統(tǒng)越來(lái)越復(fù)雜,越來(lái)越大時(shí),你就再也不能在一些玩具技術(shù)上玩了,你需要的更為工業(yè)化的技術(shù)。
- 盡可能的使用更為成熟更為工業(yè)化的技術(shù)棧,而不是自己熟悉的技術(shù)棧。所謂工業(yè)化的技術(shù)棧,你可以看看大多數(shù)公司使用的技術(shù)棧,比如:互聯(lián)網(wǎng),金融,電信……等等 ,大公司會(huì)有更多的技術(shù)投入,也需要更大規(guī)模的生產(chǎn),所以,他們使用的技術(shù)通常來(lái)說(shuō)都是比較工業(yè)化的。在技術(shù)選型上,千萬(wàn)不要被——“你看某個(gè)公司也在用這個(gè)技術(shù)”,或是一些在論壇上看到的一些程序員吐槽技術(shù)的觀點(diǎn)來(lái)決定自己的技術(shù),還是看看主流大多數(shù)公司實(shí)際在用的技術(shù)棧,會(huì)更靠譜一些。
- 選擇全球流行的技術(shù),而不是中國(guó)流行的技術(shù)。技術(shù)這個(gè)東西一定是一個(gè)全球化的東西,不是一個(gè)局域化的事。所以,一定要選國(guó)際化的會(huì)更好。另外,千萬(wàn)不要被某些公司的“特別案例”騙過(guò)去了,那怕這個(gè)案例很性感,關(guān)鍵還是要看解決問(wèn)題的思路和采用的技術(shù)是否具有普世性。只有普世性的技術(shù)有更強(qiáng)的生命力。
- 盡可能的使用紅利大的主流技術(shù),而不要自己發(fā)明輪子,更不要魔改。我見(jiàn)過(guò)好些個(gè)公司魔改開(kāi)源軟件,比如有個(gè)公司同魔改 mesos,最后改著改著發(fā)現(xiàn)自己發(fā)明另一個(gè) kubernetes。我還見(jiàn)過(guò)很多公司或技術(shù)團(tuán)隊(duì)喜歡自己發(fā)明自己的專用輪子,最后都會(huì)被主流開(kāi)源軟件所取代。完全沒(méi)有必要。不重新發(fā)明輪子,不魔改,不是因?yàn)樽约杭夹g(shù)不能,而是因?yàn)椋@個(gè)世界早已不是自己干所有事的年代了,這個(gè)時(shí)代是要想盡方法跟整個(gè)產(chǎn)業(yè),整個(gè)技術(shù)社區(qū)融合和合作,這樣才會(huì)有最大的收益。那些試圖因?yàn)槟硞€(gè)特例需要自成一套的玩法,短期沒(méi)問(wèn)題,但長(zhǎng)期來(lái)說(shuō),我都不看好。
- 絕大多數(shù)情況下,如無(wú)非常特殊要求,選 Java 基本是不會(huì)錯(cuò)的。一方面,這是因?yàn)?Java 的業(yè)務(wù)開(kāi)發(fā)的生產(chǎn)力是非常好的,而且有 Spring 框架保障,代碼很難寫(xiě)爛,另外,Java 的社區(qū)太成熟了,你需要的各種架構(gòu)和技術(shù)都可以很容易獲得,技術(shù)紅利實(shí)在是太大。這種運(yùn)行在 JVM 上的語(yǔ)言有太多太多的好處了。在 Java 的技術(shù)棧上,你的架構(gòu)風(fēng)險(xiǎn)和架構(gòu)的成本(無(wú)論是人力成本,時(shí)間成本和資金成本)從長(zhǎng)期來(lái)說(shuō)都是最優(yōu)的
在我見(jiàn)過(guò)的公司中,好些公司的架構(gòu)都被技術(shù)負(fù)責(zé)人個(gè)人的喜好、擅長(zhǎng)和個(gè)人經(jīng)驗(yàn)給綁架了,完全不是從一個(gè)客觀的角度來(lái)進(jìn)行技術(shù)選型。其實(shí),從 0 到 1 的階段,你用什么樣的技術(shù)都行,如果你做一個(gè)簡(jiǎn)單的應(yīng)用,沒(méi)有事務(wù)處理沒(méi)有復(fù)雜的交易流程,比如一些論壇、社交之類的應(yīng)用,你用任何語(yǔ)言都行。但是如果有一天你的系統(tǒng)變復(fù)雜了,需要處理交易了,量也上來(lái)了,從 1 到 10,甚至從 10 到 100,你的開(kāi)發(fā)團(tuán)隊(duì)也變大了,需要構(gòu)建的系統(tǒng)越來(lái)越大,你可能會(huì)發(fā)現(xiàn)你只有一個(gè)選擇,就是 Java。想想京東從 .NET 到 Java,淘寶從 PHP 到 Java……
原則四:完備性會(huì)比性能更重要
我發(fā)現(xiàn)好些公司的架構(gòu)師做架構(gòu)的時(shí)候,首要考慮的是架構(gòu)的性能是否能夠撐得住多大多大的流量,而不是考慮系統(tǒng)的完備性和擴(kuò)展性。所以,我已經(jīng)多次見(jiàn)過(guò)這樣的案例了,一開(kāi)始直接使用 MongoDB 這樣的非關(guān)系型數(shù)據(jù)庫(kù),或是把數(shù)據(jù)直接放在 Redis 里,而直接放棄關(guān)系型數(shù)據(jù)庫(kù)的數(shù)據(jù)完備性的模型,而在后來(lái)需要在數(shù)據(jù)上進(jìn)行關(guān)系查詢的時(shí)候,發(fā)現(xiàn) NoSQL 的數(shù)據(jù)庫(kù)在 Join 上都表現(xiàn)的太差,然后就開(kāi)始各種飛線,為了不做 Join 就開(kāi)始冗余數(shù)據(jù),然而自己又維護(hù)不好冗余數(shù)據(jù)后帶來(lái)的數(shù)據(jù)一致性的問(wèn)題,導(dǎo)致數(shù)據(jù)上的各種錯(cuò)亂丟失。
所以,我給如下的一些如下的架構(gòu)原則:
- 使用最科學(xué)嚴(yán)謹(jǐn)?shù)募夹g(shù)模型為主,并以不嚴(yán)謹(jǐn)?shù)哪P妥鳛檠a(bǔ)充。對(duì)于上面那個(gè)案例來(lái)說(shuō),就是——永遠(yuǎn)使用完備支持 ACID 的關(guān)系型數(shù)據(jù)庫(kù),然后用 NoSQL 作補(bǔ)充,而不是完全放棄關(guān)系型數(shù)據(jù)庫(kù)。這里的原則就是所謂的“先緊后松”,一開(kāi)始緊了,你可以慢慢松,但是開(kāi)始松了,以后你想緊再也緊不過(guò)來(lái)了。
- 性能上的東西,總是有很多解的。我這么多年的經(jīng)歷告訴我,性能上的事,總是有解的,手段也是最多的,這個(gè)比起架構(gòu)的完備性和擴(kuò)展性來(lái)說(shuō)真的不必太過(guò)擔(dān)心。
為了追求所謂的性能,把整個(gè)系統(tǒng)的完備性丟失掉,相當(dāng)?shù)氐貌粌斒А?/p>
原則五:制定并遵循符從標(biāo)準(zhǔn)、規(guī)范和最佳實(shí)踐
這個(gè)原則是非常重要的,因?yàn)橹挥蟹麖牧藰?biāo)準(zhǔn),你的架構(gòu)才能夠有更好的擴(kuò)展性。比如:我經(jīng)常性的見(jiàn)到很多公司的系統(tǒng)既沒(méi)有符從業(yè)界標(biāo)準(zhǔn),也沒(méi)有形成自己公司的標(biāo)準(zhǔn),感覺(jué)就像一群烏合之眾一樣。最典型的例子就是 HTTP 調(diào)用的狀態(tài)返回碼。業(yè)內(nèi)給你的標(biāo)準(zhǔn)是 200 表示成功,3xx 跳轉(zhuǎn),4xx 表示調(diào)用端出錯(cuò),5xx 表示服務(wù)端出錯(cuò),我實(shí)在是不明白為什么無(wú)論成功和失敗大家都喜歡返回 200,然后在 body 里指出是否 error(前兩年我在微信公眾號(hào)里看到一個(gè)有一定名氣的互聯(lián)網(wǎng)老兵推薦使用無(wú)論正確還是出錯(cuò)都返回 200 的做法,我在后臺(tái)再三確認(rèn)后,我發(fā)現(xiàn)這樣的架構(gòu)師真是害人不淺)。這樣做最大的問(wèn)題是——監(jiān)控系統(tǒng)將在一種低效的狀態(tài)下工作。監(jiān)控系統(tǒng)需要把所有的網(wǎng)絡(luò)請(qǐng)求包打開(kāi)后才知道是否是錯(cuò)誤,而且完全不知道是調(diào)用端出錯(cuò)還是服務(wù)端出錯(cuò),于是一些像重試或熔斷這樣的控制系統(tǒng)完全不知道怎么搞(如果是 4xx 錯(cuò),那么重試或熔斷是沒(méi)有意義的,只有 5xx 才有意義)。有時(shí)候,我會(huì)有種越活越退步的感覺(jué),錯(cuò)誤碼設(shè)計(jì)這種最基本最基礎(chǔ)的東西為什么會(huì)沒(méi)有?并且一個(gè)公司會(huì)任由著大家亂來(lái)?這些基礎(chǔ)技能怎么就這樣丟掉了?
還有,我還見(jiàn)過(guò)一些公司,他們整個(gè)組織沒(méi)有一個(gè)統(tǒng)一的用戶 ID 的設(shè)計(jì),各個(gè)系統(tǒng)之間同步用戶的數(shù)據(jù)是通過(guò)用戶的身份證 ID,是的,就是現(xiàn)實(shí)世界的身份證 ID,包括在網(wǎng)關(guān)上設(shè)置的用戶白名單居然也是用身份證 ID。我對(duì)這個(gè)公司的內(nèi)的用戶隱私管理有很大的擔(dān)憂。一個(gè)企業(yè),一個(gè)組織,如果沒(méi)有標(biāo)準(zhǔn)和規(guī)范,也就會(huì)有抽象,這一定是要出各種亂子的。
下面,我羅列一些你需要注意的標(biāo)準(zhǔn)和規(guī)范(包括但不限于):
- 服務(wù)間調(diào)用的協(xié)議標(biāo)準(zhǔn)和規(guī)范。這其中包括 Restful API 路徑, HTTP 方法、狀態(tài)碼、標(biāo)準(zhǔn)頭、自定義頭等,返回?cái)?shù)據(jù) JSon Scheme……等。
- 一些命名的標(biāo)準(zhǔn)和規(guī)范。這其中包括如:用戶 ID,服務(wù)名、標(biāo)簽名、狀態(tài)名、錯(cuò)誤碼、消息、數(shù)據(jù)庫(kù)……等等
- 日志和監(jiān)控的規(guī)范。這其中包括:日志格式,監(jiān)控?cái)?shù)據(jù),采樣要求,報(bào)警……等等
- 配置上的規(guī)范。這其中包括:操作系統(tǒng)配置、中間件配置,軟件包……等等
- 中間件使用的規(guī)范。數(shù)據(jù)庫(kù),緩存、消息隊(duì)列……等等
- 軟件和開(kāi)發(fā)庫(kù)版本統(tǒng)一。整個(gè)組織架構(gòu)內(nèi),軟件或開(kāi)發(fā)庫(kù)的版本最好每年都升一次級(jí),然后在各團(tuán)隊(duì)內(nèi)統(tǒng)一。
這里重要說(shuō)一下兩個(gè)事:
- Restful API 的規(guī)范。我覺(jué)得是非常重要的,這里給兩個(gè)我覺(jué)得寫(xiě)得最好的參考:Paypal 和 Microsoft 。Restful API 有一個(gè)標(biāo)準(zhǔn)和規(guī)范最大的好處就是監(jiān)視可以很容易地做各種統(tǒng)計(jì)分析,控制系統(tǒng)可以很容器的做流量編排和調(diào)度。
- 另一個(gè)是服務(wù)調(diào)用鏈追蹤。對(duì)于服務(wù)調(diào)用鏈追蹤來(lái)說(shuō),基本上都是參考于 Google Dapper 這篇論文,目前有很多的實(shí)現(xiàn),最嚴(yán)格的實(shí)現(xiàn)是 Zipkin,這也是 Spring Cloud Sleuth 的底層實(shí)現(xiàn)。Zipkin 貼近 Google Dapper 論文的好處在于——無(wú)狀態(tài),快速地把 Span 發(fā)出來(lái),不消耗服務(wù)應(yīng)用側(cè)的內(nèi)存和 CPU。這意味著,監(jiān)控系統(tǒng)寧可自己死了也不能干擾實(shí)際應(yīng)用。
- 軟件升級(jí)。我發(fā)現(xiàn)很多公司包括 BAT,他們完全沒(méi)有軟件升級(jí)的活動(dòng),全靠開(kāi)發(fā)人員自發(fā)。然而,這種成體系的活動(dòng),是永遠(yuǎn)不可能靠大的自發(fā)形成的。一個(gè)公司至少一年要有一次軟件版本升級(jí)的 review,然后形成軟件版本的統(tǒng)一和一致,這樣會(huì)極太簡(jiǎn)化系統(tǒng)架構(gòu)的復(fù)雜度。
原則六:重視架構(gòu)擴(kuò)展性和可運(yùn)維性
在我見(jiàn)過(guò)很多架構(gòu)里,技術(shù)人員只考慮當(dāng)下,但從來(lái)不考慮系統(tǒng)的未來(lái)擴(kuò)展性和可運(yùn)維性。所謂的管生不管養(yǎng)。如果你生下來(lái)的孩子胳膊少腿,嚴(yán)重畸形,那么未來(lái)是很難玩的。因?yàn)榧軜?gòu)不是和軟件不是寫(xiě)好就完的,是需要不斷修改不斷維護(hù)的,80% 的軟件成本都是在維護(hù)上。所以,如何讓你的架構(gòu)有更好的擴(kuò)展性,可以更容易地運(yùn)維,這個(gè)是比較重要的。所謂的擴(kuò)展性,意味著,我可以很容易地加更多的功能,或是加入更多的系統(tǒng),而所謂可運(yùn)維,就是說(shuō)我可以對(duì)線上的系統(tǒng)做任意的變更。擴(kuò)展性要求的是有標(biāo)準(zhǔn)規(guī)范且不耦合的業(yè)務(wù)架構(gòu),可運(yùn)維性要求的則是可控的能力,也就是一組各式各樣的控制系統(tǒng)。
- 通過(guò)服務(wù)編排架構(gòu)來(lái)降低服務(wù)間的耦合。比如:通過(guò)一個(gè)業(yè)務(wù)流程的專用服務(wù),或是像 Workflow,Event Driven Architecture , Broker,Gateway,Service Discovery 等這類的的中間件來(lái)降低服務(wù)間的依賴關(guān)系。
- 通過(guò)服務(wù)發(fā)現(xiàn)或服務(wù)網(wǎng)關(guān)來(lái)降低服務(wù)依賴所帶來(lái)的運(yùn)維復(fù)雜度。服務(wù)發(fā)現(xiàn)可以很好的降低相關(guān)依賴服務(wù)的運(yùn)維復(fù)雜度,讓你可以很輕松的上線或下線服務(wù),或是進(jìn)行服務(wù)伸縮。
- 一定要使用各種軟件設(shè)計(jì)的原則。比如:像 SOLID 這樣的原則,IoC/DIP,SOA 或 Spring Cloud 等架構(gòu)的最佳實(shí)踐(參看《SteveY 對(duì) Amazon 和 Google 平臺(tái)的吐槽》中的 Service Interface 的那幾條軍規(guī)),分布式系統(tǒng)架構(gòu)的相關(guān)實(shí)踐,或微軟件的 ……等等
原則七:對(duì)控制邏輯進(jìn)行全面收口
所有的程序都會(huì)有兩種邏輯,一種是業(yè)務(wù)邏輯,一種是控制邏輯,業(yè)務(wù)邏輯就是完成業(yè)務(wù)的邏輯,控制邏輯是輔助,比如你用多線程,還是用分布式,是用數(shù)據(jù)庫(kù)還是用文件,如何配置、部署,運(yùn)維、監(jiān)控,事務(wù)控制,服務(wù)發(fā)現(xiàn),彈性伸縮,灰度發(fā)布,高并發(fā),等等,等等 ……這些都是控制邏輯,跟業(yè)務(wù)邏輯沒(méi)有一毛錢關(guān)系??刂七壿嫷募夹g(shù)深度會(huì)通常會(huì)比業(yè)務(wù)邏輯要深一些,門檻也會(huì)要高一些,所以,最好要專業(yè)的程序員來(lái)負(fù)責(zé)控制邏輯的開(kāi)發(fā),統(tǒng)一規(guī)劃統(tǒng)一管理,進(jìn)行收口。這其中包括:
- 流量收口。包括南北向和東西向的流量的調(diào)度,主要通過(guò)流量網(wǎng)關(guān),開(kāi)發(fā)框架 SDK 或 Service Mesh 這樣的技術(shù)。
- 服務(wù)治理收口。包括:服務(wù)發(fā)現(xiàn)、健康檢查,配置管理、事務(wù)、事件、重試、熔斷、限流……主要通過(guò)開(kāi)發(fā)框架 SDK – 如:Spring Cloud,或服務(wù)網(wǎng)格 Service Mesh 等技術(shù)。
- 監(jiān)控?cái)?shù)據(jù)收口。包括:日志、指標(biāo)、調(diào)用鏈……主要通過(guò)一些標(biāo)準(zhǔn)主流的探針,再加上后臺(tái)的數(shù)據(jù)清洗和數(shù)據(jù)存儲(chǔ)來(lái)完成,最好是使用無(wú)侵入式的技術(shù)。監(jiān)控的數(shù)據(jù)必需統(tǒng)一在一個(gè)地方進(jìn)行關(guān)聯(lián),這樣才會(huì)產(chǎn)生信息。
- 資源調(diào)度有應(yīng)用部署的收口。包括:計(jì)算、網(wǎng)絡(luò)和存儲(chǔ)的收口,主要是通過(guò)容器化的方案,如 k8s 來(lái)完成。
- 中間件的收口。包括:數(shù)據(jù)庫(kù),消息,緩存,服務(wù)發(fā)現(xiàn),網(wǎng)關(guān)……等等。這類的收口方式一般要在企業(yè)內(nèi)部統(tǒng)一建立一個(gè)共享的云化的中間件資源池。
對(duì)此,這里的原則是:
- 你要選擇容易進(jìn)行業(yè)務(wù)邏輯和控制邏輯分離的技術(shù)。這里,Java 的 JVM+ 字節(jié)碼注入 +AOP 式的 Spring 開(kāi)發(fā)框架,會(huì)帶給你太多的優(yōu)勢(shì)。
- 你要選擇可以享受“前人種樹(shù),后人乘涼”的有技術(shù)紅利的技術(shù)。如:有龐大社區(qū)而且相互兼容的技術(shù),如:Java, Docker, Ansible,HTTP,Telegraf/Collectd……
- 中間件你要使用可以支持 HA 集群和多租戶的技術(shù)。這里基本上所有的主流中間件都會(huì)支持 HA 集群方式的。
原則八:不要遷就老舊系統(tǒng)的技術(shù)債務(wù)
我發(fā)現(xiàn)很多公司都很非常大的技術(shù)債務(wù),這些債務(wù)具體表現(xiàn)如下:
- 使用老舊的技術(shù)。比如,使用 HTTP1.0, Java 1.6,Websphere,ESB,基于 socket 的通訊協(xié)議,過(guò)時(shí)的模型……等等
- 不合理的設(shè)計(jì)。比如,在 gateway 中寫(xiě)大量的業(yè)務(wù)邏輯,單體架構(gòu),數(shù)據(jù)和業(yè)務(wù)邏輯深度耦合,錯(cuò)誤的系統(tǒng)架構(gòu)(把緩存當(dāng)數(shù)據(jù)庫(kù),用消息隊(duì)列同步數(shù)據(jù))……等等
- 缺少配套設(shè)施。比如,沒(méi)有自動(dòng)化測(cè)試,沒(méi)有好的軟件文檔,沒(méi)有質(zhì)量好的代碼,沒(méi)有標(biāo)準(zhǔn)和規(guī)范……等等
來(lái)找我尋求技術(shù)幫助的人都有各種各樣的問(wèn)題。我都會(huì)對(duì)他們苦口婆心地說(shuō)同樣的一句話——“如果你是來(lái)找我 case-by-case 解決問(wèn)題,我興趣不大,因?yàn)?,你們千萬(wàn)不要寄希望能夠很簡(jiǎn)單的把一輛夏利車改成一輛法拉利跑車,或是把一棟地基沒(méi)打好的歪樓搞正。以前欠下的技術(shù)債,都得要還,沒(méi)打好的地基要重新打,沒(méi)建配套設(shè)施都要建。這些基礎(chǔ)設(shè)施如果不按照正確科學(xué)的方式建立的話,你是不可能有一個(gè)好的的系統(tǒng),我也沒(méi)辦法幫你 case-by-case 的解決問(wèn)題……”,一開(kāi)始,他們都會(huì)對(duì)我說(shuō),沒(méi)問(wèn)題,我們就是要還債,但是,最后發(fā)現(xiàn)要還的債真多,有點(diǎn)承受不了,就開(kāi)始現(xiàn)原形了。
他們開(kāi)始為自己的“欠的技術(shù)債”找各種合理化的理由——給你解釋各種各樣的歷史原因和不得以而為之的理由。談著談著,讓我有一種感覺(jué)——他們希望得到一種什么都不改什么都不付出的方式就可以進(jìn)步的心態(tài),他們寧可讓新的技術(shù) low 下來(lái)遷就于這些技術(shù)債,把新的技術(shù)濫用地亂七八糟的。有一個(gè)公司,他們的系統(tǒng)架構(gòu)和技術(shù)選型基本都搞錯(cuò)了,使用錯(cuò)誤的模型構(gòu)建系統(tǒng),導(dǎo)致整個(gè)系統(tǒng)的性能非常之差,也才幾千萬(wàn)條數(shù)據(jù),但他們想的不是還債,不是把地基和配套設(shè)施建好,而且要把樓修的更高,上更多的系統(tǒng)——他們覺(jué)得現(xiàn)有的系統(tǒng)挺好,性能問(wèn)題的原因是他們沒(méi)一個(gè)大數(shù)據(jù)平臺(tái),所以要建大數(shù)據(jù)平臺(tái)……
我見(jiàn)過(guò)很多很多公司,包括大如 BAT 這樣的公司,都會(huì)在原來(lái)的技術(shù)債上進(jìn)行更多的建設(shè),然后,技術(shù)債越來(lái)越大,利息越來(lái)越大,最終成為一個(gè)高利貸,再也還不了(我在《開(kāi)發(fā)團(tuán)隊(duì)的效率》一文中講過(guò)一個(gè) WatchDog 的架構(gòu)模式,一個(gè)系統(tǒng)爛了,不是去改這個(gè)系統(tǒng),而是在旁邊建一個(gè)系統(tǒng)來(lái)看著它,我很難理解為什么會(huì)有這樣的邏輯,也許是為了要解決更多的就業(yè)……)
這里有幾個(gè)原則和方法我是非常堅(jiān)持的,分享給大家:
- 與其花大力氣遷就技術(shù)債務(wù),不如直接還技術(shù)債。是所謂的長(zhǎng)痛不如短痛。
- 建設(shè)沒(méi)有技術(shù)債的“新城區(qū)”,并通過(guò)“防腐層 ”的架構(gòu)模型,不要讓技術(shù)債侵入“新城區(qū)”。
原則九:不要依賴自己的經(jīng)驗(yàn),要依賴于數(shù)據(jù)和學(xué)習(xí)
有好些人來(lái)找我跟我說(shuō)他們的技術(shù)問(wèn)題,然后希望我能夠給他們一個(gè)答案。我說(shuō),我需要了解一下你現(xiàn)有系統(tǒng)的情況,也就是需要先做個(gè)診斷,我只有得到這些數(shù)據(jù)后,我才可能明白真正的原因是什么 ,我才可能給你做出一個(gè)比較好的技術(shù)方案。我個(gè)人覺(jué)得這是一種對(duì)對(duì)方負(fù)責(zé)的方法,因?yàn)榧夹g(shù)手段太多了,所有的技術(shù)手段都有適應(yīng)的場(chǎng)景,并且有各種 trade-off,所以,只有調(diào)研完后才能做出決定。這跟醫(yī)生看病是一樣的,確診病因不能靠經(jīng)驗(yàn),還是要靠診斷數(shù)據(jù)。在科學(xué)面前,所有的經(jīng)驗(yàn)都是靠不住的……
另外,如果有一天你在做技術(shù)決定的時(shí)候,開(kāi)始憑自己以往的經(jīng)驗(yàn),那么你就已經(jīng)不可能再成長(zhǎng)了。人都是不可能通過(guò)不斷重復(fù)過(guò)去而進(jìn)步的,人的進(jìn)步從來(lái)都是通過(guò)學(xué)習(xí)自己不知道的東西。所以,千萬(wàn)不要依賴于自己的經(jīng)驗(yàn)做決定。做任何決定之前,最好花上一點(diǎn)時(shí)間,上網(wǎng)查一下相關(guān)的資料,技術(shù)博客,文章,論文等 ,同時(shí),也看看各各公司,或是各個(gè)開(kāi)源軟件他們是怎么做的?然后,比較多種方案的 Pros/Cons,最終形成自己的決定,這樣,才可能做出一個(gè)更好的決定。
原則十:千萬(wàn)要小心 X – Y 問(wèn)題,要追問(wèn)最初的原因
對(duì)于 X-Y 問(wèn)題,也就是說(shuō),用戶為了解決 X 問(wèn)題,他覺(jué)得用 Y 可以解,于是問(wèn)我 Y 怎么搞,結(jié)果搞到最后,發(fā)現(xiàn)原來(lái)要解決的 X 問(wèn)題,這個(gè)時(shí)候最好的解決方案不是 Y,而是 Z。 這種 X-Y 問(wèn)題真是相當(dāng)之多,見(jiàn)的太多太多了。所以,每次用戶來(lái)找我的時(shí)候,我都要不斷地追問(wèn)什么是 X 問(wèn)題。
比如,好些用戶都會(huì)來(lái)問(wèn)我他們要一個(gè)大數(shù)據(jù)流式處理,結(jié)果追問(wèn)具體要解決什么樣的問(wèn)題時(shí),才發(fā)現(xiàn)他們的問(wèn)題是因?yàn)榉?wù)中有大量的狀態(tài),需要把相同用戶的數(shù)據(jù)請(qǐng)求放在同一個(gè)服務(wù)上處理,而且設(shè)計(jì)上導(dǎo)致一個(gè)慢請(qǐng)拖慢整個(gè)應(yīng)用服務(wù)。最終就是做一下性能調(diào)優(yōu)就好了,根本沒(méi)有必要上什么大數(shù)據(jù)的流式處理。
我很喜歡追問(wèn)為什么 ,這種追問(wèn),會(huì)讓客戶也跟著來(lái)一起重新思考。比如,有個(gè)客戶來(lái)找我評(píng)估的一個(gè)技術(shù)架構(gòu)的決定,從理論上來(lái)說(shuō),好像這個(gè)架構(gòu)在用戶的這個(gè)場(chǎng)景下非常不錯(cuò)。但是,這個(gè)場(chǎng)景和這個(gè)架構(gòu)是我職業(yè)生涯從來(lái)沒(méi)有見(jiàn)過(guò)的。于是,我開(kāi)始追問(wèn)這個(gè)為什么會(huì)是這么一個(gè)場(chǎng)景?當(dāng)我追問(wèn)的時(shí)候,我發(fā)現(xiàn)用戶都感到這個(gè)場(chǎng)景的各種不合理。最后引起了大家非常深刻的研論,最終用戶把那個(gè)場(chǎng)景修正后,而架構(gòu)就突然就變成了一個(gè)常見(jiàn)且成熟的的模型……
原則十一:激進(jìn)勝于保守,創(chuàng)新與實(shí)用并不沖突
我對(duì)技術(shù)的態(tài)度是比較激進(jìn)的,但是,所謂的激進(jìn)并不是瞎搞,也不是見(jiàn)新技術(shù)就上,而是積極擁抱會(huì)改變未來(lái)的新技術(shù),如:Docker/Go,我就非??斓馗M(jìn),但是像區(qū)塊鏈或是 Rust 這樣的,我就不是很積極。因?yàn)?,其并沒(méi)有命中我認(rèn)為的技術(shù)趨勢(shì)的幾個(gè)特征(參看《Go,Docker 和新技術(shù) 》)。當(dāng)然,我也不是不喜歡的就不學(xué)了,我對(duì)區(qū)塊鏈和 Rust 我一樣學(xué)習(xí),我也知道這些技術(shù)的優(yōu)勢(shì),但我不會(huì)大規(guī)模使用它們。另外,我也尊重保守的決定,這里面沒(méi)有對(duì)和錯(cuò)。但是,我個(gè)人覺(jué)得對(duì)技術(shù)激進(jìn)的態(tài)度比起保守來(lái)說(shuō)有太多的好處了。一方面來(lái)說(shuō),對(duì)于用戶來(lái)說(shuō),很大程度上來(lái)說(shuō),新技術(shù)通常都表面有很好的競(jìng)爭(zhēng)力,而且我見(jiàn)太多這樣成功的公司都在積極擁抱新的技術(shù)的,而保守的通常來(lái)說(shuō)都越來(lái)越不好。
有一些人會(huì)跟我說(shuō),我們是實(shí)用主義,我們不需要?jiǎng)?chuàng)新,能解決當(dāng)下的問(wèn)題就好,所以,我們不需要新技術(shù),更有的技術(shù)用好就行了。這類的公司,他們的技術(shù)設(shè)計(jì)第一天就在負(fù)債,雖然可以解決當(dāng)下問(wèn)題,但是馬上就會(huì)出現(xiàn)新的問(wèn)題,然后他們會(huì)疲于解決各種問(wèn)題。最后呢,最后還是會(huì)走到新的技術(shù)上。
這里的邏輯很簡(jiǎn)單 —— 進(jìn)步永遠(yuǎn)來(lái)自于探索,探索是要付出代價(jià)的,但是收益更大。對(duì)我而言,不敢冒險(xiǎn)才是最大的冒險(xiǎn),不敢犯錯(cuò)才是最大的錯(cuò)誤,害怕失去會(huì)讓你失去的更多……