Sentinel 系列教程,现已上传到 github 和 gitee 中:

  • GitHub:

    https://github.com/all4you/sentinel-tutorial

  • Gitee:

    https://gitee.com/all_4_you/sentinel-tutorial

Sentinel 能够被大家所认可,除了他自身的轻量级,高性能,可扩展之外,跟控制台的好用和易用也有着莫大的关系,因为通过控制台极大的方便了我们日常的运维工作。

我们可以在控制台上操作各种限流、降级、系统保护的规则,也可以查看每个资源的实时数据,还能管理集群环境下的服务端与客户端机器。

但是控制台只是一个独立的 spring boot 应用,他本身是没有任何数据的,他的数据都是从其他的 sentinel 实例中获取的,那他是如何获取到这些数据的呢?带着这个疑问我们从源码中寻找答案。

最简单的方法莫过于启动一个控制台的实例,然后从页面上查看每个接口请求的url,然后再到 dashboard 的代码中去深挖下去。

怎么启动控制台,这里就不再详细描述了,大家可以看 Sentinel实战:使用控制台管理规则 这篇文章去了解下,简单的几步就可以启动一个控制台了。

我们就以一个简单的查看【流控规则】为例来描述,点击【流控规则】进入页面后,按F11打开network就可以看到请求的url了,如下图所示:

可以看到,请求的 url 是 /v1/flow/rules 我们直接在源码中全局搜索 /rules ,为什么不搜索 /v1/flow/rules 呢,因为有可能 url 被拆分成两部分,我们直接搜完整的 url 可能搜不到结果。如下图所示:

我们要找的应该就是 FlowControllerV1 这个类了,打开这个类看下类上修饰的值是不是 /v1/flow 如下图所示:

从图中可以看出来,dashboard 是通过一个叫 SentinelApiClient 的类去指定的 ip 和 port 处获取数据的。这个 ip 和 port 是前端页面直接提交给后端的,而前端页面又是通过 /app/{app}/machines.json 接口获取机器列表的。

连接 dashboard

这里的机器列表中展示的就是所有连接到 dashboard 上的 sentinel 的实例,包括普通限流的 sentinel-core 和集群模式下的 token-server 和 token-client。我们可以回想一下,一个 sentinel-core 的实例要接入 dashboard 的几个步骤:

  1. 引入 dashboard 的依赖

  2. 配置 dashboard 的 ip 和 port

  3. 初始化 sentinel-core,连接 dashboard

sentinel-core 在初始化的时候,通过 JVM 参数中指定的 dashboard 的 ip 和 port,会主动向 dashboard 发起连接的请求,该请求是通过 HeartbeatSender 接口以心跳的方式发送的,并将自己的 ip 和 port 告知 dashboard。这里 sentinel-core 上报给 dashboard 的端口是 sentinel 对外暴露的自己的 CommandCenter 的端口。

HeartbeatSender 有两个实现类,一个是通过 http,另一个是通过 netty,我们看 http 的实现类:

SimpleHttpHeartbeatSender.java

private final HeartbeatMessage heartBeat = new HeartbeatMessage();

private final SimpleHttpClient httpClient = new SimpleHttpClient();

@Override

public boolean sendHeartbeat() throws Exception {

   if (TransportConfig.getRuntimePort() <= 0) {

       RecordLog.info("[SimpleHttpHeartbeatSender] Runtime port not initialized, won't send heartbeat");

       return false;

   }

   InetSocketAddress addr = getAvailableAddress();

   if (addr == null) {

       return false;

   }

   SimpleHttpRequest request = new SimpleHttpRequest(addr, HEARTBEAT_PATH);

   request.setParams(heartBeat.generateCurrentMessage());

   try {

       SimpleHttpResponse response = httpClient.post(request);

       if (response.getStatusCode() == OK_STATUS) {

           return true;

       }

   } catch (Exception e) {

       RecordLog.warn("[SimpleHttpHeartbeatSender] Failed to send heartbeat to " + addr + " : ", e);

   }

   return false;

}

通过一个 HttpClient 向 dashboard 发送了自己的信息,包括 ip port 和版本号等信息。

其中 consoleHost 和 consolePort 的值就是从 JVM 参数 csp.sentinel.dashboard.server 中获取的。

dashboard 在接收到 sentinel-core 的连接之后,就会与 sentinel-core 建立连接,并将 sentinel-core 上报的 ip 和 port 的信息包装成一个 MachineInfo 对象,然后通过 SimpleMachineDiscovery 将该对象保存在一个 map 中,如下图所示:

定时发送心跳

sentinel-core 连接上 dashboard 之后,并不是就结束了,事实上 sentinel-core 是通过一个 ScheduledExecutorService 的定时任务,每隔 10 秒钟向 dashboard 发送一次心跳信息。发送心跳的目的主要是告诉 dashboard 我这台 sentinel 的实例还活着,你可以继续向我请求数据。

这也就是为什么 dashboard 中每个 app 对应的机器列表要用 Set 来保存的原因,如果用 List 来保存的话就可能存在同一台机器保存了多次的情况。

心跳可以维持双方之间的连接是正常的,但是也有可能因为各种原因,某一方或者双方都离线了,那他们之间的连接就丢失了。

1.sentinel-core 宕机

如果是 sentinel-core 宕机了,那么这时 dashboard 中保存在内存里面的机器列表还是存在的。目前 dashboard 只是在接收到 sentinel-core 发送过来的心跳包的时候更新一次机器列表,当 sentinel-core 宕机了,不再发送心跳数据的时候,dashboard 是没有将 “失联” 的 sentinel-core 实例给去除的。而是页面上每次查询的时候,会去用当前时间减去机器上次心跳包的时间,如果时间差大于 5 分钟了,才会将该机器标记为 “失联”。

所以我们在页面上的机器列表中,需要至少等到 5 分钟之后,才会将具体失联的 sentinel-core 的机器标记为 “失联”。如下图所示:

2.dashboard 宕机

如果 dashboard 宕机了,sentinel-core 的定时任务实际上是会一直请求下去的,只要 dashboard 恢复后就会自动重新连接上 dashboard,双方之间的连接又会恢复正常了,如果 dashboard 一直不恢复,那么 sentinel-core 就会一直报错,在 sentinel-record.log 中我们会看到如下的报错信息:

不过实际生产中,不可能出现 dashboard 宕机了一直没人去恢复的情况的,如果真出现这种情况的话,那就要吃故障了。

请求数据

当 dashboard 有了具体的 sentinel-core 实例的 ip 和 port 之后,就可以去请求所需要的数据了。

让我们再回到最开始的地方,我在页面上查询某一台机器的限流的规则时,是将该机器的 ip 和 port 以及 appName 都传给了服务端,服务端通过这些信息去具体的远程实例中请求所需的数据,拿到数据后再封装成 dashboard 所需的格式返回给前端页面进行展示。

具体请求限流规则列表的代码在 SentinelApiClient 中,如下所示:

SentinelApiClient.java

public List<FlowRuleEntity> fetchFlowRuleOfMachine(String app, String ip, int port) {

   String url = "http://" + ip + ":" + port + "/" + GET_RULES_PATH + "?type=" + FLOW_RULE_TYPE;

   String body = httpGetContent(url);

   logger.info("FlowRule Body:{}", body);

   List<FlowRule> rules = RuleUtils.parseFlowRule(body);

   if (rules != null) {

       return rules.stream().map(rule -> FlowRuleEntity.fromFlowRule(app, ip, port, rule))

           .collect(Collectors.toList());

   } else {

       return null;

   }

}

可以看到也是通过一个 httpClient 请求的数据,然后再对结果进行转换,具体请求的过程是在 httpGetContent 方法中进行的,我们看下该方法,如下所示:

private String httpGetContent(String url) {

   final HttpGet httpGet = new HttpGet(url);

   final CountDownLatch latch = new CountDownLatch(1);

   final AtomicReference<String> reference = new AtomicReference<>();

   httpClient.execute(httpGet, new FutureCallback<HttpResponse>() {

       @Override

       public void completed(final HttpResponse response) {

           try {

               reference.set(getBody(response));

           } catch (Exception e) {

               logger.info("httpGetContent " + url + " error:", e);

           } finally {

               latch.countDown();

           }

       }

       @Override

       public void failed(final Exception ex) {

           latch.countDown();

           logger.info("httpGetContent " + url + " failed:", ex);

       }

       @Override

       public void cancelled() {

           latch.countDown();

       }

   });

   try {

       latch.await(5, TimeUnit.SECONDS);

   } catch (Exception e) {

       logger.info("wait http client error:", e);

   }

   return reference.get();

}

从代码中可以看到,是通过一个异步的 httpClient 再结合 CountDownLatch 等待 5 秒的超时时间去获取结果的。

获取数据的请求从 dashboard 中发出去了,那 sentinel-core 中是怎么进行相应处理的呢?看过我其他文章的同学肯定还记得, sentinel-core 在启动的时候,执行了一个 InitExecutor.init 的方法,该方法会触发所有 InitFunc 实现类的 init 方法,其中就包括两个最重要的实现类:

  • HeartbeatSenderInitFunc

  • CommandCenterInitFunc

HeartbeatSenderInitFunc 会启动一个 HeartbeatSender 来定时的向 dashboard 发送自己的心跳包,而 CommandCenterInitFunc 则会启动一个 CommandCenter 对外提供 sentinel-core 的数据服务,而这些数据服务是通过一个一个的 CommandHandler 来提供的,如下图所示:

总结

现在我们已经知道了 dashboard 是如何获取到实时数据的了,具体的流程如下所示:

1.首先 sentinel-core 向 dashboard 发送心跳包

2.dashboard 将 sentinel-core 的机器信息保存在内存中

3.dashboard 根据 sentinel-core 的机器信息通过 httpClient 获取实时的数据

4.sentinel-core 接收到请求之后,会找到具体的 CommandHandler 来处理

5.sentinel-core 将处理好的结果返回给 dashboard

思考

1.数据安全性

sentinel-dashboard 和 sentinel-core 之间的通讯是基于 http 的,没有进行加密或鉴权,可能会存在数据安全性的问题,不过这些数据并非是很机密的数据,对安全性要求并不是很高,另外增加了鉴权或加密之后,对于性能和实效性有一定的影响。

2.SentinelApiClient

目前所有的数据请求都是通过 SentinelApiClient 类去完成的,该类中充斥着大量的方法,都是发送 http 请求的。代码的可读性和可维护性不高,所以需要对该类进行重构,目前我能够想到的有两种方法:

1)通过将 sentinel-core 注册为 rpc 服务,dashboard 就像调用本地方法一样去调用 sentinel-core 中的方法,不过这样的话需要引入服务注册和发现的依赖了。

2)通过 netty 实现私有的协议,sentinel-core 通过 netty 启动一个 CommandCenter 来对外提供服务。dashboard 通过发送 Packet 来进行数据请求,sentinel-core 来处理 Packet。不过这种方法跟目前的做法没有太大的区别,唯一比较好的可能就是不需要为每种请求都写一个方法,只需要定义好具体的 Packet 就好了。

更多原创好文

请关注「逅弈逐码」

sentinel 端口_Sentinel原理:控制台是如何获取到实时数据的相关推荐

  1. sentinel 端口_Sentinel 实战控制台篇

    上篇文章我通过一个简单的例子和大家分享了怎么接入 sentinel 但是规则的配置是通过硬编码来实现的,这种方式比较原始,不能动态修改,本篇文章我将通过接入 sentinel 控制台来解决这个问题. ...

  2. 股票实时数据 python_Tushare 获取股票实时数据

    Tushare 获取股票实时数据 自己实现了一个能获取股票实时交易数据的脚本,功能是每3秒钟获取当前大盘涨跌,和自己添加股票的价格和涨跌幅 原理是通过获取Tushare 平台提供的api,来获取股票数 ...

  3. Python利用PyQt5制作一个获取网络实时数据NBA数据播报GUI

    现在NBA联赛也进行到半决赛了,我们怎么样才能以更快的方法获取NBA的数据呢?这里我们就自己来做一个数据播报的程序 文章目录 制作NBA数据爬虫 捋顺思路 编写代码 NBAReporter.py NB ...

  4. python 股票实时数据接口_获取股票实时数据的接口

    记录下获取股票实时数据的接口,记录下. 以基金兴和500018为例 ****************************** 新浪的接口: http://hq.sinajs.cn/list=sh5 ...

  5. 【股票】java+js获取股票实时数据

    [历史数据] 方法1:首先感谢网易财经提供数据下载平台,访问网易财经首页 money.163.com,点击股票,进入到股票页面,然后随便点开网页中的某支股票,比如说万科A, 你就看到了万科A股票的相关 ...

  6. 免费获取股票历史交易数据方法与代码获取股票实时数据方法集合

    现在网上有越来越多开源的股票数据的获取方法,言简意赅,小编在这里提供2种方法去获取股票数据,第一种呢还是针对于所有的用户,通过使用第三方平台提供的方法来获取到所需要的股票数据. 方法一:使用免费的网站 ...

  7. Python获取股票实时数据

    近期爬虫入门,简单搞了个小脚本经baidu查询指定股票代码的实时行情数据(好多网站禁了,所有走的baidu,原因就不细说了~~). 前期操作呢?当然是按部就班的一些列抓包,浏览器上F12就行了,找到对 ...

  8. 众志成城抗疫情:Python获取疫情实时数据!!

    ​前文 防护篇: 各自家庭聚团圆,不要外出相互窜. 注意洗手衣勤换,戴上口罩防感染. 野生动物传染源,千万不要因嘴馋. 每天食用调配餐,清热食物桌上端. 防寒添衣要保暖,通风透气舒适感. 清洁卫生干一 ...

  9. 新浪获取股票实时数据接口(22年春节后)

    2022年春节前夕 新浪获取股票实时行情接口,获取数据进行调整. 请求:http://hq.sinajs.cn/list 调用返回:Kinsoku jikou desu! 以下为最新获取方法(Java ...

最新文章

  1. Linux命令详解----iostat
  2. window下Java的环境变量的配置
  3. 多个服务器数据互通_3月21日部分服务器数据互通公告!
  4. 从ffmpeg源代码分析如何解决ffmpeg编码的延迟问题(如何解决编码 0 延时)
  5. 阮一峰react demo代码研究的学习笔记 - demo 6 debug - how check works
  6. watson软件使用_使用Watson Assistant进行多语言管理
  7. mysql dump工具升级_MySQL数据库升级
  8. BCD与ASCII码互转-C语言实现
  9. 开源WEB服务器-lighttpd 1.4.24发布
  10. 安卓怎么把一个按钮设计成梯形_常闭触点输入信号处理的电路图及PLC梯形图
  11. Windows 7 语言包
  12. Matlab软件包及安装
  13. 《数据结构教程》(第5版)学习笔记(一)
  14. 生成领料单(编号:20110704A1153)
  15. VMware虚拟机备份和恢复
  16. 大恒相机开发(大恒SDK+opencv开发)笔记1
  17. 辽宁2010省赛NEW RDSP MODE I (思维,推导公式)
  18. 14寸笔记本 2k linux,HUAWEI 华为 MateBook 14 Linux版 14英寸笔记本电脑(i7-8565U、8G、512G、MX250、2K、100%sRGB)...
  19. 自由浏览器 android,百度浏览器发布安卓6.1版 趣味视频弹幕吐槽不停
  20. Windows系统盘清理

热门文章

  1. Vue 开发中常见报错与处理
  2. python合并多个excel的某些字段_python合并多个excel文件的示例
  3. mysql range用法_MySQL中Explain的用法总结(详细)
  4. qt使用动画提示正在载中
  5. 简记模态对话框和非模态对话框
  6. oracle adg switch over,Oracle11gr2_ADG管理之switchover补充
  7. fullcalendar php,日历插件fullcalendar+php的使用教程 — 读取json数据
  8. java调用c jni_Java调用C JNI
  9. python输出所有组合数_python – GridSearchCV是否存储了所有参数组合的所有分数?...
  10. php 504网关,504 gateway timeout什么意思