zoukankan      html  css  js  c++  java
  • Alibaba Sentinel对接Spring Cloud Gateway关于不显示API管理及请求链路的坑附带解决方案

    调试Sentinel对接Scg网关的时候,出现了一个比较坑的现象,就是网关菜单,不显示请求链路和API管理的菜单项,这个问题主要是由于,Sentinel的dashboard前端sidebar.js的 代码逻辑中,       /registry/machine查询返回的数据,返回的appType = 0

    AppService.getApps().success(
    function (data) {
    if (data.code === 0) {
    let path = $location.path().split('/');
    let initHashApp = path[path.length - 1];
    $scope.apps = data.data;
    $scope.apps = $scope.apps.map(function (item) {
    if (item.app === initHashApp) {
    item.active = true;
    }
    let healthyCount = 0;
    for (let i in item.machines) {
    if (item.machines[i].healthy) {
    healthyCount++;
    }
    }
    item.healthyCount = healthyCount;
    // 对应后端接口 /registry/machine查询数据,返回的appType = 0
    item.isGateway = item.appType === 1 || item.appType === 11 || item.appType === 12;

    if (item.shown) {
    return item;
    }
    });
    }
    }
    );
    通过后端MachineRegistryController的receiveHeartBeat方法返回的数据 item的appType为0,这就使得菜单一直显示普通的服务类型的菜单,而不显示网关类型的菜单。

    receiveHeartBeat方法实际是由连接dashboard的各个客户端发送心跳数据,传入的参数中含有appType, 而透过客户端的代码可以看到以,使用http方式传输为例,可以看一下客户端SimpleHttpHeartbeatSender的源码,这里的sendHeartbeat方法,就是对应dashboard的receiveHeartBeat来进行信息交互的,通过调试可以看出发送的心跳数据HeartbeatMessage中,appType就为0而不是为1,HeartbeatMessage类中app_type的值是来源于SentinelConfig.getAppType() 

    public HeartbeatMessage() {
    message.put("hostname", HostNameUtil.getHostName());
    message.put("ip", TransportConfig.getHeartbeatClientIp());
    message.put("app", AppNameUtil.getAppName());
    // Put application type (since 1.6.0).
    message.put("app_type", String.valueOf(SentinelConfig.getAppType()));
    message.put("port", String.valueOf(TransportConfig.getPort()));
    }
    而SentinelConfig中 appType的默认值APP_TYPE_COMMON = 0,由于SentinelSCGAutoConfiguration自动配置的时候,init初始化方法未能在发送心跳前将appType的值进行变更,所以导致都是按默认值0来传递数据的,也就是说,SimpleHttpHeartbeatSender中的HeartbeatMessage在初始化的时候SentinelSCGAutoConfiguration里的initAppType方法还未未执行,SentinelSCGAutoConfiguration是在SimpleHttpHeartbeatSender读取csp.sentinel.app.type之后执行的,所以SentinelSCGAutoConfiguration这里的自动配置csp.sentinel.app.type是无效的,这就使得dashboard一直按普通服务展示菜单。所以只能通过,SentinelConfigLoader 会从System.getProperty加载变量信息,并最终由SentinelConfig的loadProps方法加载到props的内存Map中,解决办法是可以在服务的启动命令中加上 -Dcsp.sentinel.app.type=1 或者 在服务的Application的main方法里加入System.setProperty("csp.sentinel.app.type", "1"); 这样就可以使得机器的appType变为1

    @SpringBootApplication
    @EnableDiscoveryClient
    public class Application {
    public static void main(String[] args) {
    System.setProperty("csp.sentinel.app.type", "1");
    SpringApplication.run(Application.class, args);
    }
    }
    这样调整之后只是改变了一半的问题,你会发现即便改变完成,dashboard刷新后,菜单仍然不会刷新变为网关类型,这是什么原因呢,调试代码发现,虽然客户端心跳发送的machineInfo已经变更appType,但是dashboard查询数据AppInfo里中的apptype依旧为0,

    public class AppInfo {

    private String app = "";

    private Integer appType = 0;

    private Set<MachineInfo> machines = ConcurrentHashMap.newKeySet(); 这里的appType已经变为1了

    public AppInfo() {}
    这又是什么原因呢?经过调试,最后发现,问题就出现在了,SimpleMachineDiscovery里的addMachine方法上了

    @Component
    public class SimpleMachineDiscovery implements MachineDiscovery {

    private final ConcurrentMap<String, AppInfo> apps = new ConcurrentHashMap<>();

    @Override
    public long addMachine(MachineInfo machineInfo) {
    AssertUtil.notNull(machineInfo, "machineInfo cannot be null");
    AppInfo appInfo = apps.computeIfAbsent(machineInfo.getApp(), o -> new AppInfo(machineInfo.getApp(), machineInfo.getAppType()));
    // 只有当apps里对象不存在的时候,才会放一个新的进去,才会发生变化
    appInfo.addMachine(machineInfo);
    return 1;
    }
    这是因为,apps里存储了所有服务的服务信息,开始提到的,item.isGateway = item.appType === 1 || item.appType === 11 || item.appType 这个item对象实际对应的是appInfo对象,而appInfo对象里的appType值,是在第一次apps里对象不存在的时候,才会放一个新的进去,才会发生变化。所以当你不重启dashboard的时候,apps里的服务列表中单个对象中的appType是不会变化的,即便是你网关服务已经变更appTpye=1并发送心跳过来。所以直到你重启dashboard ,apps重新装载数据的时候,apps里的服务列表中单个对象中的appType才会重新取到客户端修改后的值并存进去。

    AppInfo appInfo = apps.computeIfAbsent(machineInfo.getApp(), o -> new AppInfo(machineInfo.getApp(), machineInfo.getAppType()));

    machineInfo.getAppType()变为1了
    apps的中AppInfo的appType才会被machineInfo.getAppType值覆盖掉
    这个时候页面中的菜单才会变为
    ————————————————
    版权声明:本文为CSDN博主「幕紫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/ankeway/article/details/107262986

  • 相关阅读:
    JavaScript 核心学习——继承
    吴裕雄--天生自然 PHP开发学习:PhpStorm的配置与安装
    吴裕雄--天生自然 HADOOP大数据分布式处理:安装WinSCP
    吴裕雄--天生自然 HADOOP大数据分布式处理:安装XShell
    云栖专辑 | 阿里开发者们的第14个感悟:技术拓宽价值边界
    玩转大数据系列之四:搜索服务
    RocketMQ源码分析之RocketMQ事务消息实现原下篇(事务提交或回滚)
    RocketMQ源码分析之RocketMQ事务消息实现原理中篇----事务消息状态回查
    RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)
    RocketMQ源码分析之从官方示例窥探:RocketMQ事务消息实现基本思想
  • 原文地址:https://www.cnblogs.com/mscm/p/13340939.html
Copyright © 2011-2022 走看看