Sentinel 的工作模式
- 在 Sentinel 客户端(微服务)中用代码写的配置,在启动后,当有第一次流量进来的时候,会推送给 Sentinel-Dashboard;
- 在 Sentinel-Dashboard 中的配置,会被推送到 Sentinal 客户端(微服务);
- 默认情况下,不论 Sentinel-Dashboard 中的配置还是 Sentinal 客户端中的配置,都是在内存中的,一点重启,这些变化过的规则就都消失了;
Sentinel 引入配置中心
- Sentinel-Dashboard 需要知道,当配置发生变化的时候,要把配置推送到配置中心,持久话保存起来;
- 客户端要知道,配置全在配置中心里存的呢,一旦配置发生变化,配置中心要把配置推给我;
- 这样的话,不论是 Sentinel-Dashboard 还是 Sentinel 客户端重启后,都不会丢失配置;
启动 zookeeper
-
bin/zkServer.sh start
;
修改 sentinel-dashboard 的源码
打开项目 sentinel-dashboard
- 作为一个 Module 引入项目 ms-security;
修改 pom 文件
- 把 scope 的 test 注释掉,这样打包的时候,就可以把和 zookeeper 整合相关的依赖打进去了;
<!--for Zookeeper rule publisher sample-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
<!-- <scope>test</scope>-->
</dependency>
把已经写好的整合 zookeeper 的代码发到合适的位置
- 其实和 zookeeper 整合的代码是有的,只不过在 test 目录下,把这写代码移到 main 的相同目录下就行了;
- 包
com.alibaba.csp.sentinel.dashboard.rule.zookeeper
从 test 目录下拷贝到 main 下,一共 4 个类;
改代码
- 类
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
;
原来的:
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
改成:
@Autowired
@Qualifier("flowRuleZookeeperProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleZookeeperPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
改配置文件
- 位置:
sentinel-dashboard/src/main/resources/application.properties
; - 启动的端口改一下,因为 zookeeper 启动的时候,会占用 8080 端口号;
server.port=8082
改页面
- 位置:
src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
;
原来的:
<li ui-sref-active="active" ng-if="!entry.isGateway">
<a ui-sref="dashboard.flowV1({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
改成:
<li ui-sref-active="active" ng-if="!entry.isGateway">
<a ui-sref="dashboard.flow({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
直接运行启动类
- 位置:
com.alibaba.csp.sentinel.dashboard.DashboardApplication
;
重新配置 Sentinel 客户端(微服务:order)
用代码配置的规则都不要了
-
com.lixinlei.security.order.config.SentinelConfig
这个类可以直接删了;
sentinel-dashboard 的地址改一下
spring:
application:
# sentinel-bashboard 中会显示这个名字
name: orderApi
cloud:
sentinel:
transport:
# 在 9080 启动 orderApi 的时候,sentinel 还会在 8719 这个端口起一个服务和 sentinel-dashboard 通信(发心跳)
port: 8719
# sentinel-dashboard 的地址
dashboard: localhost:8082
配置规则
配置流控规则 createOrder (sentinel-dashboard 中)
- 配置完了 zookeeper 的根目录中就会有一个
sentinel_rule_config
节点,sentinel 所有的规则配置都是放在这个节点下面的; -
sentinel_rule_config
下面有一个/orderApi
节点,这个是 order 这个微服务的spring.application.name
; - 重启 sentinel-dashboard 和 orderApi,sentinel-dashboard 依然还有上次的配置;
- 此时,虽然限流规则已经通过 sentinel-dashboard 写到 zookeeper 中了,但是 Sentinel 客户端(orderApi)还不知到;
让 Sentinel 知道规则配置在 zookeeper 中
依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-zookeeper</artifactId>
<version>1.5.2</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
application.yml
# 让 Sentinel 客户端(orderApi)知道去 zookeeper 中拿配置规则
sentinel:
zookeeper:
address: 127.0.0.1:2181
path: /sentinel_rule_config
配置类
package com.lixinlei.security.order.config;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
/**
* 这里配置,让 Sentinel 客户端到 zookeeper 中读配置规则
*/
@Component
public class SentinelConfigZookeeper {
@Value("${sentinel.zookeeper.address}")
private String zkServer;
@Value("${sentinel.zookeeper.path}")
private String zkPath;
@Value("${spring.application.name}")
private String appName;
/**
* 这个 Bean 构造好了之后,马上就取 zookeeper 中读配置规则
*/
@PostConstruct
public void loadRules() {
// 第一个泛型 String,就是应用的名字,orderApi,
// 第二个泛型,就是这个应用对应的一组流量规则;
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource
= new ZookeeperDataSource<>(zkServer,
zkPath + "/" + appName,
// source 就是从 zookeeper 中读出来的字符串
source -> JSON.parseArray(source, FlowRule.class));
// 把从 zookeeper 中读到的配置规则,写入内存
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}
重启之后,在 sentinel-dashboard 配置的规则就可以在 orderApi 中生效了,此时 sentinel-dashboard 和 orderApi 之间就没有直接通信了,两者通过 zookeeper 完成交互。