Sentinel 整合 Spring Cloud + Gateway + 控制台Nacos持久化
项目版本Spring Boot版本:2.2.9.RELEASESpring Cloud版本:Hoxton.SR7Spring Cloud Alibaba版本:2.2.1.RELEASE官方doc所有功能文档概况官方文档介绍本文分为以下几部分:普通服务集成控制台整合Nacos自己Github重新封装地址网关集成(spring cloud gateway)控制台启动、参数和指定Nacos地址+name
项目版本
Spring Boot版本:2.2.9.RELEASE
Spring Cloud版本:Hoxton.SR7
Spring Cloud Alibaba版本:2.2.1.RELEASE
官方doc
介绍
本文分为以下几部分:
- 普通服务集成
- 控制台整合Nacos 自己Github重新封装地址
- 网关集成(spring cloud gateway)
- 控制台启动、参数和指定Nacos地址+namespace等
Nacos持久化最终效果图如下:
普通服务
注:Sentinel兼容Hystrix的FallbackFactory
从 Hystrix 迁移到 Sentinel方案(官方)
- https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel
Sentinel 与 Hystrix 的对比(官方)
- https://github.com/alibaba/Sentinel/wiki/Sentinel-%E4%B8%8E-Hystrix-%E7%9A%84%E5%AF%B9%E6%AF%94
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class NacosProviderClientFallback implements FallbackFactory<NacosProviderClient> {
@Override
public NacosProviderClient create(Throwable throwable) {
return new NacosProviderClient() {
@Override
public String abc(String name, int age) {
log.error("用 nacos-provider abc 方法失败, 异常信息={}", throwable.getMessage());
//throw new RuntimeException("abc:" + throwable.getMessage());
//这里直接返回BusinessException(),因为
throw new RuntimeException("aaaaaaadssssssssssss");
// return throwable.getClass().getName() + " : " + throwable.getMessage();
}
@Override
public String getEcho(String string) {
log.error("用 nacos-provider getEcho 方法失败", throwable);
throw new RuntimeException("getEcho:" + throwable.getMessage());
}
};
}
}
基础包
基础包大概截图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4jyKDPvL-1603193351351)(https://upload-images.jianshu.io/upload_images/23703439-9c0ba26f2dac32e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
引入以下两个包,一个是sentinel核心组件,一个是整合nacos实现持久化功能组件(无关顺序)
<!-- alibaba Sentinel组件 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- alibaba Sentinel整合nacos组件 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
添加自定义异常处理(不加会返回默认的错误信息Blocked by Sentinel: XXXX)
注: 网上方案实现 UrlBlockHandler 接口的版本已经比较老了,新版本已经没有UrlBlockHandler 接口
/**
* 没有配资源,默认Block异常处理(只能是Block异常)
*/
@Slf4j
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
httpServletResponse.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
if (e instanceof FlowException) {
log.error("FlowException 普通服务限流,资源信息:" + JSON.toJSONString(e.getRule()));
httpServletResponse.setStatus(org.springframework.http.HttpStatus.TOO_MANY_REQUESTS.value());
ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1000, "API interface limited flow.");
} else if (e instanceof DegradeException) {
log.error("DegradeException 普通服务降级,资源信息:" + JSON.toJSONString(e.getRule()));
ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1001, "API interface has been degraded.");
} else if (e instanceof ParamFlowException) {
ParamFlowException ex = (ParamFlowException) e;
log.error("ParamFlowException 参数热点限流,资源名={},参数={},资源信息={}", ex.getResourceName(), ex.getLimitParam(), JSON.toJSONString(ex.getRule()));
ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1002, "API interface limited flow by params.");
} else if (e instanceof AuthorityException) {
log.error("AuthorityException 授权规则,资源信息:" + JSON.toJSONString(e.getRule()));
ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1003, "API interface limited by authority.");
} else if (e instanceof SystemBlockException) {
SystemBlockException systemBlockException = (SystemBlockException) e;
log.error("SystemBlockException,资源名:{},资源类型:{}", systemBlockException.getResourceName(), systemBlockException.getRuleLimitApp());
ResponseUtil.responseFailed(objectMapper, httpServletResponse, 1004, "API interface limited by system.");
}
}
}
非必须。配置默认加注解 @SentinelResource(value = “abcdd”,fallbackClass = DefaultBlockFallbackHandler.class, defaultFallback = “defaultFallback”) 返回的异常,可以做默认异常配置。如果默认不符合异常需求,可以在各接口自己定制自己的异常,可以是同类,也可以是不同类(不同类必须指定fallbackClass属性,参照上面注解例子)
以下走的默认异常 或 不同类异常,不在同一个类中(默认异常加fallbackClass )
@GetMapping(value = "/woqu")
@SentinelResource(value = "abcdd",
fallbackClass = DefaultBlockFallbackHandler.class, defaultFallback = "defaultFallback")
public String woqu(String name){
if(name.equals("abc")){
throw new IllegalArgumentException("adffdgdfg");
}
if(name.equals("bbb")){
try {
Thread.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "aaaaaaasdjkl" + name;
}
以下走的自定义异常(可以用同一个类中的,也可以用不同类中的,不同类加fallbackClass 属性)
@SentinelResource(value = "chello", blockHandler = "exceptionHandler2", defaultFallback = "fallback2")
@GetMapping(value = "/hello")
public String abcd(@RequestParam(value = "name") String name, int age){
log.info("name={}",name);
log.info("age={}",age);
String content = nacosProviderClient.abc(name, age);
return "我是feign: " + content;
}
public String exceptionHandler2(String name, int age, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at "+ name + ","+ age;
}
public String fallback2(Throwable e){
log.info("进入sentinelResource注解测试,进入fallback2,参数b={}", e.getMessage());
return "defaultFallback";
}
最后CustomRequestOriginParser这个只要是给授权黑名单或ip(AuthorityRule)生效的,可以各微服务自定义,这里放到基础包只是演示
简单实现黑名单功能:
@Component
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// <X> 从 Header 中,获得请求来源
String origin = request.getHeader("s-user");
// <Y> 如果为空,给一个默认的
if (StringUtils.isEmpty(origin)) {
origin = "default";
}
return origin;
}
}
简单实现ip限流功能:
@Component
public class CustomRequestOriginParser2 implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
String ip = null;
try {
ip = Inet4Address.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
String u = request.getRemoteUser();
return ip;
}
}
微服务处理
上面基础包搭建完毕,各微服务只需引入上述基础包:
<!-- sentinel自定义封装组件 -->
<dependency>
<groupId>com.myyshop.framework</groupId>
<artifactId>sentinel-spring-boot-starter</artifactId>
<version>1.0.0-RELEASE</version>
</dependency>
整合Nacos持久化需要引入基础包(上面有)。配置则引入如下配置:
注意:下面配置的信息,只有server-addr中的地址修改成自己nacos-config的地址即可,其余信息都不需要动,尤其是groupId、dataId的格式(应用名-flow-rules、应用名-degrade-rules、应用名-system-rules、应用名-authority-rules、应用名-param-flow-rules)、rule-type不能修改,这个是与sentinel控制台源码中推送数据到nacos约定好的。
spring:
cloud:
sentinel:
transport:
dashboard: 192.168.128.36:8081 #主要改这里,其他基本不用动
datasource:
# 名称随意,流控数据规则配置
flow:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
# 规则类型,取值见:
# org.springframework.cloud.alibaba.sentinel.datasource.RuleType
rule-type: flow
namespace: ${myyshop.sentinel.nacos.namespace}
# 名称随意,流控数据规则配置
degrade:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
namespace: ${myyshop.sentinel.nacos.namespace}
# 名称随意,流控数据规则配置
system:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system
namespace: ${myyshop.sentinel.nacos.namespace}
# 名称随意,流控数据规则配置
authority:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-authority-rules
groupId: SENTINEL_GROUP
rule-type: authority
namespace: ${myyshop.sentinel.nacos.namespace}
# 名称随意,流控数据规则配置
param:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
namespace: ${myyshop.sentinel.nacos.namespace}
eager: true #控制台热加载,false为懒加载(第一次调用接口才会加载)
Sentinel控制台整合Nacos实现推拉
使用Sentinel Dashboard动态推,拉数据同步到Nacos,使用Sentinel Dashboard动态推,拉数据同步到Nacos。
个人改Alibaba重新封装控制台源码:(分支 lbj_release-1.7)
- https://github.com/lbjfish/sentinel-parent
具体实现可以参考我整理的如下大佬们的文档:
- https://www.liangzl.com/get-article-detail-139092.html
- https://blog.csdn.net/dsh153/article/details/105767733 (跟下面那个一样)
- https://blog.csdn.net/weixin_41213402/article/details/105510373?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf
- http://blog.didispace.com/spring-cloud-alibaba-sentinel-2-4/
- https://blog.csdn.net/LSY_CSDN_/article/details/105114573?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.add_param_isCf (有源码1.6.2版本的)
- https://blog.csdn.net/lilizhou2008/article/details/97075236?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf (主要参照这个的)
- https://blog.csdn.net/zhulin2012/article/details/100987420?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.add_param_isCf
网关限流(Spring Cloud Gateway)
网关限流文档(官方)
- https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
Sentinel提供针对Spring Cloud Gateway的参数开关,该开关是针对JVM -D(java -jar -Dproject.name=***)的开关,如果要开启Sentinel控制台对网关特定页面的开关,则需要配置如下(最主要是-Dcsp.sentinel.app.type=1):
-Dcsp.sentinel.dashboard.server=192.168.128.36:8081 -Dcsp.sentinel.app.type=1
如果application.yml中有如下配置,则不需要加入(
-Dcsp.sentinel.dashboard.server=192.168.128.36:8081)
spring:
cloud:
sentinel:
transport:
dashboard: 192.168.128.36:8081
添加上述jar包启动参数之后,需要加入如下pom包依赖(引包顺序要严格按照下面这样,测试换位置不生效,不知道为什么)
<!--sentinel gateway依赖包-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
引入上述pom包依赖后,还需加入如下配置(主要是Nacos持久化配置):
spring:
cloud:
sentinel:
transport:
dashboard: 192.168.128.36:8081 #主要改这里,其他基本不用动
datasource:
gw-flow:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-gw-flow-rules
groupId: SENTINEL_GROUP
rule-type: gw-flow
namespace: ${myyshop.sentinel.nacos.namespace}
gw-api-group:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-gw-api-rules
groupId: SENTINEL_GROUP
rule-type: gw-api-group
namespace: ${myyshop.sentinel.nacos.namespace}
degrade:
nacos:
server-addr: ${spring.cloud.nacos.config.server-addr}
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
namespace: ${myyshop.sentinel.nacos.namespace}
eager: true #控制台热加载,false为懒加载(第一次调用接口才会加载)
网关需要加入配置(主要是异常相关格式化,还有代码限流、降级等)
@Configuration
public class SentinelGatewayConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public SentinelGatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
// @Bean
// @Order(Ordered.HIGHEST_PRECEDENCE)
// public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// // Register the block exception handler for Spring Cloud Gateway.
// return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
// }
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new JsonSentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
// @Bean
// @Order(-1)
// public GlobalFilter sentinelGatewayFilter() {
// return new SentinelGatewayFilter();
// }
/*****************************************************************************/
//以下是添加 API 分组和route 维度
// @PostConstruct
// public void doInit() {
// initCustomizedApis();
// initGatewayRules();
// }
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("some_customized_api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/Hansen666666"));
// add(new ApiPathPredicateItem().setPattern("/gprovider/**")
// .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
/**
* 配置限流规则
*/
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("some_customized_api")
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(2)
.setIntervalSec(1)
);
// rules.add(new GatewayFlowRule("csdn")
// .setCount(1)
// .setIntervalSec(1)
// );
//
// rules.add(new GatewayFlowRule("gateway-provider")
// .setCount(3) // 限流阈值
// .setIntervalSec(1) // 统计时间窗口,单位是秒,默认是 1 秒
// );
GatewayRuleManager.loadRules(rules);
}
}
添加自定义异常处理(不加会返回默认的错误信息Blocked by Sentinel: XXXX),下面为模仿源码写的自定义异常处理。
1.继承SentinelGatewayBlockExceptionHandler类(主要为了重写handle方法)
2.参照DefaultBlockRequestHandler类源码handleRequest方法和acceptsHtml方法(这个是SpringBoot默认返回的404异常页面,也就是说在网页上会有404异常,在Postman会显示Json异常)
public class JsonSentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {
public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
super(viewResolvers, serverCodecConfigurer);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
} else {
return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> {
if(ex instanceof ParamFlowException){
return WebfluxResponseUtil.responseFailed(exchange, 10000, HttpStatus.TOO_MANY_REQUESTS.value(),
"API interface limited flow by gateway.");
}
if(ex instanceof DegradeException){
return WebfluxResponseUtil.responseFailed(exchange, 10001, HttpStatus.SERVICE_UNAVAILABLE.value(),
"API interface degraded by gateway.");
}
return WebfluxResponseUtil.responseFailed(exchange, 10000, HttpStatus.TOO_MANY_REQUESTS.value(),
"API interface limited flow by gateway.");
});
}
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
}
}
Sentinel控制台
控制台文档(官方)
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
目前集成控制台有两种方式:
各自问题参照官方FAQ
https://github.com/alibaba/Sentinel/wiki/FAQ
Sentinel的JVM -D启动参数配置项,包含log文件指定路径(官方)
https://github.com/alibaba/Sentinel/wiki/%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9
控制台VM启动参数
下载jar或重新编译源码获取jar后,然后添加启动参数启动控制台,idea VM options启动参数如下:
-Dserver.port=8081
-Dcsp.sentinel.api.port=8723
-Dcsp.sentinel.dashboard.server=localhost:8081
-Dproject.name=sentinel-lbj
-Dserver.servlet.session.timeout=864000
-Dnacos.serverAddr=localhost:8849
-Dnacos.namespace=d4178075-92ee-429a-baad-6cd01d59b9b8
上面配置解释:
- -Dserver.port 为控制台启动端口号(不配置默认8080)
- -Dcsp.sentinel.api.port Sentinel 客户端监控微服务 API 的端口,默认8719
- -Dcsp.sentinel.dashboard.server 默认控制台提供的监控(就是sentinel-dashboard的地址),此配置必须配置,如不配置,则没有sentinel-dashboard默认控制台
- -Dproject.name 默认控制台名称,默认sentinel-dashboard
- -Dserver.servlet.session.timeout 控制台登录过期时间,可以指定分钟,默认30分钟,如 7200 表示 7200 秒,60m 表示 60 分钟
- -Dnacos.serverAddr 官方没有此配置,自己加的自定义配置,指定Nacos配置中心地址
- -Dnacos.namespace 官方没有此配置,自己加的自定义配置,指定Nacos持久化命名空间,例如本项目命名空间是sentinel(d4178075-92ee-429a-baad-6cd01d59b9b8)
linux 或 windows 下启动
下载官方jar或拿到源码编译后得到jar,直接执行下面代码:
nohup
java -Dserver.port=8081
-Dcsp.sentinel.dashboard.server=localhost:8081
-Dnacos.namespace=d4178075-92ee-429a-baad-6cd01d59b9b8
-Dnacos.serverAddr=localhost:8849
-Dsentinel.dashboard.auth.username=myyshop
-Dsentinel.dashboard.auth.password=myyshop
-jar
sentinel-dashboard.jar &
上述是Linux后台运行方式,加入 nohup **** & 就会后台运行,否则关闭服务就断了。Windows类似,不需要加 nohup **** &
Sentinel控制台部分源码(sentinel-dashboard)
以Nacos限流配置为例,FlowRuleNacosPublisher 发布配置到Nacos,发布的配置是JSON格式,但是JSON没有格式化,不美观,以下推送到Nacos实现美化JSON功能,这样容易改Nacos配置。
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<FlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
//lbj增加格式化、美化json内容 - start
String content = converter.convert(rules);
JSONArray jsonArray = JSONArray.parseArray(content);
String prettyContent = JSON.toJSONString(jsonArray, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteDateUseDateFormat);
//lbj增加格式化、美化json内容 - end
configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, prettyContent);
}
}
自己加入Nacos的 -Dnacos.serverAddr 和 -Dnacos.namespace 相关参数,这样可以直接在JVM -D启动参数动态加,而不用改源码,再编译,这样很麻烦:
@Bean
public ConfigService nacosConfigService() throws Exception {
String namespace = System.getProperty("nacos.namespace");
String serverAddr = Optional.ofNullable(System.getProperty("nacos.serverAddr")).orElse("localhost:8848");
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
if(StringUtil.isNotBlank(namespace)){
properties.setProperty(PropertyKeyConst.NAMESPACE, namespace);
}
return ConfigFactory.createConfigService(properties);
}
上述配置在 NacosConfig 类中,通过System.getProperty获取启动参数,
获取 namespace 和 serverAddr。
踩坑记录
如果你的微服务部署在docker中,并且没有指定host模式(–net=host),默认docker会走bridge模式,那这样docker镜像内部会分配自定义虚拟ip,这样跟主机互ping没有问题,但在一个局域网其他网段ip要想ping通docker内部虚拟ip就不行了。
而现在国内大部分公司都是使用docker去部署服务,Sentinel默认拿到ip是docker内部的虚拟ip,如果Sentinel部署在另外一台机器上(生产都要分开部署),则拿不到当前服务的簇点链路,因为Sentinel访问不到当前服务的端口数据(假如当前服务ip+端口=172.17.0.3:8719)。
注:172.17.0.3是docker内部虚拟ip,192.168.128.20是主机ip,8719是Sentinel客户端监控微服务 API 的端口,默认8719
host模式:使用 --net=host 指定。
none模式:使用 --net=none 指定。
bridge模式:使用 --net=bridge 指定,默认设置。
container模式:使用 --net=container:NAME_or_ID 指定。
因此有两种方案可以解决此情况:
- 将docker默认模式改成host模式(–net=host)
- 将Sentinel要监控的API端口(默认8719)从docker中绑定到宿主机上,可以使用 -p 参数显式将一个或者一组端口从容器里绑定到宿主机上(ip:hostPort:containerPort)
第一套方案不用说了,如果选定第二套方案,需要每个微服务都配置一个端口暴露给Sentinel,如果10个微服务,就暴露10个,不能重复,需要如下配置(这里以uaa为例):
spring:
cloud:
sentinel:
transport:
client-ip: 192.168.128.20 #如果是docker容器,需要指定宿主机ip,这样sentinel就不会拉docker内虚拟ip
port: 8777 #指定Sentinel客户端监控微服务API的端口,
上述ip+端口配置好后(以uaa为例),通过docker run启动uaa服务(这里uaa暴露给sentinel的端口是8777,其他服务端口尽量不能重复),配置如下:
docker run -p 7001:7001 -p 8777:8777 --name ${app_name} \
--link registry2:registry2 \
-v /usr/local/server-log/uaa-server:/logs \
-d ${app_name}:latest
注:8777是Sentinel客户端监控 uaa的端口,不指定默认8719
更多推荐
所有评论(0)