一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

2021-09-03 11:46程序猿小亮 Java教程

這篇文章主要介紹了Sentinel實現(xiàn)動態(tài)配置的集群流控,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

介紹

為什么要使用集群流控呢?

相對于單機流控而言,我們給每臺機器設(shè)置單機限流閾值,在理想情況下整個集群的限流閾值為機器數(shù)量??單機閾值。不過實際情況下流量到每臺機器可能會不均勻,會導(dǎo)致總量沒有到的情況下某些機器就開始限流。因此僅靠單機維度去限制的話會無法精確地限制總體流量。而集群流控可以精確地控制整個集群的調(diào)用總量,結(jié)合單機限流兜底,可以更好地發(fā)揮流量控制的效果。

基于單機流量不均的問題以及如何設(shè)置集群整體的QPS的問題,我們需要創(chuàng)建一種集群限流的模式,這時候我們很自然地就想到,可以找一個 server 來專門統(tǒng)計總的調(diào)用量,其它的實例都與這臺 server 通信來判斷是否可以調(diào)用。這就是最基礎(chǔ)的集群流控的方式。

原理

集群限流的原理很簡單,和單機限流一樣,都需要對 qps 等數(shù)據(jù)進(jìn)行統(tǒng)計,區(qū)別就在于單機版是在每個實例中進(jìn)行統(tǒng)計,而集群版是有一個專門的實例進(jìn)行統(tǒng)計。

這個專門的用來統(tǒng)計數(shù)據(jù)的稱為 Sentinel 的 token server,其他的實例作為 Sentinel 的 token client 會向 token server 去請求 token,如果能獲取到 token,則說明當(dāng)前的 qps 還未達(dá)到總的閾值,否則就說明已經(jīng)達(dá)到集群的總閾值,當(dāng)前實例需要被 block,如下圖所示:

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

和單機流控相比,集群流控中共有兩種身份:

  • Token Client:集群流控客戶端,用于向所屬 Token Server 通信請求 token。集群限流服務(wù)端會返回給客戶端結(jié)果,決定是否限流。
  • Token Server:即集群流控服務(wù)端,處理來自 Token Client 的請求,根據(jù)配置的集群規(guī)則判斷是否應(yīng)該發(fā)放 token(是否允許通過)。

而單機流控中只有一種身份,每個 sentinel 都是一個 token server。

注意,集群限流中的 token server 是單點的,一旦 token server 掛掉,那么集群限流就會退化成單機限流的模式。

Sentinel 集群流控支持限流規(guī)則和熱點規(guī)則兩種規(guī)則,并支持兩種形式的閾值計算方式:

  • 集群總體模式:即限制整個集群內(nèi)的某個資源的總體 qps 不超過此閾值。
  • 單機均攤模式:單機均攤模式下配置的閾值等同于單機能夠承受的限額,token server 會根據(jù)連接數(shù)來計算總的閾值(比如獨立模式下有 3 個 client 連接到了 token server,然后配的單機均攤閾值為 10,則計算出的集群總量就為 30),按照計算出的總的閾值來進(jìn)行限制。這種方式根據(jù)當(dāng)前的連接數(shù)實時計算總的閾值,對于機器經(jīng)常進(jìn)行變更的環(huán)境非常適合。

部署方式

token server 有兩種部署方式:

一種是獨立部署,就是單獨啟動一個 token server 服務(wù)來處理 token client 的請求,如下圖所示:

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

如果獨立部署的 token server 服務(wù)掛掉的話,那其他的 token client 就會退化成本地流控的模式,也就是單機版的流控,所以這種方式的集群限流需要保證 token server 的高可用性。

一種是嵌入部署,即作為內(nèi)置的 token server 與服務(wù)在同一進(jìn)程中啟動。在此模式下,集群中各個實例都是對等的,token server 和 client 可以隨時進(jìn)行轉(zhuǎn)變,如下圖所示:

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

嵌入式部署的模式中,如果 token server 服務(wù)掛掉的話,我們可以將另外一個 token client 升級為token server來,當(dāng)然啦如果我們不想使用當(dāng)前的 token server 的話,也可以選擇另外一個 token client 來承擔(dān)這個責(zé)任,并且將當(dāng)前 token server 切換為 token client。Sentinel 為我們提供了一個 api 來進(jìn)行 token server 與 token client 的切換:


	
  1. http://<ip>:<port>/setClusterMode?mode=<xxx>

其中 mode 為 0 代表 client,1 代表 server,-1 代表關(guān)閉。

PS:注意應(yīng)用端需要引入集群限流客戶端或服務(wù)端的相應(yīng)依賴。

集群限流控制臺

sentinel為用戶提供集群限流控制臺功能,能夠通過控制臺配置集群的限流規(guī)則以及配置集群的Server與Client。

集群限流客戶端

要想使用集群限流功能,必須引入集群限流 client 相關(guān)依賴:


	
  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-cluster-client-default</artifactId>
  4. <version>1.8.0</version>
  5. </dependency>

集群限流服務(wù)端

要想使用集群限流服務(wù)端,必須引入集群限流 server 相關(guān)依賴:


	
  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-cluster-server-default</artifactId>
  4. <version>1.8.0</version>
  5. </dependency>

我們結(jié)合server和client實現(xiàn)一個嵌入式模式。在pom中同時引入上面的兩個依賴,并配置sentinel控制臺地址,實現(xiàn)一個查詢訂單的接口。

pom


	
  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-cluster-server-default</artifactId>
  4. </dependency>
  5.  
  6. <dependency>
  7. <groupId>com.alibaba.csp</groupId>
  8. <artifactId>sentinel-cluster-client-default</artifactId>
  9. </dependency>

application.yml


	
  1. server:
  2. port: 9091
  3.  
  4. spring:
  5. application:
  6. name: cloudalibaba-sentinel-clusterServer
  7. cloud:
  8. sentinel:
  9. transport:
  10. #配置sentinel dashboard地址
  11. dashboard: localhost:8080
  12. port: 8719 #默認(rèn)8719端口

OrderController


	
  1. @RestController
  2. public class OrderController {
  3. /**
  4. * 查詢訂單
  5. * @return
  6. */
  7. @GetMapping("/order/{id}")
  8. public CommonResult<Order> getOrder(@PathVariable("id") Long id){
  9.  
  10. Order order = new Order(id, "212121");
  11. return CommonResult.success(order.toString());
  12. }
  13. }

代碼示例如cloudalibaba-sentinel-cluster-embedded9091

修改VM options配置,啟動三個不同端口的實例,即可。


	
  1. -Dserver.port=9091 -Dproject.name=cloudalibaba-sentinel-clusterServer -Dcsp.sentinel.log.use.pid=true
  2. -Dserver.port=9092 -Dproject.name=cloudalibaba-sentinel-clusterServer -Dcsp.sentinel.log.use.pid=true
  3. -Dserver.port=9093 -Dproject.name=cloudalibaba-sentinel-clusterServer -Dcsp.sentinel.log.use.pid=true

控制臺配置

登錄sentinel的控制臺,并有訪問量后,我們就可以在 Sentinel上面看到集群流控,如下圖所示:

點擊添加Token Server。

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

從實例列表中選擇一個作為Server端,其他作為Client端,并選中到右側(cè)Client列表,配置token sever端的最大允許的QPS,用于對 Token Server 的資源使用進(jìn)行限制,防止在嵌入模式下影響應(yīng)用本身。

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

配置完成之后的Token Server列表,如下圖所示

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

使用控制臺配置token Server、token Client以及限流規(guī)則,有很多的缺點:

1、限流規(guī)則,不能持久化,應(yīng)用重啟之后,規(guī)則丟失。

2、token Server 、token Client配置也會丟失。

官方推薦給集群限流服務(wù)端注冊動態(tài)配置源來動態(tài)地進(jìn)行配置。我們使用nacos作為配置中心,動態(tài)配置客戶端與服務(wù)端屬性以及限流規(guī)則,實現(xiàn)動態(tài)集群限流。

sentinel結(jié)合nacos實現(xiàn)集群限流

我們使用Nacos對cloudalibaba-sentinel-cluster-embedded9091進(jìn)行改造,實現(xiàn)動態(tài)配置源來動態(tài)進(jìn)行配置。

配置源注冊的相關(guān)邏輯可以置于 InitFunc 實現(xiàn)類中,并通過 SPI 注冊,在 Sentinel 初始化時即可自動進(jìn)行配置源加載監(jiān)聽。

嵌入模式部署

添加ClusterInitFunc類


	
  1. public class ClusterInitFunc implements InitFunc {
  2.  
  3. //應(yīng)用名稱
  4. private static final String APP_NAME = AppNameUtil.getAppName();
  5.  
  6. //nacos集群地址
  7. private final String remoteAddress = "localhost:8848";
  8.  
  9. //nacos配置的分組名稱
  10. private final String groupId = "SENTINEL_GROUP";
  11.  
  12. //配置的dataId
  13. private final String flowDataId = APP_NAME + Constants.FLOW_POSTFIX;
  14. private final String paramDataId = APP_NAME + Constants.PARAM_FLOW_POSTFIX;
  15. private final String configDataId = APP_NAME + Constants.CLIENT_CONFIG_POSTFIX;
  16. private final String clusterMapDataId = APP_NAME + Constants.CLUSTER_MAP_POSTFIX;
  17.  
  18. private static final String SEPARATOR = "@";
  19.  
  20.  
  21. @Override
  22. public void init() {
  23. // Register client dynamic rule data source.
  24. //動態(tài)數(shù)據(jù)源的方式配置sentinel的流量控制和熱點參數(shù)限流的規(guī)則。
  25. initDynamicRuleProperty();
  26.  
  27. // Register token client related data source.
  28. // Token client common config
  29. // 集群限流客戶端的配置屬性
  30. initClientConfigProperty();
  31. // Token client assign config (e.g. target token server) retrieved from assign map:
  32. //初始化Token客戶端
  33. initClientServerAssignProperty();
  34.  
  35. // Register token server related data source.
  36. // Register dynamic rule data source supplier for token server:
  37. //集群的流控規(guī)則,比如限制整個集群的流控閥值,啟動的時候需要添加-Dproject.name=項目名
  38. registerClusterRuleSupplier();
  39. // Token server transport config extracted from assign map:
  40. //初始化server的端口配置
  41. initServerTransportConfigProperty();
  42.  
  43. // Init cluster state property for extracting mode from cluster map data source.
  44. //初始化集群中服務(wù)是客戶端還是服務(wù)端
  45. initStateProperty();
  46. }
  47.  
  48. private void initDynamicRuleProperty() {
  49.  
  50. //流量控制的DataId分別是APP_NAME + Constants.FLOW_POSTFIX;熱點參數(shù)限流規(guī)則的DataId是APP_NAME + Constants.PARAM_FLOW_POSTFIX;
  51.  
  52. ReadableDataSource<String, List<FlowRule>> ruleSource = new NacosDataSource<>(remoteAddress, groupId,
  53. flowDataId, source -> jsON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
  54. FlowRuleManager.register2Property(ruleSource.getProperty());
  55.  
  56. ReadableDataSource<String, List<ParamFlowRule>> paramRuleSource = new NacosDataSource<>(remoteAddress, groupId,
  57. paramDataId, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
  58. ParamFlowRuleManager.register2Property(paramRuleSource.getProperty());
  59. }
  60.  
  61. private void initClientConfigProperty() {
  62. ReadableDataSource<String, ClusterClientConfig> clientConfigDs = new NacosDataSource<>(remoteAddress, groupId,
  63. configDataId, source 編程客棧-> JSON.parseObject(source, new TypeReference<ClusterClientConfig>() {}));
  64. ClusterClientConfigManager.registerClientConfigProperty(clientConfigDs.getProperty());
  65. }
  66.  
  67. private void initServerTransportConfigProperty() {
  68. ReadableDataSource<String, ServerTransportConfig> serverTransportDs = new NacosDataSource<>(remoteAddress, groupId,
  69. clusterMapDataId, source -> {
  70. List<ClusterGroupEntity> groupList = new Gson().fromJson(source, new TypeToken<List<ClusterGroupEntity>>(){}.getType());
  71. return Optional.ofNullable(groupList)
  72. www.cppcns.com .flatMap(this::extractServerTransportConfig)
  73. .orElse(null);
  74. });
  75. ClusterServerConfigManager.registerServerTransportProperty(serverTransportDs.getProperty());
  76. }
  77.  
  78. private void registerClusterRuleSupplier() {
  79. // Register cluster flow rule property supplier which creates data source by namespace.
  80. // Flow rule dataId format: ${namespace}-flow-rules
  81. ClusterFlowRuleManager.setPropertySupplier(namespace -> {
  82. ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
  83. namespace + Constants.FLOW_POSTFIX, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
  84. return ds.getProperty();
  85. });
  86. // Register cluster parameter flow rule property supplier which creates data source by namespace.
  87. ClusterParamFlowRuleManager.setPropertySupplier(namespace -> {
  88. ReadableDataSource<String, List<ParamFlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
  89. namespace + Constants.PARAM_FLOW_POSTFIX, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
  90. return ds.getProperty();
  91. });
  92. }
  93.  
  94. private void initClientServerAssignProperty() {
  95. // Cluster map format:
  96. // [{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","serverId":"112.12.88.68@8728","port":11111}]
  97. // serverId: <ip@commandPort>, commandPort for port exposed to Sentinel dashboard (transport module)
  98. ReadableDataSource<String, ClusterClientAssignConfig> clientAssignDs = new NacosDataSource<>(remoteAddress, groupId,
  99. clusterMapDataId, source -> {
  100. List<ClusterGroupEntity> groupList = new Gson().fromJson(source, new TypeToken<List<ClusterGroupEntity>>(){}.getType());
  101. return Optional.ofNullable(groupList)
  102. .flatMap(this::extractClientAssignment)
  103. .orElse(null);
  104. });
  105. ClusterClientConfigManager.registerServerAssignProperty(clientAssignDs.getProperty());
  106. }
  107.  
  108. private void initStateProperty() {
  109. // Cluster map format:
  110. // [{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","serverId":"112.12.88.68@8728","port":11111}]
  111. // serverId: <ip@commandPort>, commandPort for port exposed to Sentinel dashboard (transport module)
  112. ReadableDataSource<String, Integer> clusterModeDs = new NacosDataSource<>(remoteAddress, groupId,
  113. clusterMapDataId, source -> {
  114. List<ClusterGroupEntity> groupList = new Gson().fromJson(source, new TypeToken<List<ClusterGroupEntity>>(){}.getType());
  115. return Optional.ofNullable(groupList)
  116. .map(this::extractMode)
  117. .orElse(ClusterStateManager.CLUSTER_NOT_STARTED);
  118. });
  119. ClusterStateManager.registerProperty(clusterModeDs.getProperty());
  120. }
  121.  
  122. private int extractMode(List<ClusterGroupEntity> groupList) {
  123. // If any server group serverId matches current, then it's token server.
  124. if (groupList.stream().anyMatch(this::machineEqual)) {
  125. return ClusterStateManager.CLUSTER_SERVER;
  126. }
  127. // If current machine belongs to any of the token server group, then it's token client.
  128. // Otherwise it's unassigned, should be set to NOT_STARTED.
  129. boolean canBeClient = groupList.stream()
  130. .flatMap(e -> e.getClientSet().stream())
  131. .filter(Objects::nonNull)
  132. .anyMatch(e -> e.equals(getCurrentMachineId()));
  133. return canBeClient ? ClusterStateManager.CLUSTER_CLIENT : ClusterStateManager.CLUSTER_NOT_STARTED;
  134. }
  135.  
  136. private Optional<ServerTransportConfig> extractServerTransportConfig(List<ClusterGroupEntity> groupList) {
  137. return groupList.stream()
  138. .filter(this::machineEqual)
  139. .findAny()
  140. .map(e -> new ServerTransportConfig().setPort(e.getPort()).setIdleSeconds(600));
  141. }
  142.  
  143. private Optional<ClusterClientAssignConfig> extractClientAssignment(List<ClusterGroupEntity> groupList) {
  144. if (groupList.stream().anyMatch(this::mwww.cppcns.comachineEqual)) {
  145. return Optional.empty();
  146. }
  147. // Build client assign config from tJTVlRhe client set of target server group.
  148. for (ClusterGroupEntity group : groupList) {
  149. if (group.getClientSet().contains(getCurrentMachineId())) {
  150. String ip = group.getIp();
  151. Integer port = group.getPort();
  152. return Optional.of(new ClusterClientAssignConfig(ip, port));
  153. }
  154. }
  155. return Optional.empty();
  156. }
  157.  
  158. private boolean machineEqual(/*@Valid*/ ClusterGroupEntity group) {
  159. return getCurrentMachineId().equals(group.getServerId());
  160. }
  161.  
  162. private String getCurrentMachineId() {
  163. // Note: this may not work well for container-based env.
  164. return HostNameUtil.getIp() + SEPARATOR + TransportConfig.getRuntimePort();
  165. }
  166. }

在resources文件夾下創(chuàng)建META-INF/service,,然后創(chuàng)建一個叫做com.alibaba.csp.sentinel.init.InitFunc的文件,在文件中指名實現(xiàn)InitFunc接口的類全路徑,內(nèi)容如下:


	
  1. com.liang.springcloud.alibaba.init.ClusterInitFunc

添加配置的解析類:


	
  1. public class ClusterGroupEntity implements Serializable {
  2.  
  3. private String serverId;
  4. private String ip;
  5. private Integer port;
  6. private Set<String> clientSet;
  7.  
  8. public String getServerId() {
  9. return serverId;
  10. }
  11.  
  12. public void setServerId(String serverId) {
  13. this.serverId = serverId;
  14. }
  15.  
  16. public String getIp() {
  17. return ip;
  18. }
  19.  
  20. public void setIp(String ip) {
  21. this.ip = ip;
  22. }
  23.  
  24. public Integer getPort() {
  25. return port;
  26. }
  27.  
  28. public void setPort(Integer port) {
  29. this.port = port;
  30. }
  31.  
  32. public Set<String> getClientSet() {
  33. return clientSet;
  34. }
  35.  
  36. public void setClientSet(Set<String> clientSet) {
  37. this.clientSet = clientSet;
  38. }
  39.  
  40. @Override
  41. public String toString() {
  42. return "ClusterGroupEntity{" +
  43. "serverId='" + serverId + '\'' +
  44. ", ip='" + ip + '\'' +
  45. ", port=" + port +
  46. ", clientSet=" + clientSet +
  47. '}';
  48. }
  49. }

在Nacos中添加動態(tài)規(guī)則配置,以及token server與token client的配置:

DataId:cloudalibaba-sentinel-clusterServer-flow-rules Group:SENTINEL_GROUP 配置內(nèi)容(json格式):


	
  1. [
  2. {
  3. "resource" : "/order/{id}", // 限流的資源名稱
  4. "grade" : 1, // 限流模式為:qps,線程數(shù)限流0,qps限流1
  5. "count" : 20, // 閾值為:20
  6. "clusterMode" : true, // 是否是集群模式,集群模式為:true
  7. "clusterConfig" : {
  8. "flowId" : 111, // 全局唯一id
  9. "thresholdType" : 1, // 閾值模式為:全局閾值,0是單機均攤,1是全局閥值
  10. "fallbackToLocalWhenFail" : true // 在 client 連接失敗或通信失敗時,是否退化到本地的限流模式
  11. }
  12. }
  13. ]

DataId:cloudalibaba-sentinel-clusterServer-cluster-client-config Group:SENTINEL_GROUP 配置內(nèi)容(json格式):


	
  1. {
  2. "requestTimeout": 20
  3. }

DataId:cloudalibaba-sentinel-clusterServer-cluster-map Group:SENTINEL_GROUP 配置內(nèi)容(json格式):


	
  1. [{
  2. "clientSet": ["10.133.40.30@8721", "10.133.40.30@8722"],
  3. "ip": "10.133.40.30",
  4. "serverId": "10.133.40.30@8720",
  5. "port": 18730 //這個端口是token server通信的端口
  6. }]

重新啟動服務(wù),并訪問接口,我們可以看到流控規(guī)則與集群流控都自動配置完成。我們需要測試,我們集群流控是否已經(jīng)生效。

不斷執(zhí)行以下命令:


	
  1. ab -n 100 -c 50 http://localhost:9091/order/1
  2. ab -n 100 -c 50 http://localhost:9092/order/3
  3. ab -n 100 -c 50 http://localhost:9093/order/1

測試效果圖:

我們從實時監(jiān)控圖上可以看出,資源名為/order/{id},整個集群的QPS為20,跟我們的配置是一樣的。當(dāng)作為token server的機器掛掉后,集群限流會退化到 local 模式的限流,即在本地按照單機閾值執(zhí)行限流檢查。

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

Token Server 分配配置:

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

上面這張圖可以很好幫忙我們解釋嵌入模式的具體實現(xiàn)。通過配置信息解析,管理我們的token server與token client。

適用范圍:

嵌入模式適合某個應(yīng)用集群內(nèi)部的流控。由于隔離性不佳,token server會影響應(yīng)用本身,需要限制 token server 的總QPS。

獨立模式部署

獨立模式相對于嵌入模式而言就是將token server與應(yīng)用隔離,進(jìn)行獨立部署。將嵌入模式中token server和token client分離,分別進(jìn)行配置。我們只需要將 InitFunc 實現(xiàn)類進(jìn)行拆分。

token server的nacos配置

server的名稱空間配置,(集群的namespace或客戶端項目名)如下:

DataId:cluster-server-namespace-set Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. [
  2. "cloudalibaba-sentinel-cluster-client-alone"
  3. ]

server的通信端口配置,如下:

DataId:cluster-server-transport-config Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. {
  2. "idleSecods":600,
  3. "port": 18730
  4. }

Token sever的流控限制配置,如下:

DataId:cluster-server-flow-config Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. {
  2. "exceedCount":1.0,
  3. "maxAllowedQps":20000,
  4. "namespace":"cloudalibaba-sentinel-clust編程客棧er-client-alone"
  5. }

token server的host地址與端口號配置,如下:

DataId: cluster-server-config Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. {
  2. "serverHost": "10.133.40.30",
  3. "serverPort": 18730
  4. }

token server的InitFunc類:


	
  1. /**
  2. * @PROJECT_NAME: SpringCloud-Learning
  3. * @USER: yuliang
  4. * @DESCRIPTION:
  5. * @DATE: 2021-04-01 10:01
  6. */
  7. public class ClusterServerInitFunc implements InitFunc {
  8.  
  9. //nacos集群地址
  10. private final String remoteAddress = "localhost:8848";
  11. //配置的分組名稱
  12. private final String groupId = "SENTINEL_ALONE_GROUP";
  13.  
  14. //配置的dataId
  15. private final String namespaceSetDataId = "cluster-server-namespace-set";
  16. private final String serverTransportDataId = "cluster-server-transport-config";
  17. private final String serverFlowDataId = "cluster-server-flow-config";
  18.  
  19. @Override
  20. public void init() {
  21.  
  22. //監(jiān)聽特定namespace(集群的namespace或客戶端項目名)下的集群限流規(guī)則
  23. initPropertySupplier();
  24. // 設(shè)置tokenServer管轄的作用域(即管理哪些應(yīng)用)
  25. initTokenServerNameSpaces();
  26.  
  27. // Server transport configuration data source.
  28. //Server端配置
  29. initServerTransportConfig();
  30.  
  31. // 初始化最大qps
  32. initServerFlowConfig();
  33.  
  34. //初始化服務(wù)器狀態(tài)
  35. initStateProperty();
  36.  
  37. }
  38.  
  39. private void initPropertySupplier(){
  40.  
  41. // Register cluster flow rule property supplier which creates data source by namespace.
  42. // Flow rule dataId format: ${namespace}-flow-rules
  43. ClusterFlowRuleManager.setPropertySupplier(namespace -> {
  44. ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
  45. namespace + Constants.FLOW_POSTFIX,
  46. source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
  47. return ds.getProperty();
  48. });
  49. // Register cluster parameter flow rule property supplier which creates data source by namespace.
  50. ClusterParamFlowRuleManager.setPropertySupplier(namespace -> {
  51. ReadableDataSource<String, List<ParamFlowRule>> ds = new NacosDataSource<>(remoteAddress, groupId,
  52. namespace + Constants.PARAM_FLOW_POSTFIX, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
  53. return ds.getProperty();
  54. });
  55.  
  56. }
  57.  
  58.  
  59. private void initTokenServerNameSpaces(){
  60. // Server namespace set (scope) data source.
  61. ReadableDataSource<String, Set<String>> namespaceDs = new NacosDataSource<>(remoteAddress, groupId,
  62. namespaceSetDataId, source -> JSON.parseObject(source, new TypeReference<Set<String>>() {}));
  63. ClusterServerConfigManager.registerNamespaceSetProperty(namespaceDs.getProperty());
  64. }
  65.  
  66. private void initServerTransportConfig(){
  67. // Server transport configuration data source.
  68. ReadableDataSource<String, ServerTransportConfig> transportConfigDs = new NacosDataSource<>(remoteAddress,
  69. groupId, serverTransportDataId,
  70. source -> JSON.parseObject(source, new TypeReference<ServerTransportConfig>() {}));
  71. ClusterServerConfigManager.registerServerTransportProperty(transportConfigDs.getProperty());
  72. }
  73.  
  74.  
  75. private void initServerFlowConfig(){
  76.  
  77. // Server namespace set (scope) data source.
  78. ReadableDataSource<String, ServerFlowConfig> serverFlowConfig = new NacosDataSource<>(remoteAddress, groupId,
  79. serverFlowDataId, source -> JSON.parseObject(source, new TypeReference<ServerFlowConfig>() {}));
  80.  
  81. ClusterServerConfigManager.registerGlobalServerFlowProperty(serverFlowConfig.getProperty());
  82. }
  83.  
  84. private void initStateProperty() {
  85. ClusterStateManager.applyState(ClusterStateManager.CLUSTER_SERVER);
  86.  
  87. }
  88. }

token client的nacos配置

客戶端請求超時配置,如下:

DataId:cluster-client-config Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. {
  2. "requestTimeout": 20
  3. }

流控限流配置,如下:

DataId: cloudalibaba-sentinel-cluster-client-alone-flow-rules Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. [
  2. {
  3. "resource" : "/order/{id}", // 限流的資源名稱
  4. "grade" : 1, // 限流模式為:qps
  5. "count" : 30, // 閾值為:30
  6. "clusterMode" : true, // 集群模式為:true
  7. "clusterConfig" : {
  8. "flowId" : 111, // 全局唯一id
  9. "thresholdType" : 1, // 閾值模式為:全局閾值
  10. "fallbackToLocalWhenFail" : true // 在 client 連接失敗或通信失敗時,是否退化到本地的限流模式
  11. }
  12. }
  13. ]

熱點限流配置,如下:

DataId:cloudalibaba-sentinel-cluster-client-alone-param-rules Group:SENTINEL_ALONE_GROUP 配置內(nèi)容(json格式):


	
  1. [
  2. {
  3. "resource" : "order", // 限流的資源名稱
  4. "paramIdx" : 1, //參數(shù)索引
  5. "grade" : 1, // 限流模式為:qps
  6. "count" : 10, // 閾值為:10
  7. "clusterMode" : true, // 集群模式為:true
  8. "clusterConfig" : {
  9. "flowId" : 121, // 全局唯一id
  10. "thresholdType" : 1, // 閾值模式為:全局閾值
  11. "fallbackToLocalWhenFail" : true // 在 client 連接失敗或通信失敗時,是否退化到本地的限流模式
  12. },
  13. "paramFlowItemList":[ //索引為1的參數(shù)值為hot時,接口閾值為50,其他值均為10
  14. {
  15. object: "hot",
  16. count: 50,
  17. classType: "java.lang.String"
  18. }
  19. ]
  20. }
  21. ]

Token client的InitFunc類:


	
  1. /**
  2. * @PROJECT_NAME: SpringCloud-Learning
  3. * @USER: yuliang
  4. * @DESCRIPTION:
  5. * @DATE: 2021-04-01 17:47
  6. */
  7. public class ClusterClientInitFunc implements InitFunc {
  8.  
  9. //項目名稱
  10. private static final String APP_NAME = AppNameUtil.getAppName();
  11. //nacos集群地址
  12. private final String remoteAddress = "localhost:8848";
  13. //nacos配置的分組名稱
  14. private final String groupId = "SENTINEL_ALONE_GROUP";
  15.  
  16. //項目名稱 + Constants的配置名稱,組成配置的dataID
  17. private final String flowDataId = APP_NAME + Constants.FLOW_POSTFIX;
  18. private final String paramDataId = APP_NAME + Constants.PARAM_FLOW_POSTFIX;
  19. private final String configDataId = "cluster-client-config";
  20. private final String serverDataId = "cluster-server-config";
  21.  
  22.  
  23. @Override
  24. public void init() throws Exception {
  25.  
  26. // Register client dynamic rule data source.
  27. //客戶端,動態(tài)數(shù)據(jù)源的方式配置sentinel的流量控制和熱點參數(shù)限流的規(guī)則。
  28. initDynamicRuleProperty();
  29.  
  30. // Register token client related data source.
  31. // Token client common config
  32. // 集群限流客戶端的配置屬性
  33. initClientConfigProperty();
  34. // Token client assign config (e.g. target token server) retrieved from assign map:
  35. //初始化Token客戶端
  36. initClientServerAssignProperty();
  37.  
  38. //初始化客戶端狀態(tài)
  39. initStateProperty();
  40. }
  41.  
  42. private void initDynamicRuleProperty() {
  43.  
  44. //流量控制的DataId分別是APP_NAME + Constants.FLOW_POSTFIX;熱點參數(shù)限流規(guī)則的DataId是APP_NAME + Constants.PARAM_FLOW_POSTFIX;
  45.  
  46. ReadableDataSource<String, List<FlowRule>> ruleSource = new NacosDataSource<>(remoteAddress, groupId,
  47. flowDataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
  48. FlowRuleManager.register2Property(ruleSource.getProperty());
  49.  
  50. ReadableDataSource<String, List<ParamFlowRule>> paramRuleSource = new NacosDataSource<>(remoteAddress, groupId,
  51. paramDataId, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {}));
  52. ParamFlowRuleManager.register2Property(paramRuleSource.getProperty());
  53. }
  54.  
  55. private void initClientConfigProperty() {
  56. ReadableDataSource<String, ClusterClientConfig> clientConfigDs = new NacosDataSource<>(remoteAddress, groupId,
  57. configDataId, source -> JSON.parseObject(source, new TypeReference<ClusterClientConfig>() {}));
  58. ClusterClientConfigManager.registerClientConfigProperty(clientConfigDs.getProperty());
  59. }
  60.  
  61. private void initClientServerAssignProperty() {
  62. ReadableDataSource<String, ClusterClientAssignConfig> clientAssignDs = new NacosDataSource<>(remoteAddress, groupId,
  63. serverDataId, source -> JSON.parseObject(source, new TypeReference<ClusterClientAssignConfig>() {}));
  64. ClusterClientConfigManager.registerServerAssignProperty(clientAssignDs.getProperty());
  65. }
  66.  
  67. private void initStateProperty() {
  68. ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);
  69.  
  70. }
  71. }

核心的代碼與配置,如上所示,其他代碼,可以訪問:


	
  1. <module>cloudalibaba-sentinel-cluster-server-alone9092</module>
  2. <module>cloudalibaba-sentinel-cluster-client-alone9093</module>

測試:

啟動cloudalibaba-sentinel-cluster-server-alone9092,我們啟動兩個實例,模擬集群(可以啟動多個):


	
  1. -Dserver.port=9092 -Dcsp.sentinel.log.use.pid=true
  2. -Dserver.port=9094 -Dcsp.sentinel.log.use.pid=true

啟動cloudalibaba-sentinel-cluster-client-alone9093,我們啟動1個實例,模擬server(實現(xiàn)master選舉之后,可以啟動多個):


	
  1. -Dserver.port=9093 -Dcsp.sentinel.log.use.pid=true

不斷執(zhí)行以下命令,進(jìn)行接口訪問測試:


	
  1. ab -n 100 -c 50 http://localhost:9092/order/1
  2. ab -n 100 -c 50 http://localhost:9094/order/3

我們從實時監(jiān)控圖上可以看出,資源名為/order/{id},整個集群的QPS為30,跟我們的配置是一樣的。當(dāng)作為token server的機器掛掉后,集群限流會退化到 local 模式的限流,即在本地按照單機閾值執(zhí)行限流檢查。

Sentinel實現(xiàn)動態(tài)配置的集群流控的方法

熱點限流已經(jīng)為大家實現(xiàn)了,大家可以自行測試,比較簡單,不再累述。


	
  1. ab -n 100 -c 50 http://localhost:9092/hot_order/1/hot
  2. ab -n 100 -c 50 http://localhost:9094/hot_order/1/hot
  3.  
  4. ab -n 100 -c 50 http://localhost:9092/hot_order/1/nothot
  5. ab -n 100 -c 50 http://localhost:9094/hot_order/1/nothot

其它

若在生產(chǎn)環(huán)境使用集群限流,管控端還需要關(guān)注以下的問題:

  • Token Server 自動管理、調(diào)度(分配/選舉 Token Server)
  • Token Server 高可用,在某個 server 不可用時自動 failover 到其它機器

 總結(jié)

集群流控,有兩種模式,嵌入模式和獨立模式,個人不建議在業(yè)務(wù)系統(tǒng)使用集群流控,集群流控可以在網(wǎng)關(guān)層做,業(yè)務(wù)層的話可以使用單機流控,相對來說簡單好上手。token server目前存在單點問題,需要個人實現(xiàn)master選舉,并修改 cluster-server-config的IP即可。

代碼示例

本文示例讀者可以通過查看下面?zhèn)}庫中的項目,如下所示:


	
  1. <module>cloudalibaba-sentinel-cluster</module>

github:https://github.com/jiuqiyuliang/SpringCloud-Learning

到此這篇關(guān)于Sentinel實現(xiàn)動態(tài)配置的集群流控的文章就介紹到這了,更多相關(guān)Sentinel集群流控內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/jiuqiyuliang/article/details/115524800

延伸 · 閱讀

精彩推薦
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7472021-02-04
  • Java教程Java實現(xiàn)搶紅包功能

    Java實現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
主站蜘蛛池模板: 亚洲色欲色欲综合网站 | 亚洲国产精品一区二区久久 | japanese在线观看 | 亚洲熟区 | 精品亚洲国产一区二区 | 2019年国产高清情侣视频 | 水蜜臀 | 国产精品全国探花在线观看 | 亚洲热在线观看 | 成人久久久 | 好看的亚洲视频 | 日本不卡在线一区二区三区视频 | 红怡院欧洲 | 女人与d0gxxx| 91国语精品自产拍在线观看一 | 国产精品欧美亚洲韩国日本 | 99热这里只有精品久久免费 | 人成网站在线观看 | 小鸟酱视频在线观看 | 精品免费视在线视频观看 | 午夜福利在线观看6080 | 91庥豆果冻天美精东蜜桃传媒 | 国产一级持黄大片99久久 | 我将她侵犯1~6樱花动漫在线看 | 欧美日韩中文国产一区二区三区 | 深夜免费网站 | 高清不卡日本v在线二区 | 538精品视频 | 高h短篇辣肉各种姿势bl | 奇米影视7777久久精品 | 国产第9页 | 黄 色 成 年人在线 幻女free性俄罗斯第一次摘花 | 东北老妇露脸xxxxx | 把女的下面扒开添视频 | 日本免费三片在线播放 | tube69中国露脸| 青青久久久 | 日韩精品在线视频观看 | 亚洲白拍 | 国产精品免费小视频 | 兽皇videos日本另类 |