到高可用微服務(wù)全鏈路實(shí)踐)
簡(jiǎn)介gulimall谷粒商城是一套覆蓋電商全流程的Java微服務(wù)實(shí)戰(zhàn)項(xiàng)目資料包面向具備JavaWeb基礎(chǔ)、希望掌握Spring Cloud Alibaba、分布式事務(wù)與高并發(fā)集群方案的開發(fā)者。資源將完整筆記、配套資料、可運(yùn)行代碼整合在一起集群篇已更新完成可對(duì)照服務(wù)注冊(cè)、配置中心、網(wǎng)關(guān)路由、集群容災(zāi)等真實(shí)生產(chǎn)場(chǎng)景逐段學(xué)習(xí)。壓縮包共4429個(gè)文件、約287.77MB既有711個(gè)Java源碼和126個(gè)Vue組件構(gòu)成的業(yè)務(wù)代碼也有大量圖片素材輔助界面說明配合SQL腳本、YML配置、Dockerfile、Nginx與Registry集群配置以及貫穿全階段的MD筆記便于按模塊查閱和二次開發(fā)。目前已有2910人學(xué)習(xí)下載對(duì)于正在系統(tǒng)梳理微服務(wù)技術(shù)?;驕?zhǔn)備分布式相關(guān)面試的后端開發(fā)者來說是一份可操作性很強(qiáng)的參考資料。1. 集群篇谷粒商城從單機(jī)到集群先想清楚這三件事拿到這套「gulimall谷粒商城」資料包我最先翻的不是業(yè)務(wù)代碼而是集群篇。微服務(wù)項(xiàng)目教程遍地都是但能把注冊(cè)中心、配置中心、網(wǎng)關(guān)、中間件集群和 Nginx 編排串成一條完整鏈路的資料很少。資料包里筆記、代碼、conf 文件都齊集群篇已經(jīng)完成對(duì)正想把單機(jī)版商城往生產(chǎn)級(jí)環(huán)境遷移的 Java 開發(fā)者來說可以直接對(duì)著復(fù)現(xiàn)。它實(shí)際解決三個(gè)問題服務(wù)如何被動(dòng)態(tài)發(fā)現(xiàn)、流量如何在網(wǎng)關(guān)和中間件層分?jǐn)偂⒉渴鸷笕绾悟?yàn)證集群真的生效。我按拆包的視角把架構(gòu)、中間件、部署、驗(yàn)證四條線依次拆開講。2. 谷粒商城集群架構(gòu)從 gulimall 模塊拆分到 Nacos 注冊(cè)中心2.1 模塊邊界與調(diào)用鏈gulimall 的代碼結(jié)構(gòu)是典型的多模塊 Maven 工程業(yè)務(wù)服務(wù)按電商域拆成 product、order、member、coupon、ware 等獨(dú)立服務(wù)。集群化部署前必須先把每塊服務(wù)的職責(zé)和端口理清楚否則配置網(wǎng)關(guān)和負(fù)載均衡時(shí)容易把 upstream 地址寫錯(cuò)。模塊默認(rèn)端口主要職責(zé)集群化關(guān)注點(diǎn)gulimall-gateway88統(tǒng)一入口路由轉(zhuǎn)發(fā)需要多實(shí)例上層用 Nginx 做負(fù)載均衡gulimall-auth-server12000認(rèn)證授權(quán)OAuth2 接入會(huì)話和 token 一致性gulimall-product10000商品、分類、品牌管理強(qiáng)依賴 Redis 緩存和搜索gulimall-order9000訂單、購(gòu)物車、狀態(tài)機(jī)異步消息、分布式事務(wù)gulimall-member8000會(huì)員等級(jí)、積分無狀態(tài)方便水平擴(kuò)容gulimall-coupon7000優(yōu)惠券發(fā)放與分?jǐn)傋⒁馊瘞?kù)存恢復(fù)gulimall-ware11000庫(kù)存、采購(gòu)數(shù)據(jù)一致性要求高這些端口在資料包的 SQL 和 YAML 里都能對(duì)上。集群化時(shí)除了 gateway每個(gè)服務(wù)都可以多實(shí)例注冊(cè)到 Nacos。服務(wù)間調(diào)用不再寫 IP而是用lb://服務(wù)名讓負(fù)載均衡器去選實(shí)例。2.1.1 端口規(guī)劃與防火墻注意部署多節(jié)點(diǎn)集群時(shí)防火墻放行不能只開業(yè)務(wù)端口。Nacos 除了 8848 還有 9848 的 gRPC 端口Redis Cluster 節(jié)點(diǎn)間通信是 16379Kafka 是 9092網(wǎng)關(guān)是 88。我習(xí)慣在安全組里按服務(wù)角色分組放行避免圖省事全部放通。調(diào)用鏈在單機(jī)版是瀏覽器 → 網(wǎng)關(guān) → 業(yè)務(wù)服務(wù)。上了集群之后動(dòng)態(tài)請(qǐng)求先到 Nginx由 Nginx 把流量分?jǐn)偨o多個(gè)網(wǎng)關(guān)實(shí)例網(wǎng)關(guān)再通過注冊(cè)中心找到目標(biāo)服務(wù)靜態(tài)資源則由 Nginx 直接返回。2.2 注冊(cè)中心為什么選 Nacosregistry.conf 到底改了什么服務(wù)多實(shí)例之后第一件事是服務(wù)發(fā)現(xiàn)。gulimall 選 Nacos 而不是 Eureka原因很實(shí)際Nacos 同時(shí)提供注冊(cè)中心和配置中心一個(gè)組件解決兩個(gè)需求還支持 namespace 隔離環(huán)境。資料包里的 registry.conf 是我在集群篇里重點(diǎn)看的一份文件我習(xí)慣先把它放在 Nacos 服務(wù)端 conf 目錄下比對(duì)看節(jié)點(diǎn)列表和數(shù)據(jù)庫(kù)源是否一致。Nacos 集群部署時(shí)真正的節(jié)點(diǎn)列表在conf/cluster.conf按行寫各節(jié)點(diǎn)地址。一般我會(huì)這樣寫192.168.1.31:8848 192.168.1.32:8848 192.168.1.33:8848然后在application.properties里接上 MySQL讓 Nacos 共享配置和實(shí)例數(shù)據(jù)spring.datasource.platformmysql db.num1 db.url.0jdbc:mysql://192.168.1.50:3306/nacos_config?useUnicodetruecharacterEncodingutf8 db.userroot db.passwordyourpassword注意 Nacos 集群每個(gè)節(jié)點(diǎn)的數(shù)據(jù)庫(kù)配置必須一致否則節(jié)點(diǎn)間拉不到同一份配置。db.num默認(rèn)是 1多數(shù)據(jù)源時(shí)按db.url.0、db.url.1遞增。2.2.1 namespace 與多環(huán)境隔離業(yè)務(wù)服務(wù)側(cè)的注冊(cè)配置也有幾個(gè)關(guān)鍵點(diǎn)。每個(gè)參與集群的服務(wù)都要聲明注冊(cè)地址和命名空間資料包里的標(biāo)準(zhǔn)寫法是這樣spring: application: name: gulimall-order cloud: nacos: discovery: server-addr: nacos-1:8848,nacos-2:8848,nacos-3:8848 namespace: gulimall-prod config: server-addr: ${spring.cloud.nacos.discovery.server-addr} namespace: gulimall-prod file-extension: yaml server: port: 9000server-addr配置多個(gè)節(jié)點(diǎn)時(shí)客戶端會(huì)把所有地址當(dāng)作已知節(jié)點(diǎn)某個(gè)節(jié)點(diǎn)掛了不影響注冊(cè)。namespace必須和服務(wù)端一致否則控制臺(tái)能看到服務(wù)實(shí)際調(diào)用卻是 503。file-extension: yaml是讓配置中心去加載gulimall-order.yaml這份文件統(tǒng)一放在 Nacos 配置列表里修改后無需重啟服務(wù)。2.3 網(wǎng)關(guān)集群與路由規(guī)則網(wǎng)關(guān)是流量的第一道關(guān)卡。gulimall-gateway 本身也要注冊(cè)進(jìn) Nacos路由才能用lb://方式轉(zhuǎn)發(fā)到目標(biāo)服務(wù)。資料包里的網(wǎng)關(guān)配置大致如下spring: cloud: gateway: routes: - id: product_route uri: lb://gulimall-product predicates: - Path/api/product/** filters: - RewritePath/api/product/(?segment.*), /product/$\{segment} - id: order_route uri: lb://gulimall-order predicates: - Path/api/order/** filters: - RewritePath/api/order/(?segment.*), /order/$\{segment}這里最關(guān)鍵的是uri: lb://gulimall-product中的lb://它告訴 Spring Cloud Gateway 使用 LoadBalancerClient 從 Nacos 拉取gulimall-product實(shí)例列表而不是走寫死的 IP。RewritePath用正則把/api/product/xxx重寫為/product/xxx剝離前綴內(nèi)部服務(wù)不需要感知外部 URL 規(guī)范。網(wǎng)關(guān)多實(shí)例后每臺(tái)實(shí)例的路由規(guī)則必須一致最簡(jiǎn)單的做法是把網(wǎng)關(guān)配置也放到 Nacos 配置中心避免漏改。3. 中間件集群化Redis Cluster、Kafka 與 Sentinel 的協(xié)同部署3.1 Redis Cluster緩存與分布式鎖的落點(diǎn)gulimall 的商品詳情、首頁(yè)輪播、用戶驗(yàn)證碼都走 Redis 緩存。單機(jī) Redis 只要重啟緩存擊穿就能把數(shù)據(jù)庫(kù)打掛。集群篇的方案是 Redis Cluster把 16384 個(gè) slot 分布到多個(gè)主從節(jié)點(diǎn)上。我一般用 Docker 起最小拓?fù)渥鲵?yàn)證核心配置是這幾個(gè)參數(shù)cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 appendonly yes bind 0.0.0.0cluster-enabled開啟集群模式cluster-config-file是節(jié)點(diǎn)保存集群狀態(tài)的文件每次啟動(dòng)會(huì)重寫cluster-node-timeout是節(jié)點(diǎn)判斷 PONG 超時(shí)的時(shí)間單位毫秒設(shè)太短容易誤判太長(zhǎng)故障轉(zhuǎn)移慢appendonly yes開啟 AOF避免節(jié)點(diǎn)重啟丟數(shù)據(jù)。節(jié)點(diǎn)起好后用 redis-cli 分配槽位redis-cli --cluster create \ 192.168.1.11:6379 192.168.1.12:6379 192.168.1.13:6379 \ 192.168.1.14:6379 192.168.1.15:6379 192.168.1.16:6379 \ --cluster-replicas 1--cluster-replicas 1表示每個(gè)主節(jié)點(diǎn)配一個(gè)從節(jié)點(diǎn)三個(gè)主三從組成最小容錯(cuò)集群。某一主節(jié)點(diǎn)掛了從節(jié)點(diǎn)會(huì)在cluster-node-timeout之后被提升為主節(jié)點(diǎn)這是自動(dòng)的。3.1.1 槽位遷移與擴(kuò)縮容集群擴(kuò)容時(shí)槽位不會(huì)自動(dòng)遷移需要手動(dòng)執(zhí)行redis-cli --cluster rebalance或reshard。常見做法是先加入新節(jié)點(diǎn)再 reshard把部分 slot 從老節(jié)點(diǎn)搬過去。搬移過程中客戶端可能出現(xiàn)MOVED重定向所以 Spring Boot 配置中的max-redirects要給夠spring: redis: cluster: nodes: - 192.168.1.11:6379 - 192.168.1.12:6379 - 192.168.1.13:6379 max-redirects: 3max-redirects是客戶端跟隨 MOVED/ASK 重定向的最大次數(shù)。正常情況一次跳轉(zhuǎn)就能找到目標(biāo)節(jié)點(diǎn)擴(kuò)容或槽位遷移時(shí)需要多次。這里也容易踩坑Redis Cluster 要求所有節(jié)點(diǎn)密碼一致Spring Boot 的spring.redis.password在集群模式下會(huì)應(yīng)用到每個(gè)節(jié)點(diǎn)不需要逐個(gè)配。3.2 Kafka 集群異步消息與故障切換訂單服務(wù)創(chuàng)建訂單后要通知庫(kù)存服務(wù)鎖定庫(kù)存還要給優(yōu)惠券服務(wù)發(fā)消息這些跨服務(wù)動(dòng)作在 gulimall 里走 Kafka。Kafka 集群的配置核心在server.properties每臺(tái) broker 需要有獨(dú)立且唯一的broker.id其他配置保持一致broker.id1 listenersPLAINTEXT://192.168.1.21:9092 log.dirs/data/kafka-logs num.partitions8 default.replication.factor3 offsets.topic.replication.factor3 min.insync.replicas2 zookeeper.connect192.168.1.31:2181,192.168.1.32:2181,192.168.1.33:2181重點(diǎn)解釋幾個(gè)參數(shù)offsets.topic.replication.factor決定消費(fèi)者 offset 提交主題的副本數(shù)如果小于 broker 數(shù)而某個(gè) broker 宕了部分消費(fèi)者將無法提交 offsetmin.insync.replicas控制寫數(shù)據(jù)時(shí)最少幾個(gè)副本寫入成功才算完成配合 producer 的acksall消息基本不丟log.dirs不要放系統(tǒng)盤Kafka 對(duì)磁盤順序?qū)懸蕾嚭艽蟆roducer 端用 KafkaTemplate 發(fā)送寫法比較簡(jiǎn)潔Resource private KafkaTemplateString, String kafkaTemplate; public void publishOrderPaidEvent(OrderPaidEvent event) { String json JSON.toJSONString(event); kafkaTemplate.send(order-paid-event, event.getOrderSn(), json); }注意send的第二個(gè)參數(shù)是 key拿訂單號(hào)當(dāng) key同一訂單的支付、取消、超時(shí)消息會(huì)落在同一分區(qū)消費(fèi)端能按順序處理。消費(fèi)端要把 group-id 設(shè)置成和項(xiàng)目?jī)?nèi)一致否則會(huì)重復(fù)或漏消費(fèi)KafkaListener(topics order-paid-event, groupId order-event-group) public void onMessage(String json) { OrderPaidEvent event JSON.parseObject(json, OrderPaidEvent.class); // 解鎖倉(cāng)庫(kù)庫(kù)存、更新訂單狀態(tài) }集群環(huán)境下同一 group 的消費(fèi)實(shí)例數(shù)不要大于分區(qū)數(shù)否則多出來的實(shí)例會(huì)一直空轉(zhuǎn)。order-paid-event 如果開了 8 個(gè)分區(qū)消費(fèi)實(shí)例最多 8 個(gè)。這幾個(gè)參數(shù)光看注釋不容易記我整理了一個(gè)對(duì)照表部署時(shí)直接對(duì)著寫參數(shù)單機(jī)默認(rèn)集群建議原因offsets.topic.replication.factor13防止 broker 宕機(jī)導(dǎo)致 offset 丟失min.insync.replicas12配合 acksall 保證不丟消息default.replication.factor13新建 topic 默認(rèn)副本數(shù)避免單點(diǎn)3.3 Sentinel 集群限流保護(hù)網(wǎng)關(guān)與核心服務(wù)gulimall 學(xué)習(xí)版常用單機(jī) Sentinel生產(chǎn)集群則需要打開 cluster 模式。Sentinel 集群限流需要一個(gè) Token Server 做全局流量統(tǒng)計(jì)普通 client 會(huì)把請(qǐng)求數(shù)據(jù)上報(bào)給 Token Server由它統(tǒng)一判定是否放行。給限流規(guī)則加集群開關(guān)通常同時(shí)把規(guī)則持久化到 Nacos[ { resource: gulimall-product, count: 500, grade: 1, limitApp: default, strategy: 0, clusterMode: true, clusterConfig: { flowId: 1001, thresholdType: 0 } } ]grade1表示按 QPS 限流thresholdType0表示全局閾值資源在所有節(jié)點(diǎn)共享一個(gè) count如果每個(gè)節(jié)點(diǎn)單獨(dú)計(jì)數(shù)用戶刷新兩次就觸發(fā)限流了這是常見誤配。Sentinel 客戶端還需要配置 Token Server 地址spring: cloud: sentinel: transport: port: 8719 dashboard: 192.168.1.40:8858 cluster: server-addr: 192.168.1.41:12000port: 8719是客戶端接收控制臺(tái)心跳的端口。多個(gè)服務(wù)在同一臺(tái)機(jī)器上時(shí)需要改成不同值否則端口沖突會(huì)讓控制臺(tái)顯示心跳斷開。集群限流適合網(wǎng)關(guān)和商品服務(wù)這種熱點(diǎn)入口不建議對(duì)內(nèi)部數(shù)據(jù)庫(kù)操作開啟。4. 部署實(shí)錄從 default.conf 到 nginx.conf 的服務(wù)編排4.1 資料包里的 conf 文件都是干什么的解開 gulimall 壓縮包會(huì)看到 .babelrc、file.conf、registry.conf、default.conf、nginx.conf、gulimall.conf 和一些 CSS 文件。這些不全是后端配置。.babelrc 是前端 vue 工程的編譯配置GL.css、index.css 是靜態(tài)資源default.conf 和 nginx.conf 屬于 Nginx 層gulimall.conf 是商城站點(diǎn)的 server 配置。file.conf 和 registry.conf 在集群篇里多用于中間件初始化比如 Nacos 的數(shù)據(jù)源初始化或 Sentinel 集群參數(shù)。我一般先按部署角色分類避免拿到包不知道先改哪個(gè)。文件歸屬層部署時(shí)的作用.babelrc前端編譯控制 ES6 語(yǔ)法轉(zhuǎn)譯規(guī)則file.conf數(shù)據(jù)源/初始化組件啟動(dòng)前的數(shù)據(jù)源或日志配置registry.conf注冊(cè)中心Nacos 集群節(jié)點(diǎn)與庫(kù)表連接信息default.confNginx默認(rèn)站點(diǎn)兜底配置nginx.confNginx全局配置包含 http、event、日志gulimall.confNginx商城反向代理和靜態(tài)資源規(guī)則GL.css / index.css前端靜態(tài)資源商城頁(yè)面樣式由 Nginx 靜態(tài)托管有一點(diǎn)需要提醒registry.conf 在 Nacos 集群里不是必須的文件名Nacos 原生用 cluster.conf這里的 registry.conf 更像資料作者整理后的可復(fù)制模板。放進(jìn) Nacos conf 目錄前記得先比對(duì) cluster.conf 節(jié)點(diǎn)列表。4.2 gulimall.conf 的動(dòng)靜分離配置集群部署時(shí)網(wǎng)關(guān)前面必須放一層 Nginx負(fù)責(zé) SSL 終端、靜態(tài)資源緩存和網(wǎng)關(guān)負(fù)載均衡。資料包里的 gulimall.conf 提供了完整的反向代理模板我在此基礎(chǔ)上調(diào)整了上游網(wǎng)關(guān)列表讓多個(gè) gateway 實(shí)例都能被代理upstream gulimall_gateway { server 192.168.1.10:88 max_fails2 fail_timeout10s; server 192.168.1.11:88 max_fails2 fail_timeout10s; server 192.168.1.12:88 max_fails2 fail_timeout10s; } server { listen 80; server_name mall.example.com; root /usr/share/nginx/html; location / { try_files $uri $uri/ gateway; } location gateway { proxy_pass http://gulimall_gateway; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 5s; proxy_read_timeout 30s; } location ~* \.(css|js|png|jpg|jpeg|gif|svg|woff2)$ { expires 7d; add_header Cache-Control public, immutable; access_log off; } }這里try_files $uri $uri/ gateway先檢查 Nginx 本地有沒有靜態(tài)文件有就直接返回沒有就把請(qǐng)求交給 upstream 中的網(wǎng)關(guān)。proxy_pass不帶 URI 后綴會(huì)把原始請(qǐng)求路徑原樣轉(zhuǎn)發(fā)給網(wǎng)關(guān)。location ~*正則匹配靜態(tài)資源expires 7d做強(qiáng)緩存。如果前端文件帶 hash緩存可以留更久不帶 hash 的話建議只緩存 1 小時(shí)避免發(fā)版后用戶看到舊樣式。4.2.1 靜態(tài)資源緩存策略gulimall 的前端里GL.css 和 index.css 這類文件名如果不帶 hash更新后瀏覽器可能仍使用緩存。常見做法是把 Nginx 緩存時(shí)間改短同時(shí)在后端接口響應(yīng)頭里加 ETag。Nginx 默認(rèn)會(huì)對(duì)靜態(tài)文件生成弱 ETag必要時(shí)可以用etag on開啟。實(shí)際部署時(shí)我一般把 CSS、JS 的expires設(shè)為 1 小時(shí)頁(yè)面 HTML 設(shè)為 no-cache這樣既不會(huì)每次請(qǐng)求都打到源站也不會(huì)出現(xiàn)發(fā)版后樣式錯(cuò)亂。4.3 集群?jiǎn)?dòng)順序與驗(yàn)證集群部署和單機(jī)最大的區(qū)別是組件有依賴順序。我按“基礎(chǔ)存儲(chǔ) → 注冊(cè)中心 → 中間件 → 業(yè)務(wù)服務(wù) → 網(wǎng)關(guān) → Nginx”的順序啟動(dòng)# 1. Nacos 集群模式啟動(dòng) /opt/nacos/bin/startup.sh -m cluster # 2. Kafka 每臺(tái) broker 依次啟動(dòng) /opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties # 3. 網(wǎng)關(guān)和業(yè)務(wù)服務(wù)用同一份 JAR 啟動(dòng)通過啟動(dòng)參數(shù)區(qū)分端口 java -jar gulimall-gateway.jar --server.port88 java -jar gulimall-order.jar --server.port9000 # 4. 檢查 Nginx 配置并熱加載 nginx -t nginx -s reload啟動(dòng)后不要急著打開頁(yè)面先用 curl 驗(yàn)證鏈路curl -H Host: mall.example.com http://127.0.0.1/api/product/info/23返回 JSON 而不是 503說明 Nginx → 網(wǎng)關(guān) → product 服務(wù)這條鏈路已通。接著看 Nacos 控制臺(tái)的服務(wù)列表確認(rèn)每個(gè)服務(wù)實(shí)例數(shù)大于 1、健康狀態(tài)為 true。再看 Redis Cluster 的狀態(tài)redis-cli --cluster check 192.168.1.11:6379該命令會(huì)輸出槽位分布、節(jié)點(diǎn)狀態(tài)、主從關(guān)系。如果輸出里沒有 inconsistent 之類的內(nèi)容說明緩存層正常。排錯(cuò)時(shí)最常見的有三個(gè)問題。第一服務(wù)注冊(cè)到 Nacos 但網(wǎng)關(guān) 503優(yōu)先檢查 namespace 是否一致以及服務(wù)名是否被寫成了下劃線。第二頁(yè)面能打開但數(shù)據(jù)加載不出查看 Redis 連接是否用了集群模式單機(jī)客戶端連集群會(huì)報(bào) MOVED 錯(cuò)誤。第三Kafka 消費(fèi)者重復(fù)消費(fèi)檢查 group-id 是否換到了新值新 group 會(huì)從頭消費(fèi)歷史消息。5. 集群壓測(cè)與驗(yàn)證技巧用一筆訂單走完整條鏈路集群起來以后驗(yàn)證不能只看控制臺(tái)綠燈。我習(xí)慣先用 wrk 對(duì)網(wǎng)關(guān)和商品接口做一輪壓測(cè)確認(rèn)集群部署沒有引入明顯的性能損耗wrk -t8 -c200 -d60s --latency http://127.0.0.1/api/product/info/23關(guān)注輸出里的 Requests/sec 和 Latency 分布。如果單實(shí)例和集群模式的吞吐差不多就要檢查流量是否被網(wǎng)關(guān)或 Nginx 配置限制了比如 keepalive 沒開、線程池太小。接著驗(yàn)證故障轉(zhuǎn)移。停掉一個(gè)網(wǎng)關(guān)實(shí)例立刻用 curl 循環(huán)請(qǐng)求觀察失敗窗口是否過長(zhǎng)for i in $(seq 1 20); do curl -s -o /dev/null -w %{http_code}\n http://127.0.0.1/api/product/info/23 sleep 0.5 done正常情況下Nginx 會(huì)在 fail_timeout 之后把請(qǐng)求導(dǎo)到健康節(jié)點(diǎn)返回碼依然 200。Redis Cluster 的驗(yàn)證方式是殺掉一個(gè)主節(jié)點(diǎn)然后執(zhí)行redis-cli -c set test-key hello正常情況下從節(jié)點(diǎn)自動(dòng)晉升為主節(jié)點(diǎn)命令仍然成功。Kafka 的驗(yàn)證則是啟動(dòng)控制臺(tái)消費(fèi)者手動(dòng)向 topic 發(fā)一條消息看能否消費(fèi)到/opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server 192.168.1.21:9092 \ --topic order-event --from-beginning --group verify-cluster壓測(cè)過程中還要盯著 JVM用jstat -gcutil pid 1000 10觀察老年代和 GC 停頓。如果 Full GC 頻繁先調(diào)大堆內(nèi)存不要急著改限流閾值集群模式強(qiáng)調(diào)水平擴(kuò)展單節(jié)點(diǎn)堆上限反而可能掩蓋問題。Sentinel 規(guī)則是否生效可以用連續(xù)快速請(qǐng)求驗(yàn)證當(dāng)接口返回Blocked by Sentinel (flow limiting)說明規(guī)則已下發(fā)生效。如果這輪驗(yàn)證全過把上面的命令整理成一個(gè)verify-cluster.sh每次發(fā)版后跑一遍比人工盯著多個(gè)控制臺(tái)直觀得多。本文還有配套的精品資源點(diǎn)擊獲取