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值覆盖掉

这个时候页面中的菜单才会变为

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Spring Cloud Alibaba是一个基于Spring Cloud的一组开源框架和组件,旨在为微服务架构提供解决方案Sentinel GatewaySpring Cloud Alibaba中的一部分,是一个高性能的API网关,用于管理和保护微服务的访问权限。 2022年的Sentinel Gateway将在当前的功能基础上进行进一步的优化和增强。首先,它将提供更加灵活和强大的流量控制和熔断降级机制,以便更好地应对高并发和流量高峰情况。这将更好地保护后端微服务的稳定性和可靠性,确保系统的正常运行。 其次,Sentinel Gateway将提供更好的安全防护能力,通过集成常见的安全防护机制,如黑名单、白名单、IP过滤等,保护系统免受恶意攻击和非法访问。这将提升整个微服务架构的安全性,保护敏感数据和业务逻辑的安全性。 此外,Sentinel Gateway还将提供更加强大和灵活的路由配置功能,允许用户根据具体需求和策略进行动态路由转发。这将使得微服务架构在面对复杂的网络环境和多样化的服务调用场景时能够更加灵活和高效地进行消息传递和数据交换。 最后,Sentinel Gateway将进一步完善其监控和统计功能,提供更加全面和准确的系统运行状态和性能指标数据。这将帮助用户更好地理解和掌握系统的运行状况,及时发现和解决潜在的问题,提升整个微服务架构的可管理性和可维护性。 综上所述,2022年的Sentinel Gateway将在流量控制、熔断降级、安全防护、动态路由、监控统计等方面进行进一步的优化和增强,为微服务架构提供更加强大和可靠的API网关解决方案
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值