共計 10939 個字符,預計需要花費 28 分鐘才能閱讀完成。
這篇文章將為大家詳細講解有關如何實踐 Service Mesh 微服務架構的基礎部署,文章內容質量較高,因此丸趣 TV 小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
當下,已經有很大一部分公司完成了單體架構向微服務架構的遷移改造,并在疲于應對大量微服務間通信問題時,開始考慮采用 Service Mesh 微服務架構作為服務與服務直接通信的透明化管理框架,以插件式的方式實現各種業務所需的高級管理功能。
而開源 PaaS Rainbond 提供了開箱即用的 Service Mesh 微服務架構,部署在 Rainbond 上的應用原生即是 Service Mesh 微服務架構應用。
接下來,我們將以 Rainbond v3.7.0 為基礎平臺,以開源商城項目 sockshop 為例,演示如何在源代碼無入侵的情況下,將項目改造為具有服務注冊與發現、分布式跟蹤、A/ B 測試、灰度發布、限流、熔斷、性能分析、高可用、日志分析等能力的高可靠性電商業務系統.
sockshop 是一個典型的微服務架構案例,具備用戶管理、商品管理、購物車、訂單流程、地址管理等完善的電商相關功能。sockshop 主要由 Spring boot、Golang、Nodejs 等多種語言開發,使用 MySQL 和 MongoDB 等多種數據庫,原方案采用單機環境下的部署方式,缺乏服務治理能力和分布式能力。
sockshop 部署后的拓撲圖總覽
sockshop 商城首頁預覽圖
sockshop 架構圖
更多信息
源碼地址
weavesocksdemo 樣例
sockshop 在 Rainbond 的部署流程 STEP1 服務創建
Rainbond 支持從源碼、鏡像、應用市場等多種方式進行應用部署,這里我們采用 DockerCompose 配置文件的創建方式,批量創建 sockshop 中包含的所有服務。
docker-compose 創建
需要注意的是,在檢測和創建過程中,獲取大量鏡像需要一定時間,請耐心等待完成!
docker-compose 源碼: 下載
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 文檔:創建一個應用
服務創建完成后,我們需要對批量創建的服務進行注冊和對部署內存的調整,根據服務之間的調用關系,分析出哪些服務是作為內部服務供給其它服務調用、哪個服務是對用戶提供訪問的,并進行接下來的操作:
STEP2 服務注冊
在 Rainbond 平臺,我們可以通過在服務的端口頁打開端口來進行服務的注冊。關于服務注冊的詳細文檔可參考 Rainbond 平臺服務注冊
各服務對應的端口和部署內存大小如下:
請注意,這里必須確定對每個服務組件的服務注冊信息和資源分配信息設置正確。
STEP3 服務發現
sockshop 通過內部域名來進行服務調用,也就是說,在完成服務的注冊后,調用服務需要發現被調用服務。
在 Rainbond 平臺,我們可以通過服務依賴來實現(詳情參考文檔服務發現)。
各服務依賴的詳情可參考上圖商城在 Rainbond 平臺的概覽
如果使用上面的 docker-compose 文件創建應用,無需手動添加依賴,在創建應用時系統已根據 docker-compose 文件內容自動配置了服務發現
STEP4 服務 Mesh 治理
在 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 分別安裝網絡治理插件。
STEP5 安裝網絡治理插件
在我的插件中選擇服務網絡治理插件進行安裝。
特別注意
工作在 7 層的 Mesh 插件默認會占用 80 端口,因此需要安裝此插件的服務本身不能占用 80 端口。因此我們推薦服務盡量監聽非 80 端口。插件內存使用量需要根據流量大小調節。
STEP6 應用安裝插件
在應用詳情頁面選擇插件標簽,然后開通指定的插件。
Rainbond 默認提供的服務網絡治理插件是基于 Envoy 制作,Rainbond ServiceMesh 架構為 Envoy 提供了標準的運行支持。安裝插件后需重啟應用生效。
STEP7 Mesh 插件配置
配置域名路由,實現端口復用。為了 front-end 服務能根據代碼已有的域名調用選擇對應的服務提供方,我們需要根據其調用的域名來進行配置。將應用進行依賴后,服務網絡治理插件能夠自動識別出其依賴的應用。我們只需在插件的配置的域名項中進行域名配置即可。如下圖:
詳細配置
更新插件相關的配置后進行保存并重啟相關應用即可。此處暫時先只用到基于域名的路由配置,關于網絡治理插件的更對詳情可參考 服務路由,灰度發布,A/B 測試
STEP8 服務性能分析
微服務是一個分布式的架構模式,它一直以來都會有一些自身的問題。當一個應用的運行狀態出現異常時,對于運維和開發人員來說,即時發現應用的狀態異常并解決是非常有必要的。我們可以通過監控手段對服務進行衡量,或者做一個數據支撐。
Rainbond 平臺為我們提供了服務監控與性能監控,可以簡單直觀的了解服務當前的狀態和信息。
目前支持 HTTP 與 mysql 協議的應用
安裝插件
應用安裝插件
同上應用網絡治理插件安裝
安裝完成效果圖
安裝完成性能分析插件,可以在安裝該插件的應用概覽頁面查看應用的平均響應時間和吞吐率。
除此以外,我們也可以在該組應用的組概覽中看到應用的訪問情況。
案例上的性能測試工具服務
sockshop 商城案例自帶性能測試的服務,但是與該項目不是持續運行,而是運行一次后程序便會退出。在這里,我們根據源碼進行了一點小的修改。主要是將程序變為不退出運行。源碼地址
我們可以通過源碼方式來創建項目——
創建完成后,我們需要在 sockshop 商城創建一個賬號為 user、密碼為 password 的用戶,負載測試需要使用該用戶名來和密碼進行模擬請求。
完成以上步驟,接下來我們對 sockshop 的分布式跟蹤進行處理。
微服務分布式跟蹤 zipkin 簡介
隨著業務越來越復雜,系統也隨之進行各種拆分,特別是隨著微服務架構和容器技術的興起,看似簡單的一個應用,后臺可能有幾十個甚至幾百個服務在支撐;一個前端的請求可能需要多次的服務調用最后才能完成;當請求變慢或者不可用時,我們無法得知是哪個后臺服務引起的,這時就需要解決如何快速定位服務故障點,Zipkin 分布式跟蹤系統就能很好的解決這樣的問題。
Zipkin 分布式跟蹤系統;它可以幫助收集時間數據,解決在 microservice 架構下的延遲問題;它管理這些數據的收集和查找;Zipkin 的設計是基于谷歌的 Google Dapper 論文。每個應用程序向 Zipkin 報告定時數據,Zipkin UI 呈現了一個依賴圖表來展示多少跟蹤請求經過了每個應用程序;如果想解決延遲問題,可以過濾或者排序所有的跟蹤請求,并且可以查看每個跟蹤請求占總跟蹤時間的百分比。
zipkin 架構
裝配了 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 會在請求中加入跟蹤的頭部信息和相應的注釋,并記錄調用的時間并將數據返回給 zipkin 的收集器 collector。
zipkin 安裝
在 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 案例
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 也已經可以正常工作了。
關于如何實踐 Service Mesh 微服務架構的基礎部署就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。