作者介紹
侯陽
SphereEx 中間件研發工程師,Apache ShardingSphere Contributor。
目前專注於 ShadowDB 及全鏈路壓測相關的設計和研發。
什么是全鏈路壓測
隨着互聯網行業的快速發展,業務也進入了快速擴張階段,多變的用戶需求對整個系統的穩定性沖擊可想而知。比如外賣平台大量用戶產生的訂單集中分布在中午和傍晚兩個時間段,再比如電商平台的購物節、秒殺活動等。
每種業務都由一系列不同的業務系統來提供服務,每個業務系統都分布式地部署在不同的機器上。“流量規划” 既能保障系統穩定性、又能節約成本對於技術團隊來說是一重大難題,為了精准地獲取到單台機器的服務能力,壓力測試要在生產環境進行。既能保證環境的真實性,也能保證流量的真實性,大大提高“流量規划”的准確性。
影子庫與全鏈路壓測
但在線上業務系統做壓測,風險不言而喻,比如數據污染問題或是性能問題。試想一下,如果壓測結束后用戶發現自己訂單丟失了或是憑空多出一批待支付的訂單,是否極大影響用戶體驗?
全鏈路在線壓測是一項復雜而龐大的工作,需要各個微服務、中間件之間配合完成。Apache ShardingSphere 關注於全鏈路在線壓測場景下數據庫層面的解決方案,推出壓測影子庫功能。借助於 ShardingSphere 強大的 SQL 解析能力,對執行 SQL 進行影子判定,同時結合影子算法靈活的配置,滿足復雜業務場景的在線壓測需求;壓測流量路由到影子庫,線上正常流量路由到生產庫,從而幫助用戶對壓測數據進行隔離,解決數據污染問題。
影子庫功能升級
影子庫功能最早實現於 v4.1.0 時期,通過添加一個邏輯的影子列,Apache ShardingSphere 通過解析執行 SQL,對其進行路由並改寫,刪除邏輯的影子列與列值。用戶無需關注具體過程,使用時僅對 SQL 進行相應改造,添加影子字段與相應的配置即可。
添加影子列的方式有兩個痛點:
-
用戶在進行壓力測試前需要根據實際的業務需求,對壓測相關 SQL 進行相應改造。
-
SQL 改寫操作會增加執行損毀,降低壓測結果的准確性。
經過 ShardingSphere 社區的討論,決定對影子庫功能進行重構。
Apache ShardingSphere 4.1.1 GA 版影子庫 API,總體上功能較為簡單,根據邏輯列對應的值判斷是否開啟影子庫。
rules:
- !SHADOW
column: # 影子字段名稱名稱
shadowMappings:
ds: shadow_ds # 生產數據源名稱列表:影子數據庫名稱列表
5.0.0 GA 重構以后的影子庫 API 更加強大。 用戶可以通過 enable
屬性控制是否開啟影子庫功能,可配置影子表可以按照表的維度控制需要進行壓測的范圍,並支持多種不同的影子算法,例如:列值匹配算法、列正則表達式匹配算法以及 SQL 注釋匹配算法。
rules:
- !SHADOW
enable: true # 影子庫開關。 可選值:true/false,默認為false
dataSources:
shadowDataSource:
sourceDataSourceName: ds # 生產數據源名稱
shadowDataSourceName: shadow_ds # 影子數據源名稱
tables:
<shadow-table-name>:
dataSourceNames: shadowDataSource # 影子表關聯影子數據源名稱列表(多個值用","隔開)
shadowAlgorithmNames:
- <shadow-algorithm-name> # 影子表關聯影子算法名稱列表
shadowAlgorithms:
<shadow-algorithm-name>:
type: # 影子算法類型
props:
xxx: xxx # 影子算法屬性配置
影子庫實戰
在線全鏈路壓測架構圖:
准備壓測環境
假設一個電商網站要對下單業務進行在線壓測。(演示使用單機部署方式)
假設壓測相關表 t_order
訂單表,測試用戶的 ID 為 0。測試用戶下單產生的數據執行到 ds_shadow
影子庫,生產數據執行到 ds 生產數據庫。
測試環境准備:
-
下載 ShardingSphere-Proxy 5.0.0 GA Download Page,安裝配置詳情參考ShardingSphere-Proxy-Quick-Start
-
配置 ShardingSphere-Proxy 以上文假設壓測場景為例:
server.yaml
rules:
- !AUTHORITY
users:
- root@%:root
- sharding@:sharding
provider:
type: NATIVE
- !TRANSACTION
defaultType: XA
providerType: Atomikos
props:
max-connections-size-per-query: 1
executor-size: 16 # Infinite by default.
proxy-frontend-flush-threshold: 128 # The default value is 128.
proxy-opentracing-enabled: false
proxy-hint-enabled: false
sql-show: true
check-table-metadata-enabled: false
lock-wait-timeout-milliseconds: 50000 # The maximum time to wait for a lock
show-process-list-enabled: false
# Proxy backend query fetch size. A larger value may increase the memory usage of ShardingSphere Proxy.
# The default value is -1, which means set the minimum value for different JDBC drivers.
proxy-backend-query-fetch-size: -1
check-duplicate-table-enabled: false
sql-comment-parse-enabled: true
proxy-frontend-executor-size: 0 # Proxy frontend executor size. The default value is 0, which means let Netty decide.
# Available options of proxy backend executor suitable: OLAP(default), OLTP. The OLTP option may reduce time cost of writing packets to client, but it may increase the latency of SQL execution
# if client connections are more than proxy-frontend-netty-executor-size, especially executing slow SQL.
proxy-backend-executor-suitable: OLAP
config-shadow.yaml
schemaName: shadow_poc_database
dataSources:
ds:
url: jdbc:mysql://127.0.0.1:3306/ds?serverTimezone=UTC&useSSL=false
username: root
password:
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
ds_shadow:
url: jdbc:mysql://127.0.0.1:3306/ds_shadow?serverTimezone=UTC&useSSL=false
username: root
password:
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHADOW
enable: true
dataSources:
shadowDataSource:
sourceDataSourceName: ds
shadowDataSourceName: ds_shadow
tables:
t_order:
dataSourceNames:
- shadowDataSource
shadowAlgorithmNames:
- user-id-insert-match-algorithm
- simple-note-algorithm
shadowAlgorithms:
user-id-insert-match-algorithm:
type: COLUMN_REGEX_MATCH
props:
operation: insert
column: user_id
regex: "[0]"
simple-note-algorithm:
type: SIMPLE_NOTE
props:
foo: bar
- 訂單服務
這里不討論訂單相關業務,以最簡單的收請求直接插入訂單表為例。訂單表結構如下:
- 訂單表結構
CREATE TABLE `t_order` (
`id` INT(11) AUTO_INCREMENT COMMENT '訂單ID',
`user_id` VARCHAR(32) NOT NULL COMMENT '下單用戶ID',
`sku` VARCHAR(32) NOT NULL COMMENT '訂單商品sku',
PRIMARY KEY (`id`)
)ENGINE = InnoDB COMMENT = '訂單表';
模擬壓測過程
- 使用
postman
模擬測試用戶創建訂單請求如下圖:
- ShardingSphere-Proxy 中執行日志可以看到 執行 SQL 被路由到影子庫執行
驗證壓測結果
- 影子庫
ds_shadow
執行查詢語句
SELECT * FROM t_order;
查詢結果:
- 生產庫 ds 執行查詢語句
SELECT * FROM t_order;
查詢結果:
測試用戶創建訂單產生的數據會路由到影子庫中。更多復雜配置請參考 ShardingSphere 官方文檔影子庫壓測。
全鏈路在線壓測完整解決方案-CyborgFlow
前文中也提到全鏈路在線壓測是一項復雜而龐大的工作,需要各個微服務、中間件之間配合與調整,以應對不同流量以及壓測標識的透傳,而且要做到測試服務無狀態並且開箱即用。
由 Apache ShardingSphere 聯合 Apache APISIX、Apache SkyWalking 共同維護的項目 CyborgFlow 提供開箱即用 (OOTB) 解決方案來在您的在線系統上執行負載測試。
Apache APISIX 負責在網關層對測試數據進行標記,並由 Apache SkyWalking 負責在整個調用鏈路上進行傳遞,最后交由 Apache ShardingSphere-Proxy 做數據隔離,壓測數據路由到影子庫中。
項目已發布 0.1.0 版本,歡迎下載使用:
https://github.com/SphereEx/CyborgFlow/releases
歡迎添加社區經理微信(ss_assistant_1)加入微信交流群,與更多 ShardingSphere 愛好者一同交流討論。