內容不斷完善中,訪問 文檔查看最新更新
當下,已經有很大一部分公司完成了單體架構向微服務架構的遷移改造,並在疲於應對大量微服務間通訊問題時,開始考慮採用Service Mesh微服務架構做爲服務與服務直接通訊的透明化管理框架,以插件式的方式實現各類業務所需的高級管理功能。html
而開源PaaS Rainbond提供了開箱即用的Service Mesh微服務架構,部署在Rainbond上的應用原生便是Service Mesh微服務架構應用。前端
接下來,咱們將以 Rainbond v3.7.0 爲基礎平臺,以開源商城項目 sockshop 爲例,演示如何在源代碼無入侵的狀況下,將項目改造爲具備服務註冊與發現
、分佈式跟蹤
、A/B測試
、灰度發佈
、限流
、熔斷
、 性能分析
、高可用
、日誌分析
等能力的高可靠性電商業務系統。java
一鍵部署Rainbond請查看 快速開始。sockshop是一個典型的微服務架構案例,具有用戶管理、商品管理、購物車、訂單流程、地址管理等完善的電商相關功能。sockshop主要由
Spring boot
、Golang
、Nodejs
等多種語言開發,使用MySQL
和MongoDB
等多種數據庫,原方案採用單機環境下的部署方式,缺少服務治理能力和分佈式能力。node
sockshop部署後的拓撲圖總覽mysql
sockshop商城首頁預覽圖git
sockshop架構圖github
更多信息golang
Rainbond支持從源碼、鏡像、應用市場等多種方式進行應用部署,這裏咱們採用DockerCompose配置文件
的建立方式,批量建立 sockshop 中包含的全部服務。web
須要注意的是,在檢測和建立過程當中,獲取大量鏡像須要必定時間,請耐心等待完成!
version: '2' services: front-end: image: weaveworksdemos/front-end:0.3.12 hostname: front-end restart: always cap_drop: - all ports: - "8079:8079" - "9001:9001" depends_on: - catalogue - carts - payment - user - orders edge-router: image: weaveworksdemos/edge-router:0.1.1 ports: - '80:80' - '8080:8080' cap_drop: - all cap_add: - NET_BIND_SERVICE - CHOWN - SETGID - SETUID - DAC_OVERRIDE tmpfs: - /var/run:rw,noexec,nosuid hostname: edge-router restart: always depends_on: - front-end catalogue: image: weaveworksdemos/catalogue:0.3.5 hostname: catalogue restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE depends_on: - catalogue-db - zipkin catalogue-db: image: rilweic/catalog-db hostname: catalogue-db restart: always environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_ALLOW_EMPTY_PASSWORD=true - MYSQL_DATABASE=socksdb carts: image: weaveworksdemos/carts:0.4.8 hostname: carts restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE tmpfs: - /tmp:rw,noexec,nosuid environment: - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false ports: - "80:80" depends_on: - carts-db - zipkin carts-db: image: mongo:3.4 hostname: carts-db restart: always cap_drop: - all cap_add: - CHOWN - SETGID - SETUID tmpfs: - /tmp:rw,noexec,nosuid orders: image: rilweic/orders hostname: orders restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE tmpfs: - /tmp:rw,noexec,nosuid environment: - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false ports: - "8848:8848" depends_on: - orders-db - zipkin - shipping - carts - payment - user orders-db: image: mongo:3.4 hostname: orders-db restart: always cap_drop: - all cap_add: - CHOWN - SETGID - SETUID tmpfs: - /tmp:rw,noexec,nosuid shipping: image: Rainbond/shipping:0.4.8 hostname: shipping restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE tmpfs: - /tmp:rw,noexec,nosuid environment: - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false ports: - "8080:8080" depends_on: - rabbitmq - zipkin queue-master: image: weaveworksdemos/queue-master:0.3.1 hostname: queue-master restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE tmpfs: - /tmp:rw,noexec,nosuid depends_on: - rabbitmq rabbitmq: image: rabbitmq:3.6.8 hostname: rabbitmq restart: always cap_drop: - all cap_add: - CHOWN - SETGID - SETUID - DAC_OVERRIDE payment: image: weaveworksdemos/payment:0.4.3 hostname: payment restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE depends_on: - zipkin user: image: weaveworksdemos/user:0.4.4 hostname: user restart: always cap_drop: - all cap_add: - NET_BIND_SERVICE environment: - MONGO_HOST=user-db:27017 depends_on: - user-db - zipkin user-db: image: weaveworksdemos/user-db:0.4.0 hostname: user-db restart: always cap_drop: - all cap_add: - CHOWN - SETGID - SETUID tmpfs: - /tmp:rw,noexec,nosuid zipkin: image: openzipkin/zipkin hostname: zipkin restart: always cap_drop: - all cap_add: - CHOWN - SETGID - SETUID tmpfs: - /tmp:rw,noexec,nosuid environment: - reschedule=on-node-failure ports: - "9411:9411"
源碼、應用市場等其餘建立方式請參考Rainbond文檔: 建立一個應用
服務建立完成後,咱們須要對批量建立的服務進行註冊和對部署內存的調整,根據服務之間的調用關係,分析出哪些服務是做爲內部服務供給其它服務調用、哪一個服務是對用戶提供訪問的,並進行接下來的操做:spring
在 Rainbond 平臺,咱們能夠經過在服務的端口頁打開端口來進行服務的註冊。關於服務註冊的詳細文檔可參考Rainbond 平臺服務註冊
各服務對應的端口和部署內存大小以下:
請注意,這裏必須肯定對每一個服務組件的服務註冊信息和資源分配信息設置正確。
sockshop經過內部域名來進行服務調用,也就是說,在完成服務的註冊後,調用服務須要發現被調用服務。
在 Rainbond 平臺,咱們能夠經過服務依賴來實現(詳情參考文檔服務發現)。
各服務依賴的詳情可參考上圖商城在Rainbond平臺的概覽
若是使用上面的 docker-compose 文件建立應用,無需手動添加依賴,在建立應用時系統已根據 docker-compose 文件內容自動配置了服務發現
在sockshop案例中,front-end
爲nodejs
項目,該服務會調用其餘 5 個服務來獲取數據,如圖所示:
front-end
在調用其餘服務時,會使用域名+端口的調用方式(該項目全部調用均爲此方式)
如 front-end
調用 orders
時,內部訪問地址爲 http://orders/xxx
.
Rainbond 平臺在服務進行調用時,會默認將頂級域名
解析到127.0.0.1
,若是調用的服務對應的端口都不衝突沒有任何問題,而在此案例中,front-end
調用的其餘 5 個服務的端口均爲 80。所以這裏須要第一個治理功能:端口複用。
在不安裝 7 層網絡治理插件的狀況下,平臺默認使用 4 層網絡治理插件,沒法提供端口複用的機制。所以,咱們爲服務front-end
orders
分別安裝網絡治理插件。
在個人插件
中選擇服務網絡治理插件
進行安裝。
特別注意
工做在 7 層的 Mesh 插件默認會佔用 80 端口,所以須要安裝此插件的服務自己不能佔用 80 端口。所以咱們推薦服務儘可能監聽非 80 端口。插件內存使用量須要根據流量大小調節。
在應用詳情頁面選擇插件
標籤,而後開通指定的插件。
Rainbond默認提供的服務網絡治理插件是基於 Envoy製做,Rainbond ServiceMesh架構爲Envoy提供了標準的運行支持。安裝插件後需重啓應用生效。
配置域名路由,實現端口複用。爲了front-end
服務能根據代碼已有的域名調用選擇對應的服務提供方,咱們須要根據其調用的域名來進行配置。將應用進行依賴後,服務網絡治理插件
可以自動識別出其依賴的應用。咱們只需在插件的配置的域名項中進行域名配置便可。以下圖:
詳細配置
更新插件相關的配置後進行保存並重啓相關應用便可。此處暫時先只用到基於域名的路由配置,關於網絡治理插件的更對詳情可參考 服務路由,灰度發佈,A/B 測試
微服務是一個分佈式的架構模式,它一直以來都會有一些自身的問題。當一個應用的運行狀態出現異常時,對於運維和開發人員來講,即時發現應用的狀態異常並解決是很是有必要的。咱們能夠經過監控手段對服務進行衡量,或者作一個數據支撐。
Rainbond 平臺爲咱們提供了服務監控與性能監控,能夠簡單直觀的瞭解服務當前的狀態和信息。
目前支持 HTTP 與 mysql 協議的應用
同上應用網絡治理插件安裝
安裝完成性能分析插件,能夠在安裝該插件的應用概覽頁面查看應用的平均響應時間
和吞吐率
。
除此之外,咱們也能夠在該組應用的組概覽中看到應用的訪問狀況。
sockshop 商城案例自帶性能測試的服務,可是與該項目不是持續運行,而是運行一次後程序便會退出。在這裏,咱們根據源碼進行了一點小的修改。主要是將程序變爲不退出運行。源碼地址
咱們能夠經過源碼方式來建立項目——
建立完成後,咱們須要在 sockshop 商城建立一個帳號爲user
、密碼爲password
的用戶,負載測試須要使用該用戶名來和密碼進行模擬請求。
完成以上步驟,接下來咱們對sockshop的分佈式跟蹤進行處理。
隨着業務愈來愈複雜,系統也隨之進行各類拆分,特別是隨着微服務架構和容器技術的興起,看似簡單的一個應用,後臺可能有幾十個甚至幾百個服務在支撐;一個前端的請求可能須要屢次的服務調用最後才能完成;當請求變慢或者不可用時,咱們沒法得知是哪一個後臺服務引發的,這時就須要解決如何快速定位服務故障點,Zipkin 分佈式跟蹤系統就能很好的解決這樣的問題。
Zipkin 分佈式跟蹤系統;它能夠幫助收集時間數據,解決在 microservice 架構下的延遲問題;它管理這些數據的收集和查找;Zipkin 的設計是基於谷歌的 Google Dapper 論文。
每一個應用程序向 Zipkin 報告定時數據,Zipkin UI 呈現了一個依賴圖表來展現多少跟蹤請求通過了每一個應用程序;若是想解決延遲問題,能夠過濾或者排序全部的跟蹤請求,而且能夠查看每一個跟蹤請求佔總跟蹤時間的百分比。
裝配了 zipkin 跟蹤器的服務能夠將服務的每次調用(能夠是 http 或者 rpc 或數據庫調用等)延時經過Transport
(目前有 4 總共發送方式,http,kafka,scribe,rabbitmq
)發送給zipkin
服務。
zipkin 主要包含 4 個模塊
collector: 接收或收集各應用傳輸的數據。
storage: 存儲接受或收集過來的數據,當前支持 Memory,MySQL,Cassandra,ElasticSearch 等,默認存儲在內存中。
API(Query): 負責查詢 Storage 中存儲的數據,提供簡單的 JSON API 獲取數據,主要提供給 web UI 使用
Web: 提供簡單的 web 界面
從上圖能夠簡單歸納爲一次請求調用,zipkin 會在請求中加入跟蹤的頭部信息和相應的註釋,並記錄調用的時間並將數據返回給 zipkin 的收集器 collector。
在 Rinbond 平臺,咱們能夠直接經過 docker run 方式運行 zipkin.
注意開啓對外訪問端口和調整應用內存大小
此時建立的 zipkin 的數據存在於內存中,服務關閉或重啓數據都會丟失。所以在生產環境中,咱們須要將數據存入存儲。
zipkin 支持 MySQL,Cassandra,ElasticSearch 三種存儲。咱們以 Mysql 爲例說明。目前 zipkin 至此的 mysql 版本爲 5.6 和 5.7 版本。
在 Rainbond 平臺應用市場建立版本爲 5.7 的 mysql 應用,如圖。
建立完成 mysql 之後,咱們須要進行數據庫的初始化操做,zipkin 須要使用到 zipkin 數據和相應的表結構,須要咱們自行建立。
在應用的詳情頁面,咱們能夠選擇管理容器
進入到容器進行操做,如圖。
進入容器後,使用命令登陸 mysql 命令行。
mysql -uusername -ppassword
mysql 的用戶和密碼能夠在應用的依賴裏看到
如圖
進入 mysql 命令行後,建立數據庫 zipkin
CREATE DATABASE zipkin ;
建立 zipkin 相關的表:下載
CREATE TABLE IF NOT EXISTS zipkin_spans ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL, `id` BIGINT NOT NULL, `name` VARCHAR(255) NOT NULL, `parent_id` BIGINT, `debug` BIT(1), `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds'; ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames'; ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range'; CREATE TABLE IF NOT EXISTS zipkin_annotations ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames'; ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job'; CREATE TABLE IF NOT EXISTS zipkin_dependencies ( `day` DATE NOT NULL, `parent` VARCHAR(255) NOT NULL, `child` VARCHAR(255) NOT NULL, `call_count` BIGINT, `error_count` BIGINT ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);
在 zipkin 服務中添加環境變量 STORAGE_TYPE
爲 mysql
,此變量標誌 zipkin 使用的存儲方式。可選擇值爲 mysql
,elasticsearch
、cassandra
將 zipkin 與 mysql 創建依賴關係後,zipkin 服務便安裝完成。
zipkin 內部會默認調用環境變量MYSQL_USER
(用戶名),MYSQL_PASS
(密碼),MYSQL_HOST
(鏈接地址),MYSQL_PORT
(端口)。恰好與 Rainbond 平臺默認設置的變量一致,因此無需作任何修改。其餘服務若是鏈接的變量與 Rainbond 平臺默認提供的不一致,咱們能夠在應用的設置也添加相應的環境變量來達到訪問的目的。
sockshop 案例集成了zipkin
作分佈式跟蹤。集成的組件爲 users
、carts
、orders
、payment
、catalogue
、shipping
。
其中 carts
、orders
、shipping
爲spring-boot項目,只需在設置中將環境變量JAVA_OPTS
的-Dspring.zipkin.enabled
改成true
便可。
如圖
payment
、catalogue
、users
爲golang
項目,項目已在內部集成了 zipkin 組件,咱們須要添加環境變量ZIPKIN
爲http://zipkin:9411/api/v1/spans
來明確服務調用 zipkin 的地址。
如圖
設置完成後,能夠作直接訪問 zipkin 應用對外提供的訪問地址。訪問詳情如圖
咱們能夠在該圖中查看各個服務調用的延時詳情。
至此,咱們已經完成了基礎部署,能夠看到完整的業務拓撲圖,sockshop也已經能夠正常工做了。絕不誇張得說,項目與實際電商系統也只是差一些業務邏輯了:)
接下來的進階部分,咱們會完成每個服務的水平伸縮
、持續集成與部署
、數據備份
、灰度發佈
等,敬請關注。
Rainbond是一款以應用爲中心的開源PaaS,由好雨基於Docker、Kubernetes等容器技術自主研發,可做爲公有云或私有云環境下的應用交付平臺、DevOps平臺、自動化運維平臺和行業雲平臺,或做爲企業級的混合雲多雲管理工具、Kubernetes容器管理工具或Service Mesh微服務架構治理工具。