IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 十分钟,读懂心跳机制【手撕eureka源码NO.3】 -> 正文阅读

[大数据]十分钟,读懂心跳机制【手撕eureka源码NO.3】

本篇我们讲解eureka的心跳机制,来看看eureka的源码是通过怎样的设计来实现对服务的心跳检测的。

正式开始之前,先来思考一下eureka设计心跳机制是为了解决什么问题?

其实最主要的目的,就是通过心跳来达到对各个服务健康状态的监测。

也就是为了检测出宕机的服务,那些宕机的服务肯定是不能正常访问的,所以需要筛选出这些服务,并将这些不能正常提供访问支持的服务,从注册表中移除掉。

换句话讲,这些异常的服务都被下线啦。

所以本篇,我们从eureka的服务下线开始讲起。

服务怎么主动下线?

当我们重启服务,或者需要将某个服务关闭时,就需要将自己的服务下线,也就是告诉eureka-server:我要下线了,你记得把我的地址信息从注册表中删除!!

在关闭服务时,我们需要调用eureka-client提供DiscoveryClient.java中的shutdown()方法。

调用shutdown()方法后,eureka-client会向eureka-server发送一个服务下线的http请求,eureka-server就会将发送请求的服务实例从注册表中移除。

eureka-client端代码比较简单,直接贴出源码看一下即可:

public synchronized void shutdown() {
    //关闭定时任务
    cancelScheduledTasks();
    //通知eureka-server下线
    unregister();
    //其他..略..
}

void unregister() {
    //发送http请求
    EurekaHttpResponse<Void> httpResponse =
        eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId()); 
}

主要的业务逻辑在eureka-server端,通过前面两篇文章,其实我们已经知道eureka-server大概要做哪些工作了,比如:从注册表中删除下线的服务将缓存数据过期把变动的服务实例信息加入到Queue

还是先上一张代码简图,查看一下源码的调用流程:

23-server-主动下线-代码简图

其中最主要的方法是internalCancel(..),贴出主要部分来看一看:

public abstract class AbstractInstanceRegistry implements InstanceRegistry {
    //注册表:记录所有服务的ip和端口号等信息
    private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
        = new ConcurrentHashMap<>();
    //记录最近状态发生变化的服务实例
    private ConcurrentLinkedQueue<RecentlyChangedItem> recentlyChangedQueue 
        = new ConcurrentLinkedQueue<>();
    
    //服务下线主要方法
    protected boolean internalCancel(String appName, String id, boolean isReplication) {
        //根据服务名,获取对应的服务实例
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
            Lease<InstanceInfo> leaseToCancel = null;
            if (gMap != null) {
                //从注册表中删除下线的那一个服务实例
                leaseToCancel = gMap.remove(id);
            }
        //记录下线时间
        leaseToCancel.cancel();
        //ActionType,客户端合并数据时会用到
        instanceInfo.setActionType(ActionType.DELETED);
        //向最近发生变化的队列添加数据
        recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
        //清空缓存
        invalidateCache(appName, vip, svip);
    }
}

再次提醒: 文章中贴出来的代码,是经过提炼的,一些繁琐的if-else判断、log打印,或者是干扰理解的部分,文章中都没有贴进来。

主要是为了方便大家理解,也是为了增加文章的可读性。

AbstractInstanceRegistry.java前文我们已经多次用到过,这里就不再过多介绍。

recentlyChangedQueueConcurrentHashMap<> registry同样多次重复过,分别是存储最近变化的服务实例数据、注册表。

ActionType.DELETED在上一章客户端获取增量注册表后,本地有一个合并数据的过程,合并时根据ActionType的不同进行不同的操作,简单了解一下即可。

invalidateCache()在上一章讲解多级缓存机制时,同样也贴过源码和详细说明,这里就不再赘述了。

基本上服务主动下线的源码,只要认真学习过上两章的内容,这一小节就很容易理解了。

一张图,总结一下服务下线、缓存更新、eureka-client端感知到服务下线的过程:

心跳机制是怎么实现的?

首先,我们用一张图,来展示一下eureka心跳机制。

25-心跳机制-我还活着

从图中我们可以看出,eureka-client每隔30s就会向服务端大喊一声:我还活着。

如果转换为编程语言的话,这个过程是怎样实现的呢?想一想。

其实很简单,每隔30s,自然是用定时任务来实现。大喊一声,则是调用eureka-server端的接口,我们来看看eureka-client的代码实现。

定时任务的定义在DiscoveryClient.java中,不知道大家有没有注意到DiscoveryClientclent.java是一个非常重要的类,我们在学习源码的过程中,经常会读到这里面的代码。

先看一下方法调用简图:

代码片段:

public class DiscoveryClient implements EurekaClient {
    private void initScheduledTasks() {
        scheduler.schedule(
            new TimedSupervisorTask(
                "heartbeat",
                scheduler,
                heartbeatExecutor,
                renewalIntervalInSecs,
                TimeUnit.SECONDS,
                expBackOffBound,
                //定时任务执行的内容
                new HeartbeatThread()
            ),
            //定时间隔 30s
            renewalIntervalInSecs, TimeUnit.SECONDS);
	}

    //内部类(线程)
    private class HeartbeatThread implements Runnable {
        public void run() {
            //renew() 发送http请求
            if (renew()) {
                lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
            }
        }
    }
}

eureka-client部分的代码比较简单,我们看到此处即可。

接下来看看eureka-server的处理。

先看一下方法调用的简图:

其中最主要的方法是Lease.java中的renew(),贴出源码看一下:

public class Lease<T> {
    private volatile long lastUpdateTimestamp;
    public void renew() {
        //更新时间戳
        lastUpdateTimestamp = System.currentTimeMillis() + duration;
    }
}

没错,其实eureka-server只是更新了一下发送心跳信息的服务的最后更新时间lastUpdateTimestamp

至此,eureka的整个心跳机制就已经讲解完毕。

但是心跳机制只是方法,不是目的,设计心跳机制的目的是为了监测异常的服务,从而让eureka-server能够达到自动感知故障的目的。

下一篇,我们来看看eureka-server是怎么实现对服务的故障感知的。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:34:18  更:2022-03-08 22:38:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:30:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码