Kubernetes-基于Helm安裝部署高可用的Redis

1、Redis簡介


Redis是一個開放源代碼(BSD許可證)的代理,其在內存中存儲數據,可以代理數據庫、緩存和消息。它支持字符串、散列、列表、集合和位圖等數據結構。Redis 是一個高性能的key-value數據庫, 它在很大程度改進了memcached這類key/value存儲的不足。Redis提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby和Erlang等語言的客戶端。
Redis支持master/slave結構,數據可以從master向任意數量的slave上進行同步。Redis 與其它 key – value 緩存產品相比,具有以下三個方面特點:

  • 支持內存的持久化:可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用;
  • 支持多種數據結構:Redis不僅僅只是支持key-value類型的數據,還能夠支持字符串、散列和列表等數據結構;
  • 支持主從結構:Redis支持主從結構,保證系統的高可用。

2、基于Sentinel模式的高可用方案

本文中的Redis高可用方案采用Sentinel(哨兵)模式,在集群出現故障的時候自動進行故障轉移,保證集群的可用性。Redis Sentinel 為Redis提供了高可用性,這意味著通過使用Sentinel 可以創建一個Redis部署,在沒有人為干預的情況下能夠抵抗某些類型的失敗。Sentiel的完整功能列表如下所示:

  • 監控:不間斷的檢查master/slave實例否是安裝預期正常工作;
  • 通知:當 Redis 實例出現錯誤的時候,會使用程序(通過 API 接口)通知管理員;
  • 自動故障轉移:在master發生故障時,哨兵會開啟故障轉移處理,將一臺slave提升為master,其它的slave被重新配置使用新的master,當應用程序連接時使用新的地址配置;
  • 配置信息:Sentinel作為服務發現的權威來源,客戶端連接到Sentinel去獲取當前Redis master的地址,如果發生故障轉移,Sentinel將會匯報新的服務器地址。

Sentinel本身是一套分布式系統,它被設計成能夠進行多個進程間協同工作的模式,這樣的好處如下:

  • 多個Sentinel一致明確給定的主機不再可用時,才會執行故障檢測,這能夠有效錯報的概率。
  • 即使只有一個Sentinel在正常運行,Redis也是可用的,從而保證系統具有較高的健壯性。

Sentinel,Redis實例(master和slave)和連接到Sentinel和Redis的客戶端的數量,也是一個具有特定屬性的更大的分布式系統。在本文中,定制的Redis服務器鏡像會確定執行它的Pod是redis的Sentinel、master還是slave,并啟動適當的服務。這個Helm chart指示Sentinel狀態與環境變量。如果沒有設置,新啟動的Pod將查詢Kunbernetes的活動master。如果不存在,則它使用一種確定的方法來檢測它是否應該作為master啟動,然后將“master”或“slave”寫入到稱為redis-role的標簽中。
redis-role=master Pod是集群啟動的關鍵。在它們完成啟動,sentinel將處于等待整體。所有其他的Pod等待sentinel識別主節點。運行Pod并設置標簽podIP和runID。runID是每個redis服務器生成的唯一run_ID值的前幾個字符。
在正常操作中,應該只有一個redis=master Pod。如果失敗,Sentinel將提名一個新的master,并適當地改變所有的redis-role的值。
通過執行如下命令可以查看Pod所承擔的角色:

$ kubectl get pods -L redis-role -namespace=kube-public

3、安裝部署

2.1 環境要求

  • 已有Kubernetes 1.6+環境;
  • 已部署helm客戶端和tiller服務端(請參考:https://docs.helm.sh/using_helm/#installing-helm):
    • 在Kubernetes中創建了具備足夠權限訪問權限的service account;
    • 并通過此service account在Kubernetes部署了tiller服務端(請參考:https://docs.helm.sh/using_helm/#role-based-access-control)。
  • 在Kubernetes中提供了容量大于10g的持久化存儲卷。

2.2 Helm char配置

下表列示了Redis chart的配置參數和默認值:

參數描述默認值
redis_imageRedis鏡像quay.io/smile/redis:4.0.6r2
resources.masterRedis主節點CPU/內存的資源請求/限制Memory: 200Mi, CPU: 100m
resources.slaveRedis從節點CPU/內存的資源請求/限制Memory: 200Mi, CPU: 100m
resources.sentinel哨兵節點CPU/內存的資源請求/限制Memory: 200Mi, CPU: 100m
replicas.serversredis master/slave pods的副本數量3
replicas.sentinelssentinel pods的副本數量3
nodeSelector為Pod指派的Node標簽{}
tolerations為Pod指派的可容忍標簽[]
servers.serviceType設置”LoadBalancer”能夠通過VPC進行訪問ClusterIP
servers.annotations參考應用模式
rbac.create是否應該創建RBAC資源true
serviceAccount.create是否創建代理所使用的service account名稱true
serviceAccount.name被使用的service account。如果未進行設置,同時如果serviceAccount.create被設置為true,則Kubernetes會在后臺以模板的全名創建一個service account。

在helm install中使用–set key=value 格式設置上述的參數值,例如:

$ helm install \--set redis_image=quay.io/smile/redis:4.0.6r2 \stable/redis-ha

2.3 持久化

redis將持久化數據保存在容器的/redis-master-datal路徑下,安裝時會創建一個PersistentVolumeClaim ,并將其掛接到容器內的目錄。因此,需要在Kubernetes中提前提供一個PersistentVolume。

2.4 通過Chart安裝Redis

通過執行如下的命令,在Kubernetes中部署Redis:

$ helm install stable/redis-ha --name=redis-ha --namespace=kube-public

通過上述命令,將以默認的配置在Kubernetes中部署Redis。默認情況下,chart會安裝部署3個Sentinel Pod,1個master Pod和2個slave Pod。

3、Helm Chart分析

MySQL Chart的目錄如下,其中,values為默認的配置文件,用于為部署提供默認值。templates目錄下的YAML文件是在Kubernetes進行部署的配置文件。

redis-ha
--templates # 模板目錄,當與values.yaml組合時,將生成有效的Kubernetes清單文件。 ----NOTES.txt
----_helpers.tpl
----redis-auth-secret.yaml
----redis-master-service.yalm
----redis-role.yaml
----redis-rolebinding.yaml
----redis-sentinel-deployment.yaml
----redis-sentinel-service.yaml
----redis-server-deployment.yaml
----redis-serviceaccount.yaml 
----redis-slave-service.yaml 
--Chart.yaml # 描述chart的信息 --README.md # 可讀的chart介紹文件 --values.yaml # 默認配置文件

3.1 values.yaml

在values.yaml配置文件中設置了通過helm進行部署時的默認值。在values.yaml中,首先,定義了主Pod和哨兵Pod的請求和限制資源的要求;接著,通過nodeSelector和容忍度為Pod定義調度到哪個Node上;以及,指定容器所使用的鏡像和其它的相關信息。

## Configure resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ##
resources:server:requests:memory: 200Micpu: 100mlimits:memory: 700Misentinel:requests:memory: 200Micpu: 100mlimits:memory: 200Mi ## Node labels and tolerations for pod assignment ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector  ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-featurenodeSelector: {}tolerations: [] ## Redis image version
redis_image: quay.io/smile/redis:4.0.8r0 ## replicas number for each component
replicas:servers: 3sentinels: 3
servers:serviceType: ClusterIP # [ClusterIP|LoadBalancer]annotations: {}rbac: # Specifies whether RBAC resources should be createdcreate: trueserviceAccount: # Specifies whether a ServiceAccount should be createdcreate: true # The name of the ServiceAccount to use. # If not set and create is true, a name is generated using the fullname templatename: ## Configures redis with AUTH (requirepass & masterauth conf params)
auth: false ## Redis password ## Defaults to a random 10-character alphanumeric string if not set and auth is true ## ref: https://github.com/kubernetes/charts/blob/master/stable/redis-ha/templates/redis-auth-secret.yaml ## ## redisPassword:

3.2 redis-server-deployment.yaml

此YAML配置文件用于定義Redis master/slave的部署。

apiVersion: extensions/v1beta1
kind: Deployment
metadata: # Pay attention to the redis-role label at runtime. The self-determination logic in the image sets  # this value accordingly.name: {{ template "redis-ha.fullname" . }}-serverlabels:name: {{ template "redis-ha.fullname" . }}-serverredis-node: "true" {{ include "labels.standard" . | indent 4 }}
spec:replicas: {{ .Values.replicas.servers }} template:metadata:labels:app: {{ template "redis-ha.name" . }}release: {{ .Release.Name }}component: servername: {{ template "redis-ha.fullname" . }}-serverredis-node: "true"spec:serviceAccountName: {{ template "redis-ha.serviceAccountName" . }} {{- if .Values.nodeSelector }}nodeSelector: {{ toYaml .Values.nodeSelector | indent 8 }} {{- end }} {{- if .Values.tolerations }}tolerations: {{ toYaml .Values.tolerations | indent 8 }} {{- end }}containers: - name: redisimage: {{ .Values.redis_image }}resources: {{ toYaml .Values.resources.server | indent 10 }}env: - name: REDIS_SENTINEL_SERVICE_HOSTvalue: "redis-sentinel" - name: REDIS_CHART_PREFIXvalue: {{ template "redis-ha.fullname" . }}- {{- if .Values.auth }} - name: REDIS_PASSvalueFrom:secretKeyRef:name: {{ template "redis-ha.fullname" . }}key: auth
{{- end }}ports: - containerPort: 6379volumeMounts: - mountPath: /redis-master-dataname: datavolumes: - name: data

3.3 redis-master-service.yaml

此YAML配置文件為定義了redis master的服務,此服務暴露6379端口,以供在集群中使用。

apiVersion: v1
kind: Service
metadata:name: {{ template "redis-ha.fullname" . }}-master-svclabels: {{ include "labels.standard" . | indent 4 }}annotations: {{ toYaml .Values.servers.annotations | indent 4 }}
spec:ports: - port: 6379protocol: TCPtargetPort: 6379selector:app: {{ template "redis-ha.name" . }}release: "{{ .Release.Name }}"redis-node: "true"redis-role: "master"type: "{{ .Values.servers.serviceType }}"

3.4 redis-slave-service.yaml

此YAML配置文件為定義了redis slave的服務,此服務暴露6379端口,以供在集群中使用。

apiVersion: v1
kind: Service
metadata:name: {{ template "redis-ha.fullname" . }}-slave-svclabels:role: service
{{ include "labels.standard" . | indent 4 }}annotations: {{ toYaml .Values.servers.annotations | indent 4 }}
spec:ports: - port: 6379protocol: TCPtargetPort: 6379selector:app: {{ template "redis-ha.name" . }}release: "{{ .Release.Name }}"redis-node: "true"redis-role: "slave"type: "{{ .Values.servers.serviceType }}"

3.5 redis-sentinel-deployment.yaml

此YAML文件定義Sentinel部署,Sentinel用于監控和管理對于Redis的訪問。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:name: {{ template "redis-ha.fullname" . }}-sentinellabels: {{ include "labels.standard" . | indent 4 }}
spec:replicas: {{ .Values.replicas.sentinels }} template:metadata:labels:app: {{ template "redis-ha.name" . }}release: {{ .Release.Name }}component: sentinelname: {{ template "redis-ha.fullname" . }}-sentinelspec:serviceAccountName: {{ template "redis-ha.serviceAccountName" . }} {{- if .Values.nodeSelector }}nodeSelector: {{ toYaml .Values.nodeSelector | indent 8 }} {{- end }} {{- if .Values.tolerations }}tolerations: {{ toYaml .Values.tolerations | indent 8 }} {{- end }}containers: - name: sentinelimage: {{ .Values.redis_image }}resources: {{ toYaml .Values.resources.sentinel | indent 10 }}env: - name: SENTINELvalue: "true" - name: REDIS_CHART_PREFIXvalue: {{ template "redis-ha.fullname" . }}- {{- if .Values.auth }} - name: REDIS_PASSvalueFrom:secretKeyRef:name: {{ template "redis-ha.fullname" . }}key: auth
{{- end }}ports: - containerPort: 26379

3.6 redis-sentinel-service.yaml

此YAML文件用于在集群內容暴露Sentinel部署,以供其它應用訪問和調用。

apiVersion: v1
kind: Service
metadata:name: {{ template "redis-ha.fullname" . }}-sentinellabels:name: {{ template "redis-ha.name" . }}-sentinel-svcrole: service
{{ include "labels.standard" . | indent 4 }}
spec:ports: - port: 26379targetPort: 26379selector:app: {{ template "redis-ha.name" . }}release: "{{ .Release.Name }}"redis-role: "sentinel"

3.7 redis-serviceaccount.yaml

如果rbac.create的值為true,此YAML文件將創建一個名為{{template “redis-ha.serviceAccountName”.}}的service account。

{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:name: {{ template "redis-ha.serviceAccountName" . }}labels:app: "redis-ha"chart: {{ .Chart.Name }}-{{ .Chart.Version }}heritage: {{ .Release.Service }}release: {{ .Release.Name }} {{- end -}}

3.8 redis-role.yaml

如果rbac.create的值為true,則此YAML文件將會定義名為{{template “redis-ha.fullname” .}}一個角色,此角色擁有獲取、列示和修改pods的權限。

{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:name: {{ template "redis-ha.fullname" . }}labels: {{ include "labels.standard" . | indent 4 }}
rules: - apiGroups: - ""resources: - podsverbs: - get - list- patch
{{- end -}}

3.9 redis-rolebinding.yaml

如果rbac.create的值為true,將上述創建的service account和角色進行綁定。

{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:name: {{ template "redis-ha.fullname" . }}labels: {{ include "labels.standard" . | indent 4 }}
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: {{ template "redis-ha.fullname" . }}
subjects: - kind: ServiceAccountname: {{ template "redis-ha.serviceAccountName" . }} {{- end -}}

3.10 redis-auth-secret.yaml

如果auth的值為true,則會創建一個保密字典。

{{- if .Values.auth -}}
apiVersion: v1
kind: Secret
metadata:name: {{ template "redis-ha.fullname" . }}labels: {{ include "labels.standard" . | indent 4 }}
type: Opaque
data: {{- if .Values.redisPassword }}auth: {{ .Values.redisPassword | b64enc | quote }} {{- else }}auth: {{ randAlphaNum 10 | b64enc | quote }} {{- end }} {{- end -}}

4、Redis部署環境驗證

在Kubernetes集群中,可以通過DNS名稱{{ template “redis-ha.fullname” . }}.{{ .Release.Namespace }}.svc.cluster.local和端口6379訪問redis集群。
如果設置了認證的話,通過下面的步驟連接Redis:
1)獲取隨機創建的redis密碼:
echo $(kubectl get secret {{ template “redis-ha.fullname” . }} -o “jsonpath={.data[‘auth’]}” | base64 -D)
2)使用客戶端連接Redis master Pod:
kubectl exec -it $(kubectl get pod -o jsonpath='{range .items[*]}{.metadata.name} {.status.containerStatuses[0].state}{“\n”}{end}’ -l redis-role=master | grep running | awk ‘{print $1}’) bash
3)在容器內使用Redis CLI連接:
redis-cli -a <REDIS-PASS-FROM-SECRET>
如果未設置認證的話,通過下面的步驟連接Redis:
1)可以通過下面的命令運行Redis Pod,作為客戶端:

獲取當前系統中的Pods:

$ kubectl get pods -L redis-role --namespace=kube-public

以名稱為redis-ha-redis-ha-server-79659c558f-lgrtg的Pod作為客戶端:

$ kubectl exec -it redis-ha-redis-ha-server-79659c558f-lgrtg --namespace=kube-public bash

2)使用Redis CLI:

獲取Redis的master服務名稱:

$ kubectl get svc --namespace=kube-public
$ redis-cli -h redis-ha-redis-ha-master-svc.kube-public -p 6379
本文轉自kubernetes中文社區-Kubernetes-基于Helm安裝部署高可用的Redis

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281286.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281286.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281286.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue 深度監聽和初始綁定

vue的監聽屬性普通方式無法監聽對象內部屬性的改變&#xff0c;并且初始化時不會監聽數據對象。 vue為監聽屬性提供了一種對象方法 watch: {option.size: {// handler為默認執行的方法handler (newValue, oldValue) {this.size newValue}&#xff0c;// 立即執行handler方法…

markdown流程圖畫法小結

markdown流程圖畫法小結markdown畫圖流程圖 最簡單的流程圖為例mermaid! graph TD A --> B //在沒有(),[].{}等括號的情況之下&#xff0c;圖標默認名字就是字母 A --> C C --> D B --> D 給圖標添加名字&#xff0c;改變只有矩陣圖形&#xff0c;在箭頭上添加文字…

hihocoder 1689 - 推斷大小關系(圖論+二分)

題目鏈接 https://vjudge.net/problem/HihoCoder-1689有N個整數A1, A2, ... AN&#xff0c;現在我們知道M條關于這N個整數的信息。每條信息是&#xff1a;Ai < Aj 或者 Ai Aj 小Hi希望你能從第一條信息開始依次逐條處理這些信息。一旦能推斷出A1和AN的大小關系就立即停止。…

32歲京東畢業程序員,走投無路當了外企外包,閑得心里發慌,到點下班渾身不自在!...

??當一位京東程序員進入外企當外包會怎么樣&#xff1f;順利躺平&#xff0c;實現wlb&#xff08;工作生活平衡&#xff09;嗎&#xff1f;未必&#xff0c;因為人是一種很奇怪的動物。這位網友說&#xff1a;32歲京東畢業程序員&#xff0c;找了幾個月工作一直沒有合適的&am…

SpringBoot+Shiro學習(四):Realm授權

上一節我們講了自定義Realm中的認證&#xff08;doGetAuthenticationInfo&#xff09;&#xff0c;這節我們繼續講另一個方法doGetAuthorizationInfo授權 授權流程 流程如下&#xff1a; 首先調用Subject.isPermitted/hasRole接口&#xff0c;其會委托給SecurityManager&#x…

Git放棄文件修改

已提交 # 撤銷提交&#xff0c;保留修改內容 git reset <commit_id># 撤銷提交&#xff0c;不保留修改內容 git reset --hard <commit_id>已暫存文件 # 撤銷單個文件暫存 git reset HEAD <filename># 撤銷所有文件/文件夾暫存 git reset HEAD .已跟蹤未暫存…

[LeetCode][Java] Unique Paths II

題目&#xff1a; Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid. For example, There is one obst…

lua windows下編譯

從Lua5.1開始官方給出的文件只有源代碼和makefile文件了&#xff0c;官網給出的bulid方式也是在linux平臺&#xff0c;如果只是想找個庫使用下可以到這里來下載&#xff1a;http://joedf.ahkscript.org/LuaBuilds/ &#xff0c;如果需要自定修改庫配置的話&#xff0c;就需要自…

XAML 創建瀏覽器應用程序

XAML 創建瀏覽器應用程序XAML 創建瀏覽器應用程序作者&#xff1a;WPFDevelopersOrg - 驚鏵原文鏈接&#xff1a;https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/app-development/wpf-xaml-browser-applications-overview?viewnetframeworkdesktop-4.8框架使用.NET40&…

Git 合并分支選項 --squash 合并提交歷史

git merge --squash <branchname>--squash選項的含義是&#xff1a;本地文件內容與不使用該選項的合并結果相同&#xff0c;但是不提交、不移動HEAD&#xff0c;因此需要一條額外的commit命令。其效果相當于將another分支上的多個commit合并成一個&#xff0c;放在當前分…

Kubernetes共享使用Ceph存儲

目錄 簡要概述環境測試結果驗證簡要概述 Kubernetes pod 結合Ceph rbd塊設備的使用&#xff0c;讓Docker 數據存儲在Ceph,重啟Docker或k8s RC重新 調 度pod 不會引起數據來回遷移。 工作原理無非就是拿到ceph集群的key作為認證&#xff0c;遠程rbdmap映射掛載使用。那么就要啟用…

在Activity不可見時暫停WebView的語音播放,可見時繼續播放之前的語音

private AudioManager mAudioManager;private AudioManager.OnAudioFocusChangeListener mFocusChangeListener; Override protected void onPause() {   super.onPause();   stopPlayVoice(); } Override protected void onResume() {   super.onResume();   startPla…

MFC界面庫BCGControlBar v25.3新版亮點:Dialogs和Forms

2019獨角獸企業重金招聘Python工程師標準>>> 親愛的BCGSoft用戶&#xff0c;我們非常高興地宣布BCGControlBar Professional for MFC和BCGSuite for MFC v25.3正式發布&#xff01;新版本添加了對Visual Studio 2017的支持、增強對Windows 10的支持等。接下來幾篇文…

基于 .NET 7 的 QUIC 實現 Echo 服務

前言隨著今年6月份的 HTTP/3 協議的正式發布&#xff0c;它背后的網絡傳輸協議 QUIC&#xff0c;憑借其高效的傳輸效率和多路并發的能力&#xff0c;也大概率會取代我們熟悉的使用了幾十年的 TCP&#xff0c;成為互聯網的下一代標準傳輸協議。在去年 .NET 6 發布的時候&#xf…

php.ini-development和php.ini-production的區別

使用zip版MySQL安裝時&#xff0c;需要將php.ini-development或php.ini-production改成php.ini&#xff0c;那么php.ini-development和php.ini-production的區別在哪兒呢&#xff0c;通俗的說法時&#xff0c;development是開發環境&#xff0c;production用于生產環境&#xf…

Server.MapPath()的用法

http://blog.csdn.net/qiuhaifeng_csu/article/details/19416407 Server.MapPath(string path)作用是返回與Web服務器上的指定虛擬路徑相對應的物理文件路徑。其參數path為Web 服務器的虛擬路徑&#xff0c;返回結果是與path相對應的物理文件路徑。但有時參數并非為虛擬路徑&a…

為什么阿里巴巴禁止把SimpleDateFormat定義為static類型的?

在日常開發中&#xff0c;我們經常會用到時間&#xff0c;我們有很多辦法在Java代碼中獲取時間。但是不同的方法獲取到的時間的格式都不盡相同&#xff0c;這時候就需要一種格式化工具&#xff0c;把時間顯示成我們需要的格式。 最常用的方法就是使用SimpleDateFormat類。這是一…

關于信息收集和加工的思考

隨著互聯網的發展&#xff0c;獲取信息的手段越來越多&#xff0c;我們對手機的依賴程度超乎想象&#xff0c;每天忙碌著&#xff0c;大腦接收著豐富的信息&#xff0c;感覺每天都學習到了很多的知識。但我們對學習經常會有些誤區&#xff1a;1、書買了擺在書架上&#xff0c;看…

[譯]關于NODE_ENV,哪些你應該了解

原文 Node.js開發者經常檢測環境變量NODE_ENV&#xff0c;但你是否知道設置這個值同時也具有著某些別的意義&#xff1f;閱讀本文你將發現這些。NODE_ENV是一個在Express框架中極其常用的環境變量。用其確定應用的運行環境&#xff08;諸如開發&#xff0c;staging&#xff0c;…

GatewayWorker Not Support On Windows.

thinkphp版本&#xff1a;5.1 tp5.1運行命令行php think worker:gateway出現GatewayWorker Not Support On Windows.是因為在tp5.1的命令行中做了判定&#xff0c;不支持windows環境下運行。 這里不支持windows環境并不是說gateway worker不支持windows&#xff0c;而是tp5.1的…