微服務(wù)之基于Docker的分布式企業(yè)級實踐

如果使用 Docker 技術(shù)來架構(gòu)微服務(wù)體系,服務(wù)發(fā)現(xiàn)就是一個必然的課題。目前主流的服務(wù)發(fā)現(xiàn)模式有兩種:客戶端發(fā)現(xiàn)模式席纽,以及服務(wù)端發(fā)現(xiàn)模式耸袜。

客戶端發(fā)現(xiàn)模式

客戶端發(fā)現(xiàn)模式的架構(gòu)圖如下:

M-1

客戶端發(fā)現(xiàn)模式的典型實現(xiàn)是Netflix體系技術(shù)爪喘。客戶端從一個服務(wù)注冊服務(wù)中心查詢所有可用服務(wù)實例。客戶端使用負(fù)載均衡算法從多個可用的服務(wù)實例中選擇出一個诈悍,然后發(fā)出請求。比較典型的一個開源實現(xiàn)就是 Netflix 的 Eureka兽埃。

Netflix-Eureka

Eureka 的客戶端是采用自注冊的模式侥钳,客戶端需要負(fù)責(zé)處理服務(wù)實例的注冊和注銷,發(fā)送心跳柄错。

在使用 SpringBoot 集成一個微服務(wù)時舷夺,結(jié)合 SpringCloud 項目可以很方便得實現(xiàn)自動注冊。在服務(wù)啟動類上添加@EnableEurekaClient即可在服務(wù)實例啟動時鄙陡,向配置好的 Eureka 服務(wù)端注冊服務(wù),并且定時發(fā)送以心跳躏啰〕梅客戶端的負(fù)載均衡由 Netflix Ribbon 實現(xiàn)。服務(wù)網(wǎng)關(guān)使用 Netflix Zuul给僵,熔斷器使用 Netflix Hystrix毫捣。

除了服務(wù)發(fā)現(xiàn)的配套框架,SpringCloud 的 Netflix-Feign帝际,提供了聲明式的接口來處理服務(wù)的 Rest 請求蔓同。當(dāng)然,除了使用 FeignClient蹲诀,也可以使用 Spring RestTemplate斑粱。項目中如果使用@FeignClient可以使代碼的可閱讀性更好,Rest API 也一目了然脯爪。

服務(wù)實例的注冊管理则北、查詢矿微,都是通過應(yīng)用內(nèi)調(diào)用 Eureka 提供的 REST API 接口(當(dāng)然使用 SpringCloud-Eureka 不需要編寫這部分代碼)。由于服務(wù)注冊尚揣、注銷是通過客戶端自身發(fā)出請求的涌矢,所以這種模式的一個主要問題是對于不同的編程語言會注冊不同服務(wù),需要為每種開發(fā)語言單獨開發(fā)服務(wù)發(fā)現(xiàn)邏輯快骗。另外娜庇,使用 Eureka 時需要顯式配置健康檢查支持。

服務(wù)端發(fā)現(xiàn)模式

服務(wù)端發(fā)現(xiàn)模式的架構(gòu)圖如下:

M-2

客戶端向負(fù)載均衡器發(fā)出請求方篮,負(fù)載均衡器向服務(wù)注冊表發(fā)出請求名秀,將請求轉(zhuǎn)發(fā)到注冊表中可用的服務(wù)實例。服務(wù)實例也是在注冊表中注冊恭取,注銷的泰偿。負(fù)載均衡可以使用可以使用 Haproxy 或者 Nginx。服務(wù)端發(fā)現(xiàn)模式目前基于 Docker 的主流方案主要是 Consul蜈垮、Etcd 以及 Zookeeper耗跛。

Consul

Consul 提供了一個 API 允許客戶端注冊和發(fā)現(xiàn)服務(wù)。其一致性上基于RAFT算法攒发。通過 WAN 的 Gossip 協(xié)議调塌,管理成員和廣播消息,以完成跨數(shù)據(jù)中心的同步惠猿,且支持 ACL 訪問控制羔砾。Consul 還提供了健康檢查機制,支持 kv 存儲服務(wù)(Eureka 不支持)偶妖。Consul 的一些更詳細(xì)的介紹可以參考之前寫的一篇:Docker 容器部署 Consul 集群姜凄。

Etcd

Etcd 都是強一致的(滿足 CAP 的 CP),高可用的趾访。Etcd 也是基于 RAFT 算法實現(xiàn)強一致性的 KV 數(shù)據(jù)同步态秧。Kubernetes 中使用 Etcd 的 KV 結(jié)構(gòu)存儲所有對象的生命周期。

關(guān)于 Etcd 的一些內(nèi)部原理可以看下etcd v3原理分析

Zookeeper

ZK 最早應(yīng)用于 Hadoop扼鞋,其體系已經(jīng)非常成熟申鱼,常被用于大公司。如果已經(jīng)有自己的 ZK 集群云头,那么可以考慮用 ZK 來做自己的服務(wù)注冊中心捐友。

Zookeeper 同 Etcd 一樣,強一致性溃槐,高可用性匣砖。一致性算法是基于 Paxos 的。對于微服務(wù)架構(gòu)的初始階段,沒有必要用比較繁重的 ZK 來做服務(wù)發(fā)現(xiàn)脆粥。

服務(wù)注冊

服務(wù)注冊表是服務(wù)發(fā)現(xiàn)中的一個重要組件砌溺。除了 Kubernetes、Marathon 其服務(wù)發(fā)現(xiàn)是內(nèi)置的模塊之外变隔。服務(wù)都是需要注冊到注冊表上规伐。上文介紹的 Eureka、consul匣缘、etcd 以及 ZK 都是服務(wù)注冊表的例子猖闪。

微服務(wù)如何注冊到注冊表也是有兩種比較典型的注冊方式:自注冊模式,第三方注冊模式肌厨。

自注冊模式 Self-registration pattern

上文中的 Netflix-Eureka 客戶端就是一個典型的自注冊模式的例子培慌。也即每個微服務(wù)的實例本身,需要負(fù)責(zé)注冊以及注銷服務(wù)柑爸。Eureka 還提供了心跳機制吵护,來保證注冊信息的準(zhǔn)確,具體的心跳的發(fā)送間隔時間可以在微服務(wù)的 SpringBoot 中進(jìn)行配置表鳍。

如下馅而,就是使用 Eureka 做注冊表時,在微服務(wù)(SpringBoot 應(yīng)用)啟動時會有一條服務(wù)注冊的信息:

com.netflix.discovery.DiscoveryClient? ? : DiscoveryClient_SERVICE-USER/{your_ip}:service-user:{port}:cc9f93c54a0820c7a845422f9ecc73fb: registering service...

同樣譬圣,在應(yīng)用停用時瓮恭,服務(wù)實例需要主動注銷本實例信息:

2018-01-04 20:41:37.290? INFO 49244 --- [? ? ?  Thread-8] c.n.e.EurekaDiscoveryClientConfiguration : Unregistering application service-user with eureka with status DOWN
2018-01-04 20:41:37.340? INFO 49244 --- [? ? ? Thread-8] com.netflix.discovery.DiscoveryClient? ? : Shutting down DiscoveryClient ...
2018-01-04 20:41:37.381? INFO 49244 --- [? ? ? Thread-8] com.netflix.discovery.DiscoveryClient? ? : Unregistering ...
2018-01-04 20:41:37.559? INFO 49244 --- [? ? ? Thread-8] com.netflix.discovery.DiscoveryClient? ? : DiscoveryClient_SERVICE-USER/{your_ip}:service-user:{port}:cc9f93c54a0820c7a845422f9ecc73fb - deregister? status: 200

自注冊方式是比較簡單的服務(wù)注冊方式,不需要額外的設(shè)施或代理厘熟,由微服務(wù)實例本身來管理服務(wù)注冊屯蹦。但是缺點也很明顯,比如 Eureka 目前只提供了 Java 客戶端绳姨,所以不方便多語言的微服務(wù)擴展登澜。因為需要微服務(wù)自己去管理服務(wù)注冊邏輯,所以微服務(wù)實現(xiàn)也耦合了服務(wù)注冊和心跳機制飘庄∧匀洌跨語言性比較差。

第三方注冊模式 Third party registration pattern

第三方注冊竭宰,也即服務(wù)注冊的管理(注冊空郊、注銷服務(wù))通過一個專門的服務(wù)管理器(Registar)來負(fù)責(zé)份招。Registrator 就是一個開源的服務(wù)管理器的實現(xiàn)切揭。Registrator 提供了對于 Etcd 以及 Consul 的注冊表服務(wù)支持。 Registrator 作為一個代理服務(wù)锁摔,需要部署廓旬、運行在微服務(wù)所在的服務(wù)器或者虛擬機中。比較簡單的安裝方式就是通過 Docker,以容器的方式來運行孕豹。三方注冊模式的架構(gòu)圖如下:

M-3

通過添加一個服務(wù)管理器涩盾,微服務(wù)實例不再直接向注冊中心注冊,注銷励背。由服務(wù)管理器(Registar)通過訂閱服務(wù)春霍,跟蹤心跳,來發(fā)現(xiàn)可用的服務(wù)實例叶眉,并向注冊中心(consul址儒、etcd 等)注冊,注銷實例衅疙,以及發(fā)送心跳莲趣。這樣就可以實現(xiàn)服務(wù)發(fā)現(xiàn)組件和微服務(wù)架構(gòu)的解耦。

Registrator 配合 Consul饱溢,以及 Consul Template 搭建服務(wù)發(fā)現(xiàn)中心喧伞,可以參考: Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx 。此文示例了 Nginx 來做負(fù)載均衡绩郎,在具體的實施過程中也可以用 Haproxy 或其他方案進(jìn)行替代潘鲫。

小結(jié)

除了以上幾種做服務(wù)發(fā)現(xiàn)的技術(shù),Kubernetes 自帶了服務(wù)發(fā)現(xiàn)模塊嗽上,負(fù)責(zé)處理服務(wù)實例的注冊和注銷次舌。Kubernetes 也在每個集群節(jié)點上運行代理,來實現(xiàn)服務(wù)端發(fā)現(xiàn)路由器的功能兽愤。如果編排技術(shù)使用的 k8n彼念,可以用 k8n 的一整套 Docker 微服務(wù)方案,對 k8n 感興趣的可以閱讀下Kubernetes 架構(gòu)設(shè)計與核心原理浅萧。

在實際的技術(shù)選型中逐沙,最主要還是要結(jié)合業(yè)務(wù)、系統(tǒng)的未來發(fā)展的特征進(jìn)行合理判斷洼畅。

在 CAP 理論中吩案。Eureka 滿足了 AP,Consul 是 CA帝簇,ZK 和 Etcd 是 CP徘郭。 在分布式場景下 Eureka 和 Consul 都能保證可用性。而搭建 Eureka 服務(wù)會相對更快速丧肴,因為不需要搭建額外的高可用服務(wù)注冊中心残揉,在小規(guī)模服務(wù)器實例時,使用 Eureka 可以節(jié)省一定成本芋浮。

Eureka抱环、Consul 都提供了可以查看服務(wù)注冊數(shù)據(jù)的 WebUI 組件。Consul 還提供了 KV 存儲,支持支持 http 和 dns 接口镇草。對于創(chuàng)業(yè)公司最開始搭建微服務(wù)眶痰,比較推薦這兩者。

在多數(shù)據(jù)中心方面梯啤,Consul 自帶數(shù)據(jù)中心的 WAN 方案竖伯。ZK 和 Etcd 均不提供多數(shù)據(jù)中心功能的支持,需要額外的開發(fā)因宇。

跨語言性上黔夭,Zookeeper 需要使用其提供的客戶端 api,跨語言支持較弱羽嫡。Etcd本姥、Eureka 都支持 http,Etcd 還支持 grpc杭棵。Consul 除了 http 之外還提供了 DNS 的支持婚惫。

安全方面,Consul魂爪,Zookeeper 支持 ACL先舷,另外 Consul、Etcd 支持安全通道 Https滓侍。

SpringCloud 目前對于 Eureka蒋川、Consul、Etcd撩笆、ZK 都有相應(yīng)的支持捺球。

Consul 和 Docker 一樣,都是用 Go 語言實現(xiàn)夕冲,基于 Go 語言的微服務(wù)應(yīng)用可以優(yōu)先考慮用 Consul氮兵。

服務(wù)間的 IPC 機制

按照微服務(wù)的架構(gòu)體系,解決了服務(wù)發(fā)現(xiàn)的問題之后歹鱼。就需要選擇合適的服務(wù)間通信的機制泣栈。如果是在 SpringBoot 應(yīng)用中,使用基于 Http 協(xié)議的 REST API 是一種同步的解決方案弥姻。而且 Restful 風(fēng)格的 API 可以使每個微服務(wù)應(yīng)用更加趨于資源化南片,使用輕量級的協(xié)議也是微服務(wù)一直提倡的。

如果每個微服務(wù)是使用 DDD(Domain-Driven Design)思想的話庭敦,那么需要每個微服務(wù)盡量不使用同步的 RPC 機制疼进。異步的基于消息的方式比如 AMQP 或者 STOMP,來松耦合微服務(wù)間的依賴會是很好的選擇螺捐。目前基于消息的點對點的 pub/sub 的框架選擇也比較多颠悬。下面具體介紹下兩種 IPC 的一些方案。

同步

對于同步的請求/響應(yīng)模式的通信方式定血∨獍可以選擇基于 Restful 風(fēng)格的 Http 協(xié)議進(jìn)行服務(wù)間通信,或者跨語言性很好的 Thrift 協(xié)議澜沟。如果是使用純 Java 語言的微服務(wù)灾票,也可以使用 Dubbo。如果是 SpringBoot 集成的微服務(wù)架構(gòu)體系茫虽,建議選擇跨語言性好刊苍、Spring 社區(qū)支持比較好的 RPC。

Dubbo

Dubbo是由阿里巴巴開發(fā)的開源的 Java 客戶端的 RPC 框架濒析。Dubbo 基于 TCP 協(xié)議的長連接進(jìn)行數(shù)據(jù)傳輸正什。傳輸格式是使用 Hessian 二進(jìn)制序列化。服務(wù)注冊中心可以通過 Zookeeper 實現(xiàn)号杏。

ApacheThrift

ApacheThrift 是由 Facebook 開發(fā)的 RPC 框架婴氮。其代碼生成引擎可以在多種語言中,如 C++盾致、 Java主经、Python、PHP庭惜、Ruby罩驻、Erlang、Perl 等創(chuàng)建高效的服務(wù)护赊。傳輸數(shù)據(jù)采用二進(jìn)制格式惠遏,其數(shù)據(jù)包要比使用 Json 或者 XML 格式的 HTTP 協(xié)議小。高并發(fā)骏啰,大數(shù)據(jù)場景下更有優(yōu)勢爽哎。

Rest

Rest 基于 HTTP 協(xié)議,HTTP 協(xié)議本身具有語義的豐富性器一。隨著 Springboot 被廣泛使用课锌,越來越多的基于 Restful 風(fēng)格的 API 流行起來。REST 是基于 HTTP 協(xié)議的祈秕,并且大多數(shù)開發(fā)者也是熟知 HTTP 的渺贤。

這里另外提一點,很多公司或者團(tuán)隊也是使用Springboot的请毛,也在說自己是基于 Restful 風(fēng)格的志鞍。但是事實其實往往是實施得并不到位。對于你的 Restful 是否是真的 Restful方仿,可以參考這篇文章固棚,對于 Restful 風(fēng)格 API 的成熟度進(jìn)行了四個層次的分析: Richardson Maturity Model steps toward the glory of REST统翩。

如果使用Springboot的話,無論使用什么服務(wù)發(fā)現(xiàn)機制此洲,都可以通過 Spring 的RestTemplate來做基礎(chǔ)的Http請求封裝厂汗。

如果使用的前文提到的Netflix-Eureka的話,可以使用Netflix-Feign呜师。Feign是一個聲明式 Web Service 客戶端娶桦。客戶端的負(fù)載均衡使用 Netflix-Ribbon汁汗。

異步

在微服務(wù)架構(gòu)中衷畦,排除純粹的“事件驅(qū)動架構(gòu)”,使用消息隊列的場景一般是為了進(jìn)行微服務(wù)之間的解耦知牌。服務(wù)之間不需要了解是由哪個服務(wù)實例來消費或者發(fā)布消息祈争。只要處理好自己領(lǐng)域范圍的邏輯,然后通過消息通道來發(fā)布角寸,或者訂閱自己關(guān)注的消息就可以铛嘱。目前開源的消息隊列技術(shù)也很多。比如 Apache Kafka袭厂,RabbitMQ墨吓,Apache ActiveMQ 以及阿里巴巴的 RocketMQ 目前已經(jīng)成為 Apache 項目之一。消息隊列的模型中纹磺,主要的三個組成就是:

Producer:生產(chǎn)消息帖烘,將消息寫入 channel。

Message Broker:消息代理橄杨,將寫入 channel 的消息按隊列的結(jié)構(gòu)進(jìn)行管理秘症。負(fù)責(zé)存儲/轉(zhuǎn)發(fā)消息。Broker 一般是需要單獨搭建式矫、配置的集群乡摹,而且必須是高可用的。

Consumer:消息的消費者采转。目前大多數(shù)的消息隊列都是保證消息至少被消費一次聪廉。所以根據(jù)使用的消息隊列設(shè)施不同,消費者要做好冪等故慈。

不同的消息隊列的實現(xiàn)板熊,消息模型不同。各個框架的特性也不同:

RabbitMQ

RabbitMQ 是基于 AMQP 協(xié)議的開源實現(xiàn)察绷,由以高性能干签、可伸縮性出名的 Erlang 寫成。目前客戶端支持 Java拆撼、.Net/C# 和 Erlang容劳。在 AMQP(Advanced Message Queuing Protocol)的組件中喘沿,Broker 中可以包含多個Exchange(交換機)組件。Exchange 可以綁定多個 Queue 以及其他 Exchange竭贩。消息會按照 Exchange 中設(shè)置的 Routing 規(guī)則蚜印,發(fā)送到相應(yīng)的 Message Queue。在 Consumer 消費了這個消息之后娶视,會跟 Broker 建立連接。發(fā)送消費消息的通知睁宰。則 Message Queue 才會將這個消息移除肪获。

Kafka

Kafka 是一個高性能的基于發(fā)布/訂閱的跨語言分布式消息系統(tǒng)。Kafka 的開發(fā)語言為 Scala柒傻。其比較重要的特性是:

以時間復(fù)雜度為O(1)的方式快速消息持久化孝赫;

高吞吐率;

支持服務(wù)間的消息分區(qū)红符,及分布式消費青柄,同時保證消息順序傳輸;

支持在線水平擴展,自帶負(fù)載均衡预侯;

支持只消費且僅消費一次(Exactly Once)模式等等致开。

說個缺點: 管理界面是個比較雞肋了點,可以使用開源的kafka-manager

其高吞吐的特性萎馅,除了可以作為微服務(wù)之間的消息隊列双戳,也可以用于日志收集, 離線分析糜芳, 實時分析等飒货。

Kafka 官方提供了 Java 版本的客戶端 API,Kafka 社區(qū)目前也支持多種語言峭竣,包括 PHP塘辅、Python、Go皆撩、C/C++扣墩、Ruby、NodeJS 等扛吞。

ActiveMQ

ActiveMQ 是基于 JMS(Java Messaging Service)實現(xiàn)的 JMSProvider沮榜。JMS主要提供了兩種類型的消息:點對點(Point-to-Point)以及發(fā)布/訂閱(Publish/Subscribe)。目前客戶端支持 Java喻粹、C蟆融、C++、 C#守呜、Ruby型酥、Perl山憨、Python、PHP弥喉。而且 ActiveMQ 支持多種協(xié)議:Stomp郁竟、AMQP、MQTT 以及 OpenWire由境。

RocketMQ/ONS

RocketMQ 是由阿里巴巴研發(fā)開源的高可用分布式消息隊列棚亩。ONS是提供商業(yè)版的高可用集群。ONS 支持 pull/push虏杰〖ン。可支持主動推送,百億級別消息堆積纺阔。ONS 支持全局的順序消息瘸彤,以及有友好的管理頁面,可以很好的監(jiān)控消息隊列的消費情況笛钝,并且支持手動觸發(fā)消息多次重發(fā)质况。

小結(jié)

通過上篇的微服務(wù)的服務(wù)發(fā)現(xiàn)機制,加上 Restful API玻靡,可以解決微服務(wù)間的同步方式的進(jìn)程間通信结榄。當(dāng)然,既然使用了微服務(wù)囤捻,就希望所有的微服務(wù)能有合理的限界上下文(系統(tǒng)邊界)潭陪。微服務(wù)之間的同步通信應(yīng)盡量避免,以防止服務(wù)間的領(lǐng)域模型互相侵入最蕾。為了避免這種情況依溯,就可以在微服務(wù)的架構(gòu)中使用一層API gateway(會在下文介紹)。所有的微服務(wù)通過API gateway進(jìn)行統(tǒng)一的請求的轉(zhuǎn)發(fā)瘟则,合并黎炉。并且API gateway也需要支持同步請求,以及NIO的異步的請求(可以提高請求合并的效率以及性能)醋拧。

消息隊列可以用于微服務(wù)間的解耦慷嗜。在基于Docker的微服務(wù)的服務(wù)集群環(huán)境下,網(wǎng)絡(luò)環(huán)境會比一般的分布式集群復(fù)雜丹壕。選擇一種高可用的分布式消息隊列實現(xiàn)即可庆械。如果自己搭建諸如Kafka、RabbitMQ集群環(huán)境的話菌赖,那對于Broker設(shè)施的高可用性會要求很高缭乘。基于Springboot的微服務(wù)的話琉用,比較推薦使用Kafka 或者ONS堕绩。雖然ONS是商用的策幼,但是易于管理以及穩(wěn)定性高,尤其對于必要場景才依賴于消息隊列進(jìn)行通信的微服務(wù)架構(gòu)來說,會更適合奴紧。如果考慮到會存在日志收集特姐,實時分析等場景,也可以搭建Kafka集群黍氮。目前阿里云也有了基于Kafka的商用集群設(shè)施唐含。

使用 API Gateway 處理微服務(wù)請求轉(zhuǎn)發(fā)、合并

前面主要介紹了如何解決微服務(wù)的服務(wù)發(fā)現(xiàn)和通信問題沫浆。在微服務(wù)的架構(gòu)體系中捷枯,使用DDD思想劃分服務(wù)間的限界上下文的時候,會盡量減少微服務(wù)之間的調(diào)用件缸。為了解耦微服務(wù)铜靶,便有了基于API Gateway方式的優(yōu)化方案叔遂。

解耦微服務(wù)的調(diào)用

比如他炊,下面一個常見的需求場景——“用戶訂單列表”的一個聚合頁面。需要請求”用戶服務(wù)“獲取基礎(chǔ)用戶信息已艰,以及”訂單服務(wù)“獲取訂單信息痊末,再通過請求“商品服務(wù)”獲取訂單列表中的商品圖片、標(biāo)題等信息哩掺。如下圖所示的場景 :

M-4

如果讓客戶端(比如H5凿叠、Android、iOS)發(fā)出多個請求來解決多個信息聚合嚼吞,則會增加客戶端的復(fù)雜度盒件。比較合理的方式就是增加API Gateway層。API Gateway跟微服務(wù)一樣舱禽,也可以部署炒刁、運行在Docker容器中,也是一個Springboot應(yīng)用誊稚。如下翔始,通過Gateway API進(jìn)行轉(zhuǎn)發(fā)后:

M-5

所有的請求的信息,由Gateway進(jìn)行聚合里伯,Gateway也是進(jìn)入系統(tǒng)的唯一節(jié)點城瞎。并且Gateway和所有微服務(wù),以及提供給客戶端的也是Restful風(fēng)格API疾瓮。Gateway層的引入可以很好的解決信息的聚合問題脖镀。而且可以更好得適配不同的客戶端的請求,比如H5的頁面不需要展示用戶信息狼电,而iOS客戶端需要展示用戶信息认然,則只需要添加一個Gateway API請求資源即可补憾,微服務(wù)層的資源不需要進(jìn)行變更。

API Gateway 的特點

API gateway除了可以進(jìn)行請求的合并卷员、轉(zhuǎn)發(fā)盈匾。還需要有其他的特點,才能成為一個完整的Gateway毕骡。

響應(yīng)式編程

Gateway是所有客戶端請求的入口缝彬。類似Facade模式。為了提高請求的性能掸哑,最好選擇一套非阻塞I/O的框架蔗草。在一些需要請求多個微服務(wù)的場景下,對于每個微服務(wù)的請求不一定需要同步叙凡。前文舉例的“用戶訂單列表”的例子中劈伴,獲取用戶信息,以及獲取訂單列表握爷,就是兩個獨立請求跛璧。只有獲取訂單的商品信息,需要等訂單信息返回之后新啼,根據(jù)訂單的商品id列表再去請求商品微服務(wù)追城。為了減少整個請求的響應(yīng)時間,需要Gateway能夠并發(fā)處理相互獨立的請求燥撞。一種解決方案就是采用響應(yīng)式編程座柱。

目前使用Java技術(shù)棧的響應(yīng)式編程方式有,Java8的CompletableFuture物舒,以及ReactiveX提供的基于JVM的實現(xiàn)-RxJava色洞。

ReactiveX是一個使用可觀察數(shù)據(jù)流進(jìn)行異步編程的編程接口,ReactiveX結(jié)合了觀察者模式冠胯、迭代器模式和函數(shù)式編程的精華火诸。除了RxJava還有RxJS,RX.NET等多語言的實現(xiàn)。

對于Gateway來說涵叮,RxJava提供的Observable可以很好的解決并行的獨立I/O請求惭蹂,并且如果微服務(wù)項目中使用Java8,團(tuán)隊成員會對RxJava的函數(shù)學(xué)習(xí)吸收會更快割粮。同樣基于Lambda風(fēng)格的響應(yīng)式編程盾碗,可以使代碼更加簡潔。關(guān)于RxJava的詳細(xì)介紹可以可以閱讀RxJava文檔和教程舀瓢。

通過響應(yīng)式編程的Observable模式廷雅,可以很簡潔、方便得創(chuàng)建事件流、數(shù)據(jù)流航缀,以及用簡潔的函數(shù)進(jìn)行數(shù)據(jù)的組合和轉(zhuǎn)換商架,同時可以訂閱任何可觀察的數(shù)據(jù)流并執(zhí)行操作。

通過使用RxJava,“用戶訂單列表”的資源請求時序圖:

M-6

響應(yīng)式編程可以更好的處理各種線程同步芥玉、并發(fā)請求蛇摸,通過Observables和Schedulers提供了透明的數(shù)據(jù)流、事件流的線程處理灿巧。在敏捷開發(fā)模式下赶袄,響應(yīng)式編程使代碼更加簡潔,更好維護(hù)抠藕。

鑒權(quán)

Gateway作為系統(tǒng)的唯一入口饿肺,基于微服務(wù)的所有鑒權(quán),都可以圍繞Gateway去做盾似。在Springboot工程中敬辣,基礎(chǔ)的授權(quán)可以使用spring-boot-starter-security以及Spring Security(Spring Security也可以集成在Spring MVC項目中)。

Spring Security主要使用AOP零院,對資源請求進(jìn)行攔截溉跃,內(nèi)部維護(hù)了一個角色的Filter Chain。因為微服務(wù)都是通過Gateway請求的门粪,所以微服務(wù)的@Secured可以根據(jù)Gateway中不同的資源的角色級別進(jìn)行設(shè)置喊积。

Spring Security提供了基礎(chǔ)的角色的校驗接口規(guī)范烹困。但客戶端請求的Token信息的加密玄妈、存儲以及驗證,需要應(yīng)用自己完成髓梅。對于Token加密信息的存儲可以使用Redis拟蜻。這里再多提一點,為了保證一些加密信息的可變性枯饿,最好在一開始設(shè)計Token模塊的時候就考慮到支持多個版本密鑰酝锅,以防止萬一內(nèi)部密鑰被泄露(之前聽一個朋友說其公司的Token加密代碼被員工公布出去)。至于加密算法奢方,以及具體的實現(xiàn)在此就不再展開搔扁。 在Gateway鑒權(quán)通過之后,解析后的token信息可以直接傳遞給需要繼續(xù)請求的微服務(wù)層蟋字。

如果應(yīng)用需要授權(quán)(對資源請求需要管理不同的角色稿蹲、權(quán)限),也只要在Gateway的Rest API基礎(chǔ)上基于AOP思想來做即可鹊奖。統(tǒng)一管理鑒權(quán)和授權(quán)苛聘,這也是使用類似Facade模式的Gateway API的好處之一。

負(fù)載均衡

API Gateway跟Microservice一樣,作為Springboot應(yīng)用设哗,提供Rest api唱捣。所以同樣運行在Docker容器中。Gateway和微服務(wù)之間的服務(wù)發(fā)現(xiàn)還是可以采用前文所述的客戶端發(fā)現(xiàn)模式网梢,或者服務(wù)端發(fā)現(xiàn)模式震缭。

在集群環(huán)境下,API Gateway 可以暴露統(tǒng)一的端口战虏,其實例會運行在不同IP的服務(wù)器上蛀序。因為我們是使用阿里云的ECS作為容器的基礎(chǔ)設(shè)施,所以在集群環(huán)境的負(fù)載均衡也是使用阿里云的負(fù)載均衡SLB,域名解析也使用AliyunDNS活烙。下圖是一個簡單的網(wǎng)絡(luò)請求的示意:

M-7

在實踐中徐裸,為了不暴露服務(wù)的端口和資源地址,也可以在服務(wù)集群中再部署Nginx服務(wù)作為反向代理啸盏,外部的負(fù)載均衡設(shè)施比如SLB可以將請求轉(zhuǎn)發(fā)到Nginx服務(wù)器重贺,請求通過Nginx再轉(zhuǎn)發(fā)給Gateway端口。如果是自建機房的集群回懦,就需要搭建高可用的負(fù)載均衡中心气笙。為了應(yīng)對跨機器請求,最好使用Consul,Consul(Consul Template)+Registor+Haproxy來做服務(wù)發(fā)現(xiàn)和負(fù)載均衡中心怯晕。

緩存

對于一些高QPS的請求潜圃,可以在API Gateway做多級緩存。分布式的緩存可以使用Redis舟茶,Memcached等谭期。如果是一些對實時性要求不高的,變化頻率不高但是高QPS的頁面級請求吧凉,也可以在Gateway層做本地緩存隧出。而且Gateway可以讓緩存方案更靈活和通用。

API Gateway的錯誤處理

在Gateway的具體實現(xiàn)過程中阀捅,錯誤處理也是一個很重要的事情胀瞪。對于Gateway的錯誤處理,可以使用Hystrix來處理請求的熔斷饲鄙。并且RxJava自帶的onErrorReturn回調(diào)也可以方便得處理錯誤信息的返回凄诞。對于熔斷機制,需要處理以下幾個方面:

服務(wù)請求的容錯處理

作為一個合理的Gateway忍级,其應(yīng)該只負(fù)責(zé)處理數(shù)據(jù)流帆谍、事件流,而不應(yīng)該處理業(yè)務(wù)邏輯颤练。在處理多個微服務(wù)的請求時既忆,會出現(xiàn)微服務(wù)請求的超時驱负、不可用的情況。在一些特定的場景下患雇, 需要能夠合理得處理部分失敗跃脊。比如上例中的“用戶訂單列表”,當(dāng)“User”微服務(wù)出現(xiàn)錯誤時苛吱,不應(yīng)該影響“Order”數(shù)據(jù)的請求酪术。最好的處理方式就是給當(dāng)時錯誤的用戶信息請求返回一個默認(rèn)的數(shù)據(jù),比如顯示一個默認(rèn)頭像翠储,默認(rèn)用戶昵稱绘雁。然后對于請求正常的訂單,以及商品信息給與正確的數(shù)據(jù)返回援所。如果是一個關(guān)鍵的微服務(wù)請求異常庐舟,比如當(dāng)“Order”領(lǐng)域的微服務(wù)異常時,則應(yīng)該給客戶端一個錯誤碼住拭,以及合理的錯誤提示信息挪略。這樣的處理可以盡量在部分系統(tǒng)不可用時提升用戶體驗。使用RxJava時滔岳,具體的實現(xiàn)方式就是針對不同的客戶端請求的情況杠娱,寫好onErrorReturn,做好錯誤數(shù)據(jù)兼容即可谱煤。

異常的捕捉和記錄

Gateway主要是做請求的轉(zhuǎn)發(fā)摊求、合并。為了能清楚得排查問題刘离,定位到具體哪個服務(wù)室叉、甚至是哪個Docker容器的問題,需要Gateway能對不同類型的異常寥闪、業(yè)務(wù)錯誤進(jìn)行捕捉和記錄太惠。如果使用FeignClient來請求微服務(wù)資源磨淌,可以通過對ErrorDecoder接口的實現(xiàn)疲憋,來針對Response結(jié)果進(jìn)行進(jìn)一步的過濾處理,以及在日志中記錄下所有請求信息梁只。如果是使用Spring Rest Template,則可以通過定義一個定制化的RestTempate缚柳,并對返回的ResponseEntity進(jìn)行解析。在返回序列化之后的結(jié)果對象之前搪锣,對錯誤信息進(jìn)行日志記錄秋忙。

超時機制

Gateway線程中大多是IO線程,為了防止因為某一微服務(wù)請求阻塞构舟,導(dǎo)致Gateway過多的等待線程灰追,耗盡線程池、隊列等系統(tǒng)資源。需要Gateway中提供超時機制弹澎,對超時接口能進(jìn)行優(yōu)雅的服務(wù)降級朴下。

在SpringCloud的Feign項目中集成了Hystrix。Hystrix提供了比較全面的超時處理的熔斷機制苦蒿。默認(rèn)情況下殴胧,超時機制是開啟的。除了可以配置超時相關(guān)的參數(shù)佩迟,Netflix還提供了基于Hytrix的實時監(jiān)控Netflix -Dashboard,并且集群服務(wù)只需再附加部署Netflix-Turbine团滥。通用的Hytrix的配置項可以參考Hystrix-Configuration。

如果是使用RxJava的Observable的響應(yīng)式編程报强,想對不同的請求設(shè)置不同的超時時間灸姊,可以直接在Observable的timeout()方法的參數(shù)進(jìn)行設(shè)置回調(diào)的方法以及超時時間等。

重試機制

對于一些關(guān)鍵的業(yè)務(wù)秉溉,在請求超時時厨钻,為了保證正確的數(shù)據(jù)返回,需要Gateway能提供重試機制坚嗜。如果使用SpringCloudFeign夯膀,則其內(nèi)置的Ribbon,會提供的默認(rèn)的重試配置苍蔬,可以通過設(shè)置spring.cloud.loadbalancer.retry.enabled=false將其關(guān)閉诱建。Ribbon提供的重試機制會在請求超時或者socket read timeout觸發(fā),除了設(shè)置重試碟绑,也可以定制重試的時間閥值以及重試次數(shù)等俺猿。

對于除了使用Feign,也使用Spring RestTemplate的應(yīng)用格仲,可以通過自定義的RestTemplate,對于返回的ResponseEntity對象進(jìn)行結(jié)果解析押袍,如果請求需要重試(比如某個固定格式的error-code的方式識別重試策略),則通過Interceptor進(jìn)行請求攔截凯肋,以及回調(diào)的方式invoke多次請求谊惭。想學(xué)文中的技術(shù)可以加入我的群:619881427

小結(jié)

對于微服務(wù)的架構(gòu),通過一個獨立的API Gateway,可以進(jìn)行統(tǒng)一的請求轉(zhuǎn)發(fā)侮东、合并以及協(xié)議轉(zhuǎn)換圈盔。可以更靈活得適配不同客戶端的請求數(shù)據(jù)悄雅。而且對于不同客戶端(比如H5和iOS的展示數(shù)據(jù)不同)驱敲、不同版本兼容的請求,可以很好地在Gateway進(jìn)行屏蔽,讓微服務(wù)更加純粹宽闲。微服務(wù)只要關(guān)注內(nèi)部的領(lǐng)域服務(wù)的設(shè)計众眨,事件的處理握牧。

API gateway還可以對微服務(wù)的請求進(jìn)行一定的容錯、服務(wù)降級娩梨。使用響應(yīng)式編程來實現(xiàn)API gateway可以使線程同步我碟、并發(fā)的代碼更簡潔,更易于維護(hù)姚建。在對于微服務(wù)的請求可以統(tǒng)一通過FeignClint矫俺。代碼也會很有層次。如下圖掸冤,是一個示例的請求的類層次厘托。

M-8

Clint負(fù)責(zé)集成服務(wù)發(fā)現(xiàn)(對于使用Eureka自注冊方式)、負(fù)載均衡以及發(fā)出請求稿湿,并獲取ResponseEntity對象铅匹。

Translator將ResponseEntity轉(zhuǎn)換成Observable對象,以及對異常進(jìn)行統(tǒng)一日志采集饺藤,類似于DDD中防腐層的概念包斑。

Adapter調(diào)用各個Translator,使用Observable函數(shù)涕俗,對請求的數(shù)據(jù)流進(jìn)行合并罗丰。如果存在多個數(shù)據(jù)的組裝,可以增加一層Assembler專門處理DTO對象到Model的轉(zhuǎn)換再姑。

Controller,提供Restful資源的管理萌抵,每個Controller只請求唯一的一個Adapter方法。

服務(wù)集群的解決方案

企業(yè)在實踐使用Docker部署元镀、運行微服務(wù)應(yīng)用的時候绍填,無論是一開始就布局微服務(wù)架構(gòu),或者從傳統(tǒng)的單應(yīng)用架構(gòu)進(jìn)行微服務(wù)化遷移栖疑。都需要能夠處理復(fù)雜的集群中的服務(wù)調(diào)度讨永、編排、監(jiān)控等問題遇革。下面主要為介紹在分布式的服務(wù)集群下卿闹,如何更安全、高效得使用Docker,以及在架構(gòu)設(shè)計上澳淑,需要考慮的方方面面比原。

負(fù)載均衡

這里說的是集群中的負(fù)載均衡,如果是純服務(wù)端API的話就是指Gateway API的負(fù)載均衡杠巡,如果使用了Nginx的話,則是指Nginx的負(fù)載均衡雇寇。我們目前使用的是阿里云的負(fù)載均衡服務(wù)SLB氢拥。其中一個主要原因是可以跟DNS域名服務(wù)進(jìn)行綁定蚌铜。對于剛開始進(jìn)行創(chuàng)業(yè)的公司來說,可以通過Web界面來設(shè)置負(fù)載均衡的權(quán)重嫩海,比較便于部分發(fā)布冬殃、測試驗證,以及健康檢查監(jiān)控等等。從效率和節(jié)約運維成本上來說都是個比較適合的選擇叁怪。

如果自己搭建七層負(fù)載均衡如使用Nginx或Haproxy的話审葬,也需要保證負(fù)責(zé)負(fù)載均衡的集群也是高可用的,以及提供便捷的集群監(jiān)控,藍(lán)綠部署等功能奕谭。

持久化及緩存

關(guān)系型數(shù)據(jù)庫(RDBMS)

對于微服務(wù)來說涣觉,使用的存儲技術(shù)主要是根據(jù)企業(yè)的需要。為了節(jié)約成本的話血柳,一般都是選用Mysql官册,在Mysql的引擎選擇的話建議選擇InnoDB引擎(5.5版本之前默認(rèn)MyISAM)。InnoDB在處理并發(fā)時更高效难捌,其查詢性能的差距也可以通過緩存膝宁、搜索等方案進(jìn)行彌補。InnoDB處理數(shù)據(jù)拷貝根吁、備份的免費方案有binlog员淫,mysqldump。不過要做到自動化的備份恢復(fù)击敌、可監(jiān)控的數(shù)據(jù)中心還是需要DBA或者運維團(tuán)隊满粗。相對花費的成本也較高。如果初創(chuàng)企業(yè)愚争,也可以考慮依托一些國內(nèi)外比較大型的云計算平臺提供的PaaS服務(wù)映皆。

微服務(wù)一般按照業(yè)務(wù)領(lǐng)域進(jìn)行邊界劃分,所以微服務(wù)最好是一開始就進(jìn)行分庫設(shè)計轰枝。是否需要進(jìn)行分表需要根據(jù)每個微服務(wù)具體的業(yè)務(wù)領(lǐng)域的發(fā)展以及數(shù)據(jù)規(guī)模進(jìn)行具體分析捅彻。但建議對于比較核心的領(lǐng)域的模型,比如“訂單”提前做好分表字段的設(shè)計和預(yù)留鞍陨。

KV模型數(shù)據(jù)庫(Key-Value-stores)

Redis是開源的Key-Value結(jié)構(gòu)的數(shù)據(jù)庫步淹。其基于內(nèi)存,具有高效緩存的性能诚撵,同時也支持持久化缭裆。Redis主要有兩種持久化方式。一種是RDB寿烟,通過指定時間間隔生成數(shù)據(jù)集的時間點快照澈驼,從內(nèi)存寫入磁盤進(jìn)行持久化。RDB方式會引起一定程度的數(shù)據(jù)丟失筛武,但性能好缝其。另外一種是AOF,其寫入機制挎塌,有點類似InnoDB的binlog,AOF的文件的命令都是以Redis協(xié)議格式保存内边。這兩種持久化是可以同時存在的榴都,在Redis重啟時,AOF文件會被優(yōu)先用于恢復(fù)數(shù)據(jù)漠其。因為持久化是可選項嘴高,所以也可以禁用Redis持久化。

在實際的場景中和屎,建議保留持久化拴驮。比如目前比較流行的解決短信驗證碼的驗證,就可使用Redis眶俩。在微服務(wù)架構(gòu)體系中莹汤,也可以用Redis處理一些KV數(shù)據(jù)結(jié)構(gòu)的場景。輕量級的數(shù)據(jù)存儲方案颠印,也很適合本身強調(diào)輕量級方案的微服務(wù)思想纲岭。

我們在實踐中,是對Redis進(jìn)行了緩存线罕、持久化止潮,兩個功能特征進(jìn)行分庫的。

在集成Springboot項目中會使用到spring-boot-starter-data-redis來進(jìn)行Redis的數(shù)據(jù)庫連接以及基礎(chǔ)配置钞楼、以及spring-data-redis提供的豐富的數(shù)據(jù)APIOperations喇闸。

另外,如果是要求高吞吐量的應(yīng)用询件,可以考慮用Memcached來專門做簡單的KV數(shù)據(jù)結(jié)構(gòu)的緩存燃乍。其比較適合大數(shù)據(jù)量的讀取,但支持的數(shù)據(jù)結(jié)構(gòu)類型比較單一宛琅。

圖形數(shù)據(jù)庫(Graph Database)

涉及到社交相關(guān)的模型數(shù)據(jù)的存儲刻蟹,圖形數(shù)據(jù)庫是一種相交關(guān)系型數(shù)據(jù)庫更高效、更靈活的選擇嘿辟。圖形數(shù)據(jù)庫也是Nosql的一種舆瘪。其和KV不同,存儲的數(shù)據(jù)主要是數(shù)據(jù)節(jié)點(node),具有指向性的關(guān)系(Relationship)以及節(jié)點和關(guān)系上的屬性(Property)红伦。

如果用Java作為微服務(wù)的主開發(fā)語言英古,最好選擇Neo4j。Neo4j是一種基于Java實現(xiàn)的支持ACID的圖形數(shù)據(jù)庫昙读。其提供了豐富的JavaAPI召调。在性能方面,圖形數(shù)據(jù)庫的局部性使遍歷的速度非常快某残,尤其是大規(guī)模深度遍歷国撵。這個是關(guān)系型數(shù)據(jù)庫的多表關(guān)聯(lián)無法企及的陵吸。

下圖是使用Neo4j的WebUI工具展示的一個官方Getting started數(shù)據(jù)模型示例玻墅。示例中的語句MATCH p=()-[r:DIRECTED]->() RETURN p LIMIT 25是Neo4j提供的查詢語言——Cypher。

M-9

在項目使用時可以集成SpringData的項目Spring Data Neo4j壮虫。以及SpringBootStartersspring-boot-starter-data-neo4j

文檔數(shù)據(jù)庫(Document database)

目前應(yīng)用的比較廣泛的開源的面向文檔的數(shù)據(jù)庫可以用Mongodb澳厢。Mongo具有高可用、高可伸縮性以及靈活的數(shù)據(jù)結(jié)構(gòu)存儲囚似,尤其是對于Json數(shù)據(jù)結(jié)構(gòu)的存儲剩拢。比較適合博客、評論等模型的存儲饶唤。

搜索技術(shù)

在開發(fā)的過程中徐伐,有時候經(jīng)常會看到有人寫了很長很繞、很難維護(hù)的多表查詢SQL募狂,或者是各種多表關(guān)聯(lián)的子查詢語句办素。對于某一領(lǐng)域模型,當(dāng)這種場景多的時候祸穷,就該考慮接入一套搜索方案了性穿。不要什么都用SQL去解決,尤其是查詢的場景雷滚。慢查詢語句的問題有時候甚至?xí)峡錎B需曾,如果DB的監(jiān)控體系做的不到位,可能問題也很難排查祈远。

Elasticsearch是一個基于Apache Lucene實現(xiàn)的開源的實時分布式搜索和分析引擎呆万。Springboot的項目也提供了集成方式: spring-boot-starter-data-elasticsearch以及spring-data-elasticsearch。

對于搜索集群的搭建车份,可以使用Docker谋减。具體搭建方法可以參考用Docker搭建Elasticsearch集群,對于Springboot項目的集成可以參考在Springboot微服務(wù)中集成搜索服務(wù)。至今躬充,最新版本的SpringDataElasticsearch已經(jīng)支持到了5.x版本的ES逃顶,可以解決很多2.x版本的痛點了。

如果是小規(guī)模的搜索集群充甚,可以用三臺低配置的機器以政,然后用ES的Docker進(jìn)項進(jìn)行搭建。也可以使用一些商業(yè)版的PaaS服務(wù)伴找。如何選擇還是要根據(jù)團(tuán)隊和業(yè)務(wù)的規(guī)模盈蛮、場景來看。

目前除了ES,使用比較廣泛的開源搜索引擎還有Solr,Solr也基于Lucene,且專注在文本搜索技矮。而ES的文本搜索確實不如Solr,ES主要專注于對分布式的支持抖誉,并且內(nèi)置了服務(wù)發(fā)現(xiàn)組件Zen來維護(hù)集群狀態(tài)殊轴,相對Solr(需要借助類似Zookeeper實現(xiàn)分布式)部署也更加輕量級。ES除了分析查詢袒炉,還可以集成日志收集以及做分析處理旁理。

消息隊列

消息隊列如前篇所述,可以作為很好的微服務(wù)解耦通信方式我磁。在分布式集群的場景下孽文,對于分布式下的最終一致性也可以提供技術(shù)基礎(chǔ)保障。并且消息隊列也可以用來處理流量削鋒夺艰。

消息隊列的對比在此不再贅述芋哭。目前公司使用的是阿里云的ONS。因為使用消息隊列還是考慮用在對高可用以及易于管理郁副、監(jiān)控上的要求减牺,所以選擇了安全可靠的消息隊列平臺。

安全技術(shù)

安全性是做架構(gòu)需要考慮的基礎(chǔ)存谎“尉危互聯(lián)網(wǎng)的環(huán)境復(fù)雜,保護(hù)好服務(wù)的安全愕贡,也是對用戶的基本承諾草雕。安全技術(shù)涉及到的范圍比較廣,本文選幾個常見問題以及常用方式來簡單介紹下固以。

服務(wù)實例安全

分布式集群本身就是對于服務(wù)實例安全的一種保障墩虹。一臺服務(wù)器或者某一個服務(wù)實例出現(xiàn)問題的時候,負(fù)載均衡可以將請求轉(zhuǎn)發(fā)到其他可用的服務(wù)實例憨琳。但很多企業(yè)是自建機房诫钓,而且是單機房的,這種布局其實比較危險篙螟。因為服務(wù)器的備份容災(zāi)也得不到完整的保障菌湃。最怕的就是數(shù)據(jù)庫也是在同一機房,主備全都在一起遍略。不單是安全性得不到很高的保障惧所,平常的運維花銷也會比較大。而且需要注意配置防火墻安全策略绪杏。

如果可以下愈,盡量使用一些高可用、高可伸縮的穩(wěn)定性IaaS平臺蕾久。

網(wǎng)絡(luò)安全

1. 預(yù)防網(wǎng)絡(luò)攻擊

目前主要的網(wǎng)絡(luò)攻擊有一下幾種:

SQL注入:根據(jù)不同的持久層框架势似,應(yīng)對策略不同。如果使用JPA,則只要遵循JPA的規(guī)范履因,基本不用擔(dān)心障簿。

XSS攻擊:做好參數(shù)的轉(zhuǎn)義處理和校驗。具體參考XSS預(yù)防

CSRF攻擊:做好Http的Header信息的Token栅迄、Refer驗證站故。具體參考CSRF預(yù)防

DDOS攻擊:大流量的DDoS攻擊,一般是采用高防IP霞篡。也可以接入一些云計算平臺的高防IP世蔗。

以上只是列舉了幾種常見的攻擊端逼,想要深入了解的可以多看看REST安全防范表朗兵。在網(wǎng)絡(luò)安全領(lǐng)域,一般很容易被初創(chuàng)企業(yè)忽視顶滩,如果沒有一個運維安全團(tuán)隊余掖,最好使用類似阿里云-云盾之類的產(chǎn)品。省心省成本礁鲁。

2. 使用安全協(xié)議

這個不用多說盐欺,無論是對于使用Restful API的微服務(wù)通信,還是使用的CDN或者使用的DNS服務(wù)仅醇。涉及到Http協(xié)議的冗美,建議都統(tǒng)一使用Https。無論是什么規(guī)模的應(yīng)用析二,都要防范流量劫持粉洼,否則將會給用戶帶來很不好的使用體驗。

3. 鑒權(quán)

關(guān)于微服務(wù)的鑒權(quán)前面API Gateway已經(jīng)有介紹叶摄。除了微服務(wù)本身之外属韧,我們使用的一些如Mysql,Redis,Elasticsearch,Eureka等服務(wù)蛤吓,也需要設(shè)置好鑒權(quán)宵喂,并且盡量通過內(nèi)網(wǎng)訪問。不要對外暴露過多的端口会傲。對于微服務(wù)的API Gateway,除了鑒權(quán)锅棕,最好前端通過Nginx反向代理來請求API層。

日志采集淌山、監(jiān)控

基于容器技術(shù)的微服務(wù)的監(jiān)控體系面臨著更復(fù)雜的網(wǎng)絡(luò)裸燎、服務(wù)環(huán)境。日志采集艾岂、監(jiān)控如何能對微服務(wù)減少侵入性顺少、對開發(fā)者更透明,一直是很多微服務(wù)的DevOps在不斷思考和實踐的。

1. 微服務(wù)日志的采集

微服務(wù)的API層的監(jiān)控脆炎,需要從API Gateway到每個微服務(wù)的調(diào)用路徑的跟蹤梅猿,采集以及分析。使用Rest API的話秒裕,為了對所有請求進(jìn)行采集袱蚓,可以使用Spring Web的OncePerRequestFilter對所有請求進(jìn)行攔截,在采集日志的時候几蜻,也最好對請求的rt進(jìn)行記錄喇潘。

除了記錄access,request等信息梭稚,還需要對API調(diào)用進(jìn)行請求跟蹤颖低。如果單純記錄每個服務(wù)以及Gateway的日志,那么當(dāng)Gateway Log出現(xiàn)異常的時候弧烤,就不知道其具體是微服務(wù)的哪個容器實例出現(xiàn)了問題忱屑。如果容器達(dá)到一定數(shù)量,也不可能排查所有容器以及服務(wù)實例的日志暇昂。比較簡單的解決方式就是對log信息都append一段含有容器信息的莺戒、唯一可標(biāo)識的Trace串。

日志采集之后急波,還需要對其進(jìn)行分析从铲。如果使用E.L.K的技術(shù)體系,就可以靈活運用Elasticsearch的實時分布式特性澄暮。Logstash可以進(jìn)行日志進(jìn)行收集名段、分析,并將數(shù)據(jù)同步到Elasticsearch赏寇。Kibana結(jié)合Logstash和ElasticSearch吉嫩,提供良好的便于日志分析的WebUI,增強日志數(shù)據(jù)的可視化管理嗅定。

對于數(shù)據(jù)量大的日志的采集自娩,為了提升采集性能,需要使用上文提到的消息隊列渠退。優(yōu)化后的架構(gòu)如下:

M-10

2. 基礎(chǔ)服務(wù)的調(diào)用日志采集

通過對微服務(wù)的所有Rest API的日志采集忙迁、分析可以監(jiān)控請求信息。

在服務(wù)內(nèi)部碎乃,對于中間件姊扔、基礎(chǔ)設(shè)施(包括Redis,Mysql,Elasticsearch等)調(diào)用的性能的日志采集和分析也是必要的。

對于中間件服務(wù)的日志采集梅誓,我們目前可以通過動態(tài)代理的方式恰梢,對于服務(wù)調(diào)用的如cache佛南、repository(包括搜索和DB)的基礎(chǔ)方法,進(jìn)行攔截及回調(diào)日志記錄方法嵌言。具體的實現(xiàn)方式可以采用字節(jié)碼生成框架ASM,關(guān)于方法的邏輯注入嗅回,可以參考之前寫的一篇ASM(四) 利用Method 組件動態(tài)注入方法邏輯,如果覺得ASM代碼不太好維護(hù)摧茴,也可以使用相對API友好的Cglib绵载。

架構(gòu)五要素:

最后,結(jié)合架構(gòu)核心的五要素來回顧下我們在搭建Docker微服務(wù)架構(gòu)使用的技術(shù)體系:

高性能

消息隊列苛白、RxJava異步并發(fā)娃豹、分布式緩存、本地緩存购裙、Http的Etag緩存懂版、使用Elasticsearch優(yōu)化查詢、CDN等等缓窜。

可用性

容器服務(wù)集群疼鸟、RxJava的熔斷處理捂人、服務(wù)降級、消息的冪等處理刷允、超時機制摹察、重試機制恩掷、分布式最終一致性等等。

伸縮性

服務(wù)器集群的伸縮供嚎、容器編排Kubernetes黄娘、數(shù)據(jù)庫分庫分表、Nosql的線性伸縮克滴、搜索集群的可伸縮等等逼争。

擴展性

基于Docker的微服務(wù)本身就是為了擴展性而生!

安全性

JPA/Hibernate,SpringSecurity劝赔、高防IP誓焦、日志監(jiān)控、Https着帽、Nginx反向代理杂伟、HTTP/2.0等等。

小結(jié)

對于服務(wù)集群的解決方案仍翰,其實無論是微服務(wù)架構(gòu)或者SOA架構(gòu)赫粥,都是比較通用的。只是對于一些中間件集群的搭建予借,可以使用Docker越平。一句Docker ps就可以很方便查詢運行的服務(wù)信息频蛔,并且升級基礎(chǔ)服務(wù)也很方便。

對于優(yōu)秀的集群架構(gòu)設(shè)計的追求是永無止境的秦叛。在跟很多創(chuàng)業(yè)公司的技術(shù)朋友們接觸下來帽驯,大家都是比較偏向于快速搭建以及開發(fā)、發(fā)布服務(wù)书闸。然而一方面也顧慮微服務(wù)的架構(gòu)會比較復(fù)雜尼变,殺雞用牛刀。但是微服務(wù)本身就是一種敏捷模式的優(yōu)秀實踐浆劲。這些朋友往往會在業(yè)務(wù)飛速發(fā)展的時候面臨一個困擾嫌术,就是服務(wù)拆分,數(shù)據(jù)庫的分庫分表牌借、通過消息去解耦像面條一樣的同步代碼度气,想要優(yōu)化性能但是無從下手的尷尬。

后記

本文主要是對于Docker的微服務(wù)實踐進(jìn)行技術(shù)方案選型以及介紹膨报。不同的業(yè)務(wù)磷籍、團(tuán)隊可能會適合不通過的架構(gòu)體系和技術(shù)方案。

作為架構(gòu)師應(yīng)該結(jié)合公司近期现柠、長期的戰(zhàn)略規(guī)劃院领,進(jìn)行長遠(yuǎn)的布局。最起碼基礎(chǔ)的架構(gòu)也是需要能支撐3年發(fā)展够吩,期間可以不斷引入新的技術(shù)并進(jìn)行服務(wù)升級和持續(xù)的代碼層重構(gòu)比然。

也許一個架構(gòu)師從0開始搭建一整套體系并不需要花費多久時間,最需要其進(jìn)行的就是不斷在團(tuán)隊推行Domain-Driven Design周循。并且使團(tuán)隊一起遵循Clean Code强法,進(jìn)行敏捷開發(fā)OvO。


鏈接:http://www.reibang.com/p/1638146c04b2

來源:簡書

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末湾笛,一起剝皮案震驚了整個濱河市饮怯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嚎研,老刑警劉巖蓖墅,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘉赎,居然都是意外死亡置媳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門公条,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拇囊,“玉大人,你說我怎么就攤上這事靶橱×认” “怎么了路捧?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長传黄。 經(jīng)常有香客問我杰扫,道長,這世上最難降的妖魔是什么膘掰? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任章姓,我火速辦了婚禮,結(jié)果婚禮上识埋,老公的妹妹穿的比我還像新娘凡伊。我一直安慰自己,他們只是感情好窒舟,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布系忙。 她就那樣靜靜地躺著,像睡著了一般惠豺。 火紅的嫁衣襯著肌膚如雪银还。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天洁墙,我揣著相機與錄音蛹疯,去河邊找鬼。 笑死扫俺,一個胖子當(dāng)著我的面吹牛苍苞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狼纬,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骂际!你這毒婦竟也來了疗琉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤歉铝,失蹤者是張志新(化名)和其女友劉穎盈简,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體太示,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡柠贤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了类缤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臼勉。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖餐弱,靈堂內(nèi)的尸體忽然破棺而出宴霸,到底是詐尸還是另有隱情囱晴,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布瓢谢,位于F島的核電站畸写,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氓扛。R本人自食惡果不足惜枯芬,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望采郎。 院中可真熱鬧千所,春花似錦、人聲如沸尉剩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽理茎。三九已至黑界,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間皂林,已是汗流浹背朗鸠。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留础倍,地道東北人烛占。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像沟启,于是被迫代替她去往敵國和親忆家。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容