美文网首页
sentinel限流二开(1)—伪造服务存活状态,dashboa

sentinel限流二开(1)—伪造服务存活状态,dashboa

作者: 小胖学编程 | 来源:发表于2021-08-19 12:20 被阅读0次

    对sentinel的二开,本着少改动源码的规则,实现规则数据的持久化。

    1. 系列文章

    【consul入门篇-1】JAVA如何使用consul作为KV存储中心
    sentinel开源限流方案—企业级二次开发方案

    2. 难点分析

    client端会向dashboard发送心跳。dashboard会在内存中维护上一次心跳时间来达到判断机器存活的目的。

    sentinel设计图

    设计思路:client发送心跳,心跳包含版本号、ip信息、服务名等,dashboard进行校验。当发现client版本号过低时,dashboard根据版本号中的ip信息,推送最新的配置。

    在该设计思路中:我们可以看出,不需要维护机器列表的存活状态,达到一个被动式的配置同步。

    但是:在目前sentinel(版本1.8.1)设计中,控制台是否显示服务名称,就是通过后端是计算出deadshown字段(不是直接赋值),前端根据这两个字段显示下拉列表。

    服务列表.png

    3. 设计思路

    1. dashboard集群化后,依旧在内存中维护心跳信息,其中包含项目名。
    2. 回显列表时,去读取consul中的规则信息appRules/项目名/规则类型,解析出规则发送过持久化的项目名
    3. 当请求经nginx负载到dashboard的某一台机器上时,dashboard取出内存维护的项目名,然后获取到consul中维护的项目名,两个set去并集。
    4. 并集中的项目名伪造存活状态,使得页面上可以正常回显。

    4. 代码实现

    为了最大程度上不修改sentinel的源码,采用继承的方式,子类去重写父类的回显方法,完成存活状态的伪造。

    @Service
    public class SimpleMachineDiscoveryDecorator extends SimpleMachineDiscovery {
    
        private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class);
    
        private ConsulClient consulClient;
    
        public SimpleMachineDiscoveryDecorator(ConsulClient consulClient) {
            this.consulClient = consulClient;
        }
    
        @Override
        public Set<AppInfo> getBriefApps() {
            Set<String> consulSet = getAppNameFromConsul();
            //原始请求
            Set<AppInfo> apps = super.getBriefApps();
            Set<String> memSet = apps.stream().map(AppInfo::getApp).collect(Collectors.toSet());
            //集合合并
            consulSet.addAll(memSet);
            //伪造请求
            return consulSet.stream().map(this::forgeAppInfo).collect(Collectors.toSet());
        }
    
        @Override
        public AppInfo getDetailApp(String app) {
            AppInfo appInfo = super.getDetailApp(app);
            //伪造存活
            if(appInfo==null){
                appInfo = forgeAppInfo(app);
            }
            return appInfo;
        }
    
        /**
         * 在consul中获取应用名
         */
        private Set<String> getAppNameFromConsul() {
            Response<List<String>> appRules = consulClient.getKVKeysOnly("appRules");
            List<String> results = appRules.getValue();
            //规则的截取-appRules/项目名/规则名
            Set<String> consulSet = new HashSet<>();
            if (results != null) {
                for (String result : results) {
                    try {
                        String[] arr = result.split("/");
                        consulSet.add(arr[1]);
                    } catch (Exception e) {
                        logger.error("", e);
                    }
                }
            }
            return consulSet;
        }
    
    
        /**
         * 伪造appInfo的请求
         */
        private AppInfo forgeAppInfo(String appName) {
            AppInfo appInfo = new AppInfo();
            appInfo.setApp(appName);
            appInfo.setAppType(0);
    
            MachineInfo machineInfo = new MachineInfo();
            machineInfo.setApp(appName);
            machineInfo.setAppType(0);
            machineInfo.setHeartbeatVersion(System.currentTimeMillis());
            machineInfo.setLastHeartbeat(System.currentTimeMillis() - 1);
            machineInfo.setIp("127.0.0.1");
            machineInfo.setHostname("localhost");
            machineInfo.setVersion("1.8.1");
            machineInfo.setPort(8011);
            appInfo.setMachines(Collections.singleton(machineInfo));
            return appInfo;
        }
    }
    

    上面代码解决了分布式环境下dashboard如何处理心跳问题。依旧如何在对sentinel改动量下的情况下,还原dashboard前后端交互。

    相关文章

      网友评论

          本文标题:sentinel限流二开(1)—伪造服务存活状态,dashboa

          本文链接:https://www.haomeiwen.com/subject/okqnbltx.html