您当前的位置:首页 > 电脑百科 > 站长技术 > 服务器

2万字长文带你细细盘点五种负载均衡策略

时间:2020-06-02 10:57:00  来源:  作者:

Dubbo的五种负载均衡策略

2020 年 5 月 15 日,Dubbo 发布 2.7.7 release 版本。其中有这么一个 Features

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

新增一个负载均衡策略。

熟悉我的老读者肯定是知道的,Dubbo 的负载均衡我都写过专门的文章,对每个负载均衡算法进行了源码的解读,还分享了自己调试过程中的一些骚操作。

新的负载均衡出来了,那必须的得解读一波。

先看一下提交记录:

https://github.com/chickenlj/incubator-dubbo/commit/6d2ba7ec7b5a1cb7971143d4262d0a1bfc826d45

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

负载均衡是基于 SPI 实现的,我们看到对应的文件中多了一个名为 shortestresponse 的 key。

这个,就是新增的负载均衡策略了。看名字,你也知道了这个策略的名称就叫:最短响应。

所以截止 2.7.7 版本,官方提供了五种负载均衡算法了,他们分别是:

  1. ConsistentHashLoadBalance 一致性哈希负载均衡
  2. LeastActiveLoadBalance 最小活跃数负载均衡
  3. RandomLoadBalance 加权随机负载均衡
  4. RoundRobinLoadBalance 加权轮询负载均衡
  5. ShortestResponseLoadBalance 最短响应时间负载均衡

前面四种我已经在之前的文章中进行了详细的分析。有的读者反馈说想看合辑,所以我会在这篇文章中把之前文章也整合进来。

所以,需要特别强调一下的是,这篇文章集合了之前写的三篇负载均衡的文章。看完最短响应时间负载均衡这一部分后,如果你看过我之前的那三篇文章,你可以温故而知新,也可以直接拉到文末看看我推荐的一个活动,然后点个赞再走。如果你没有看过那三篇,这篇文章如果你细看,肯定有很多收获,以后谈起负载均衡的时候若数家珍,但是肯定需要看非常非常长的时间,做好心理准备。

我已经预感到了,这篇文章妥妥的会超过 2 万字。属于硬核劝退文章,想想就害怕。

最短响应时间负载均衡

首先,我们看一下这个类上的注解,先有个整体的认知。

org.Apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

我来翻译一下是什么意思:

  1. 从多个服务提供者中选择出调用成功的且响应时间最短的服务提供者,由于满足这样条件的服务提供者有可能有多个。所以当选择出多个服务提供者后要根据他们的权重做分析。
  2. 但是如果只选择出来了一个,直接用选出来这个。
  3. 如果真的有多个,看它们的权重是否一样,如果不一样,则走加权随机算法的逻辑。
  4. 如果它们的权重是一样的,则随机调用一个。

再配个图,就好理解了,可以先不管图片中的标号:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

有了上面的整体概念的铺垫了,接下来分析源码的时候就简单了。

源码一共就 66 行,我把它分为 5 个片段去一一分析。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这里一到五的标号,对应上面流程图中的标号。我们一个个的说。

标号为①的部分

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这一部分是定义并初始化一些参数,为接下来的代码服务的,翻译一下每个参数对应的注释:

length 参数:服务提供者的数量。

shortestResponse 参数:所有服务提供者的估计最短响应时间。(这个地方我觉得注释描述的不太准确,看后面的代码可以知道这只是一个零时变量,在循环中存储当前最短响应时间是多少。)

shortCount 参数:具有相同最短响应时间的服务提供者个数,初始化为 0。

shortestIndexes 参数:数组里面放的是具有相同最短响应时间的服务提供者的下标。

weights 参数:每一个服务提供者的权重。

totalWeight 参数:多个具有相同最短响应时间的服务提供者对应的预热(预热这个点还是挺重要的,在下面讲最小活跃数负载均衡的时候有详细说明)权重之和。

firstWeight 参数:第一个具有最短响应时间的服务提供者的权重。

sameWeight 参数:多个满足条件的提供者的权重是否一致。

标号为②的部分

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这一部分代码的关键,就在上面框起来的部分。而框起来的部分,最关键的地方,就在于第一行。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

获取调用成功的平均时间。

成功调用的平均时间怎么算的?

调用成功的请求数总数对应的总耗时 / 调用成功的请求数总数 = 成功调用的平均时间。

所以,在下面这个方法中,首先获取到了调用成功的请求数总数:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这个 succeeded 参数是怎么来的呢?

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

答案就是:总的请求数减去请求失败的数量,就是请求成功的总数!

那么为什么不能直接获取请求成功的总数呢?

别问,问就是没有这个选项啊。你看,在 RpcStatus 里面没有这个参数呀。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

请求成功的总数我们有了,接下来成功总耗时怎么拿到的呢?

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

答案就是:总的请求时间减去请求失败的总时间,就是请求成功的总耗时!

那么为什么不能直接获取请求成功的总耗时呢?

别问,问就是......

我们看一下 RpcStatus 中的这几个参数是在哪里维护的:

org.apache.dubbo.rpc.RpcStatus#endCount(org.apache.dubbo.rpc.RpcStatus, long, boolean)

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

其中的第二个入参是本次请求调用时长,第三个入参是本次调用是否成功。

具体的方法不必细说了吧,已经显而易见了。

再回去看框起来的那三行代码:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

  1. 第一行获取到了该服务提供者成功请求的平均耗时。
  2. 第二行获取的是该服务提供者的活跃数,也就是堆积的请求数。
  3. 第三行获取的就是如果当前这个请求发给这个服务提供者预计需要等待的时间。乘以 active 的原因是因为它需要排在堆积的请求的后面嘛。

这里,我们就获取到了如果选择当前循环中的服务提供者的预计等待时间是多长。

后面的代码怎么写?

当然是出来一个更短的就把这个踢出去呀,或者出来一个一样长时间的就记录一下,接着去 pk 权重了。

所以,接下来 shortestIndexes 参数和 weights 参数就排上用场了:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

另外,多说一句的,它里面有这样的一行注释:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

和 LeastActiveLoadBalance 负载均衡策略一致,我给你截图对比一下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到,确实是非常的相似,只是一个是判断谁的响应时间短,一个是判断谁的活跃数低。

标号为③的地方

标号为③的地方是这样的:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

里面参数的含义我们都知道了,所以,标号为③的地方的含义就很好解释了:经过选择后只有一个服务提供者满足条件。所以,直接使用这个服务提供者。

标号为④的地方

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这个地方我就不展开讲了(后面的加权随机负载均衡那一小节有详细说明),熟悉的朋友一眼就看出来这是加权随机负载均衡的写法了。

不信?我给你对比一下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

你看,是不是一模一样的。

标号为⑤的地方

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

一行代码,没啥说的。就是从多个满足条件的且权重一样的服务提供者中随机选择一个。

如果一定要多说一句的话,我截个图吧:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到,这行代码在最短响应时间、加权随机、最小活跃数负载均衡策略中都出现了,且都在最后一行。

好了,到这里最短响应时间负载均衡策略就讲完了,你再回过头去看那张流程图,会发现其实流程非常的清晰,完全可以根据代码结构画出流程图。一个是说明这个算法是真的不复杂,另一个是说明好的代码会说话。

优雅

你知道 Dubbo 加入这个新的负载均衡算法提交了几个文件吗?

四个文件,其中还包含两个测试文件:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这里就是策略模式和 SPI 的好处。对原有的负载均衡策略没有任何侵略性。只需要按照规则扩展配置文件,实现对应接口即可。

这是什么?

这就是值得学习优雅!

那我们优雅的进入下一议题。

最小活跃数负载均衡

这一小节所示源码,没有特别标注的地方均为 2.6.0 版本。

为什么没有用截止目前(我当时写这段文章的时候是2019年12月01日)的最新的版本号 2.7.4.1 呢?因为 2.6.0 这个版本里面有两个 bug 。从 bug 讲起来,印象更加深刻。

最后会对 2.6.0/2.6.5/2.7.4.1 版本进行对比,通过对比学习,加深印象。

我这里补充一句啊,仅仅半年的时间,版本号就从 2.7.4.1 到了 2.7.7。其中还包含一个 2.7.5 这样的大版本。

所以还有人说 Dubbo 不够活跃?(几年前的文章现在还有人在发。)

对吧,我们不吵架,我们摆事实,聊数据嘛。

Demo 准备

我看源码的习惯是先搞个 Demo 把调试环境搭起来。然后带着疑问去抽丝剥茧的 Debug,不放过在这个过程中在脑海里面一闪而过的任何疑问。

这一小节分享的是Dubbo负载均衡策略之一最小活跃数(LeastActiveLoadBalance)。所以我先搭建一个 Dubbo 的项目,并启动三个 provider 供 consumer 调用。

三个 provider 的 loadbalance 均配置的是 leastactive。权重分别是默认权重、200、300。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

**默认权重是多少?**后面看源码的时候,源码会告诉你。

三个不同的服务提供者会给调用方返回自己是什么权重的服务。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

启动三个实例。(注:上面的 provider.xml 和 DemoServiceImpl 其实只有一个,每次启动的时候手动修改端口、权重即可。)

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

到 zookeeper 上检查一下,服务提供者是否正常:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到三个服务提供者分别在 20880、20881、20882 端口。(每个红框的最后5个数字就是端口号)。

最后,我们再看服务消费者。消费者很简单,配置consumer.xml

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

直接调用接口并打印返回值即可。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

断点打在哪?

相信很多朋友也很想看源码,但是不知道从何处下手。处于一种在源码里面"乱逛"的状态,一圈逛下来,收获并不大。

这一部分我想分享一下我是怎么去看源码。首先我会带着问题去源码里面寻找答案,即有针对性的看源码。

如果是这种框架类的,正如上面写的,我会先翻一翻官网(Dubbo 的官方文档其实写的挺好了),然后搭建一个简单的 Demo 项目,然后 Debug 跟进去看。Debug 的时候当然需要是设置断点的,那么这个断点如何设置呢?

第一个断点,当然毋庸置疑,是打在调用方法的地方,比如本文中,第一个断点是在这个地方:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

接下里怎么办?

你当然可以从第一个断点处,一步一步的跟进去。但是在这个过程中,你发现了吗?大多数情况你都是被源码牵着鼻子走的。本来你就只带着一个问题去看源码的,有可能你Debug了十分钟,还没找到关键的代码。也有可能你Debug了十分钟,问题从一个变成了无数个。

所以不要慌,我们点支烟,慢慢分析。

首先怎么避免被源码牵着四处乱逛呢?

我们得找到一个突破口,还记得我在《很开心,在使用mybatis的过程中我踩到一个坑》这篇文章中提到的逆向排查的方法吗?这次的文章,我再次展示一下该方法。

看源码之前,我们的目标要十分明确,就是想要找到 Dubbo 最小活跃数算法的具体实现类以及实现类的具体逻辑是什么。

根据我们的 provider.xml 里面的:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

很明显,我们知道 loadbalance 是关键字。所以我们拿着 loadbalance 全局搜索,可以看到 Dubbo 包下面的 LoadBalance。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这是一个 SPI 接口 
com.alibaba.dubbo.rpc.cluster.LoadBalance:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

其实现类为:

com.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance

AbstractLoadBalance 是一个抽象类,该类里面有一个抽象方法doSelect。这个抽象方法其中的一个实现类就是我们要分析的最少活跃次数负载均衡的源码。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

同时,到这里我们知道了 LoadBalance 是一个 SPI 接口,说明我们可以扩展自己的负载均衡策略。抽象方法 doSelect 有四个实现类。这个四个实现类,就是 Dubbo 官方提供的负载均衡策略(截止 2.7.7 版本之前),他们分别是:

  1. ConsistentHashLoadBalance 一致性哈希算法
  2. LeastActiveLoadBalance 最小活跃数算法
  3. RandomLoadBalance 加权随机算法
  4. RoundRobinLoadBalance 加权轮询算法

我们已经找到了 LeastActiveLoadBalance 这个类了,那么我们的第二个断点打在哪里已经很明确了。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

目前看来,两个断点就可以支撑我们的分析了。

有的朋友可能想问,那我想知道 Dubbo 是怎么识别出我们想要的是最少活跃次数算法,而不是其他的算法呢?其他的算法是怎么实现的呢?从第一个断点到第二个断点直接有着怎样的调用链呢?

在没有彻底搞清楚最少活跃数算法之前,这些统统先记录在案但不予理睬。一定要明确目标,带着一个问题进来,就先把带来的问题解决了。之后再去解决在这个过程中碰到的其他问题。在这样环环相扣解决问题的过程中,你就慢慢的把握了源码的精髓。这是我个人的一点看源码的心得。供诸君参考。

模拟环境

既然叫做最小活跃数策略。那我们得让现有的三个消费者都有一些调用次数。所以我们得改造一下服务提供者和消费者。

服务提供者端的改造如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

PS:这里以权重为 300 的服务端为例。另外的两个服务端改造点相同。

客户端的改造点如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

一共发送 21 个请求:其中前 20 个先发到服务端让其 hold 住(因为服务端有 sleep),最后一个请求就是我们需要 Debug 跟踪的请求。

运行一下,让程序停在断点的地方,然后看看控制台的输出:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

权重为300的服务端共计收到9个请求

权重为200的服务端共计收到6个请求

默认权重的服务端共计收到5个请求

我们还有一个请求在 Debug。直接进入到我们的第二个断点的位置,并 Debug 到下图所示的一行代码(可以点看查看大图):

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

正如上面这图所说的:weight=100 回答了一个问题,active=0 提出的一个问题。

weight=100 回答了什么问题呢?

默认权重是多少?是 100。

我们服务端的活跃数分别应该是下面这样的

  • 权重为300的服务端,active=9
  • 权重为200的服务端,active=6
  • 默认权重(100)的服务端,active=5

但是这里为什么截图中的active会等于 0 呢?这是一个问题。

继续往下 Debug 你会发现,每一个服务端的 active 都是 0。所以相比之下没有一个 invoker 有最小 active 。于是程序走到了根据权重选择 invoker 的逻辑中。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

active为什么是0?

active 为 0 说明在 Dubbo 调用的过程中 active 并没有发生变化。那 active 为什么是 0,其实就是在问 active 什么时候发生变化

要回答这个问题我们得知道 active 是在哪里定义的,因为在其定义的地方,必有其修改的方法。

下面这图说明了active是定义在RpcStatus类里面的一个类型为AtomicInteger 的成员变量。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

在 RpcStatus 类中,有三处()调用 active 值的方法,一个增加、一个减少、一个获取:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

很明显,我们需要看的是第一个,在哪里增加。

所以我们找到了 beginCount(URL,String) 方法,该方法只有两个 Filter 调用。ActiveLimitFilter,见名知意,这就是我们要找的东西。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


com.alibaba.dubbo.rpc.filter.ActiveLimitFilter具体如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

看到这里,我们就知道怎么去回答这个问题了:为什么active是0呢?因为在客户端没有配置ActiveLimitFilter。所以,ActiveLimitFilter没有生效,导致active没有发生变化。

怎么让其生效呢?已经呼之欲出了。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

好了,再来试验一次:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


吐血输出:2万字长文带你细细盘点五种负载均衡策略

 


吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

加上Filter之后,我们通过Debug可以看到,对应权重的活跃数就和我们预期的是一致的了。

1.权重为300的活跃数为6

2.权重为200的活跃数为11

3.默认权重(100)的活跃数为3

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

根据活跃数我们可以分析出来,最后我们Debug住的这个请求,一定会选择默认权重的invoker去执行,因为他是当前活跃数最小的invoker。如下所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

虽然到这里我们还没开始进行源码的分析,只是把流程梳理清楚了。但是把Demo完整的搭建了起来,而且知道了最少活跃数负载均衡算法必须配合ActiveLimitFilter使用,位于RpcStatus类的active字段才会起作用,否则,它就是一个基于权重的算法。

比起其他地方直接告诉你,要配置ActiveLimitFilter才行哦,我们自己实验得出的结论,能让我们的印象更加深刻。

我们再仔细看一下加上ActiveLimitFilter之后的各个服务的活跃数情况:

  • 权重为300的活跃数为6
  • 权重为200的活跃数为11
  • 默认权重(100)的活跃数为3

你不觉得奇怪吗,为什么权重为200的活跃数是最高的

其在业务上的含义是:我们有三台性能各异的服务器,A服务器性能最好,所以权重为300,B服务器性能中等,所以权重为200,C服务器性能最差,所以权重为100。

当我们选择最小活跃次数的负载均衡算法时,我们期望的是性能最好的A服务器承担更多的请求,而真实的情况是性能中等的B服务器承担的请求更多。这与我们的设定相悖。

如果你说20个请求数据量太少,可能是巧合,不足以说明问题。说明你还没被我带偏,我们不能基于巧合编程。

所以为了验证这个地方确实有问题,我把请求扩大到一万个。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

同时,记得扩大 provider 端的 Dubbo 线程池:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

由于每个服务端运行的代码都是一样的,所以我们期望的结果应该是权重最高的承担更多的请求。但是最终的结果如图所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

各个服务器均摊了请求。这就是我文章最开始的时候说的Dubbo 2.6.0 版本中最小活跃数负载均衡算法的Bug之一。

接下来,我们带着这个问题,去分析源码。

剖析源码


com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance的源码如下,我逐行进行了解读。可以点开查看大图,细细品读,非常爽:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

下图中红框框起来的部分就是一个基于权重选择invoker的逻辑:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

我给大家画图分析一下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

请仔细分析图中给出的举例说明。同时,上面这图也是按照比例画的,可以直观的看到,对于某一个请求,区间(权重)越大的服务器,就越可能会承担这个请求。所以,当请求足够多的时候,各个服务器承担的请求数,应该就是区间,即权重的比值。

其中第 81 行有调用 getWeight 方法,位于抽象类 AbstractLoadBalance 中,也需要进行重点解读的代码。


com.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance 的源码如下,我也进行了大量的备注:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

在 AbstractLoadBalance 类中提到了一个预热的概念。官网中是这样的介绍该功能的:

权重的计算过程主要用于保证当服务运行时长小于服务预热时间时,对服务进行降权,避免让服务在启动之初就处于高负载状态。服务预热是一个优化手段,与此类似的还有 JVM 预热。主要目的是让服务启动后“低功率”运行一段时间,使其效率慢慢提升至最佳状态。

从上图代码里面的公式(演变后):*计算后的权重=(uptime/warmup)weight 可以看出:随着服务启动时间的增加(uptime),计算后的权重会越来越接近weight。从实际场景的角度来看,随着服务启动时间的增加,服务承担的流量会慢慢上升,没有一个陡升的过程。所以这是一个优化手段。同时 Dubbo 接口还支持延迟暴露。

在仔细的看完上面的源码解析图后,配合官网的总结加上我的灵魂画作,相信你可以对最小活跃数负载均衡算法有一个比较深入的理解:

  1. 遍历 invokers 列表,寻找活跃数最小的 Invoker
  2. 如果有多个 Invoker 具有相同的最小活跃数,此时记录下这些 Invoker 在 invokers 集合中的下标,并累加它们的权重,比较它们的权重值是否相等
  3. 如果只有一个 Invoker 具有最小的活跃数,此时直接返回该 Invoker 即可
  4. 如果有多个 Invoker 具有最小活跃数,且它们的权重不相等,此时处理方式和 RandomLoadBalance 一致
  5. 如果有多个 Invoker 具有最小活跃数,但它们的权重相等,此时随机返回一个即可
吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

所以我觉得最小活跃数负载均衡的全称应该叫做:有最小活跃数用最小活跃数,没有最小活跃数根据权重选择,权重一样则随机返回的负载均衡算法。

Bug在哪里?

Dubbo2.6.0最小活跃数算法Bug一

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

问题出在标号为 ① 和 ② 这两行代码中:

标号为 ① 的代码在url中取出的是没有经过 getWeight 方法降权处理的权重值,这个值会被累加到权重总和(totalWeight)中。

标号为 ② 的代码取的是经过 getWeight 方法处理后的权重值。

取值的差异会导致一个问题,标号为 ② 的代码的左边,offsetWeight 是一个在 [0,totalWeight) 范围内的随机数,右边是经过 getWeight 方法降权后的权重。所以在经过 leastCount 次的循环减法后,offsetWeight 在服务启动时间还没到热启动设置(默认10分钟)的这段时间内,极大可能仍然大于 0。导致不会进入到标号为 ③ 的代码中。直接到标号为 ④ 的代码处,变成了随机调用策略。这与设计不符,所以是个 bug。

前面章节说的情况就是这个Bug导致的。

这个Bug对应的issues地址和pull request分为:

https://github.com/apache/dubbo/issues/904

https://github.com/apache/dubbo/pull/2172

那怎么修复的呢?我们直接对比 Dubbo 2.7.4.1 的代码:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到获取weight的方法变了:从url中直接获取变成了通过getWeight方法获取。获取到的变量名称也变了:从weight变成了afterWarmup,更加的见名知意。

还有一处变化是获取随机值的方法的变化,从Randmo变成了ThreadLoaclRandom,性能得到了提升。这处变化就不展开讲了,有兴趣的朋友可以去了解一下。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

Dubbo2.6.0最小活跃数算法Bug二

这个Bug我没有遇到,但是我在官方文档上看了其描述(官方文档中的版本是2.6.4),引用如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

官网上说这个问题在2.6.5版本进行修复。我对比了2.6.0/2.6.5/2.7.4.1三个版本,发现每个版本都略有不同。如下所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

图中标记为①的三处代码:

2.6.0版本的是有Bug的代码,原因在上面说过了。

2.6.5版本的修复方式是获取随机数的时候加一,所以取值范围就从**[0,totalWeight)变成了[0,totalWeight]**,这样就可以避免这个问题。

2.7.4.1版本的取值范围还是[0,totalWeight),但是它的修复方法体现在了标记为②的代码处。2.6.0/2.6.5版本标记为②的地方都是if(offsetWeight<=0),而2.7.4.1版本变成了if(offsetWeight<0)

你品一品,是不是效果是一样的,但是更加优雅了。

朋友们,魔鬼,都在细节里啊!

好了,进入下一议题。

一致性哈希负载均衡

这一部分是对于Dubbo负载均衡策略之一的一致性哈希负载均衡的详细分析。对源码逐行解读、根据实际运行结果,配以丰富的图片,可能是东半球讲一致性哈希算法在Dubbo中的实现最详细的文章了。

本小节所示源码,没有特别标注的地方,均为2.7.4.1版本。

在撰写本文的过程中,发现了Dubbo2.7.0版本之后的一个bug。会导致性能问题,如果你们的负载均衡配置的是一致性哈希或者考虑使用一致性哈希的话,可以了解一下。

哈希算法

在介绍一致性哈希算法之前,我们看看哈希算法,以及它解决了什么问题,带来了什么问题。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

如上图所示,假设0,1,2号服务器都存储的有用户信息,那么当我们需要获取某用户信息时,因为我们不知道该用户信息存放在哪一台服务器中,所以需要分别查询0,1,2号服务器。这样获取数据的效率是极低的。

对于这样的场景,我们可以引入哈希算法。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

还是上面的场景,但前提是每一台服务器存放用户信息时是根据某一种哈希算法存放的。所以取用户信息的时候,也按照同样的哈希算法取即可。

假设我们要查询用户号为100的用户信息,经过某个哈希算法,比如这里的userId mod n,即100 mod 3结果为1。所以用户号100的这个请求最终会被1号服务器接收并处理。

这样就解决了无效查询的问题。

但是这样的方案会带来什么问题呢?

扩容或者缩容时,会导致大量的数据迁移。最少也会影响百分之50的数据。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

为了说明问题,我们加入一台服务器3。服务器的数量n就从3变成了4。还是查询用户号为100的用户信息时,100 mod 4结果为0。这时,请求就被0号服务器接收了。

当服务器数量为3时,用户号为100的请求会被1号服务器处理。

当服务器数量为4时,用户号为100的请求会被0号服务器处理。

所以,当服务器数量增加或者减少时,一定会涉及到大量数据迁移的问题。可谓是牵一发而动全身。

对于上诉哈希算法其优点是简单易用,大多数分库分表规则就采取的这种方式。一般是提前根据数据量,预先估算好分区数。

缺点是由于扩容或收缩节点导致节点数量变化时,节点的映射关系需要重新计算,会导致数据进行迁移。所以扩容时通常采用翻倍扩容,避免数据映射全部被打乱,导致全量迁移的情况,这样只会发生50%的数据迁移。

假设这是一个缓存服务,数据的迁移会导致在迁移的时间段内,有缓存是失效的。

缓存失效,可怕啊。还记得我之前的文章吗,《当周杰伦把QQ音乐干翻的时候,作为程序猿我看到了什么?》就是讲缓存击穿、缓存穿透、缓存雪崩的场景和对应的解决方案。

一致性哈希算法

为了解决哈希算法带来的数据迁移问题,一致性哈希算法应运而生。

对于一致性哈希算法,官方说法如下:

一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题。

什么意思呢?我用大白话加画图的方式给你简单的介绍一下。

一致性哈希,你可以想象成一个哈希环,它由0到2^32-1个点组成。A,B,C分别是三台服务器,每一台的IP加端口经过哈希计算后的值,在哈希环上对应如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

当请求到来时,对请求中的某些参数进行哈希计算后,也会得出一个哈希值,此值在哈希环上也会有对应的位置,这个请求会沿着顺时针的方向,寻找最近的服务器来处理它,如下图所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

一致性哈希就是这么个东西。那它是怎么解决服务器的扩容或收缩导致大量的数据迁移的呢?

看一下当我们使用一致性哈希算法时,加入服务器会发什么事情。

当我们加入一个D服务器后,假设其IP加端口,经过哈希计算后落在了哈希环上图中所示的位置。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

这时影响的范围只有图中标注了五角星的区间。这个区间的请求从原来的由C服务器处理变成了由D服务器请求。而D到C,C到A,A到B这个区间的请求没有影响,加入D节点后,A、B服务器是无感知的。

所以,在一致性哈希算法中,如果增加一台服务器,则受影响的区间仅仅是新服务器(D)在哈希环空间中,逆时针方向遇到的第一台服务器(B)之间的区间,其它区间(D到C,C到A,A到B)不会受到影响。

在加入了D服务器的情况下,我们再假设一段时间后,C服务器宕机了:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

当C服务器宕机后,影响的范围也是图中标注了五角星的区间。C节点宕机后,B、D服务器是无感知的。

所以,在一致性哈希算法中,如果宕机一台服务器,则受影响的区间仅仅是宕机服务器(C)在哈希环空间中,逆时针方向遇到的第一台服务器(D)之间的区间,其它区间(C到A,A到B,B到D)不会受到影响。

综上所述,在一致性哈希算法中,不管是增加节点,还是宕机节点,受影响的区间仅仅是增加或者宕机服务器在哈希环空间中,逆时针方向遇到的第一台服务器之间的区间,其它区间不会受到影响。

是不是很完美?

不是的,理想和现实的差距是巨大的。

一致性哈希算法带来了什么问题?

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

当节点很少的时候可能会出现这样的分布情况,A服务会承担大部分请求。这种情况就叫做数据倾斜。

怎么解决数据倾斜呢?加入虚拟节点。

怎么去理解这个虚拟节点呢?

首先一个服务器根据需要可以有多个虚拟节点。假设一台服务器有n个虚拟节点。那么哈希计算时,可以使用IP+端口+编号的形式进行哈希值计算。其中的编号就是0到n的数字。由于IP+端口是一样的,所以这n个节点都是指向的同一台机器。

如下图所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

在没有加入虚拟节点之前,A服务器承担了绝大多数的请求。但是假设每个服务器有一个虚拟节点(A-1,B-1,C-1),经过哈希计算后落在了如上图所示的位置。那么A服务器的承担的请求就在一定程度上(图中标注了五角星的部分)分摊给了B-1、C-1虚拟节点,实际上就是分摊给了B、C服务器。

一致性哈希算法中,加入虚拟节点,可以解决数据倾斜问题。

当你在面试的过程中,如果听到了类似于数据倾斜的字眼。那大概率是在问你一致性哈希算法和虚拟节点。

在介绍了相关背景后,我们可以去看看一致性哈希算法在Dubbo中的应用了。

一致性哈希算法在Dubbo中的应用

前面我们说了Dubbo中负载均衡的实现是通过
org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance中的 doSelect 抽象方法实现的,一致性哈希负载均衡的实现类如下所示:

org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

由于一致性哈希实现类看起来稍微有点抽象,不太好演示,所以我想到了一个"骚"操作。前面的文章说过 LoadBalance 是一个 SPI 接口:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

既然是一个 SPI 接口,那我们可以自己扩展一个一模一样的算法,只是在算法里面加入一点输出语句方便我们观察情况。怎么扩展 SPI 接口就不描述了,只要记住代码里面的输出语句都是额外加的,此外没有任何改动即可,如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

整个类如下图片所示,请先看完整个类,有一个整体的概念后,我会进行方法级别的分析。

图片很长,其中我加了很多注释和输出语句,可以点开大图查看,一定会帮你更加好的理解一致性哈希在Dubbo中的应用:

改造之后,我们先把程序跑起来,有了输出就好分析了。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

服务端代码如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

其中的端口是需要手动修改的,我分别启动服务在20881和20882端口。

项目中provider.xml配置如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

consumer.xml配置如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

然后,启动在20881和20882端口分别启动两个服务端。客户端消费如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

运行结果输出如下,可以先看个大概的输出,下面会对每一部分输出进行逐一的解读

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

好了,用例也跑起来了,日志也有了。接下来开始结合代码和日志进行方法级别的分析。

首先是doSelect方法的入口:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

从上图我们知道了,第一次调用需要对selectors进行put操作,selectors的 key 是接口中定义的方法,value 是 ConsistentHashSelector 内部类

ConsistentHashSelector通过调用其构造函数进行初始化的。invokers(服务端)作为参数传递到了构造函数中,构造函数里面的逻辑,就是把服务端映射到哈希环上的过程,请看下图,结合代码,仔细分析输出数据:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

从上图可以看出,当 ConsistentHashSelector 的构造方法调用完成后,8个虚拟节点在哈希环上已经映射完成。两台服务器,每一台4个虚拟节点组成了这8个虚拟节点。

doSelect方法继续执行,并打印出每个虚拟节点的哈希值和对应的服务端,请仔细品读下图:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

说明一下:上面图中的哈希环是没有考虑比例的,仅仅是展现了两个服务器在哈希环上的相对位置。而且为了演示说明方便,仅仅只有8个节点。假设我们有4台服务器,每台服务器的虚拟节点是默认值(160),这个情况下哈希环上一共有160*4=640个节点。

哈希环映射完成后,接下来的逻辑是把这次请求经过哈希计算后,映射到哈希环上,并顺时针方向寻找遇到的第一个节点,让该节点处理该请求:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

还记得地址为 468e8565 的 A 服务器是什么端口吗?前面的图片中有哦,该服务对应的端口是 20882 。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

最后我们看看输出结果:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

和我们预期的一致。整个调用就算是完成了。

再对两个方法进行一个补充说明。

第一个方法是 selectForKey,这个方法里面逻辑如下图所示:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

虚拟节点都存储在 TreeMap 中。顺时针查询的逻辑由 TreeMap 保证。看一下下面的 Demo 你就明白了。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

第二个方法是 hash 方法,其中的 & 0xFFFFFFFFL 的目的如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

&是位运算符,而 0xFFFFFFFFL 转换为四字节表现后,其低32位全是1,所以保证了哈希环的范围是 [0,Integer.MAX_VALUE]:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

所以这里我们可以改造这个哈希环的范围,假设我们改为 100000。十进制的 100000 对于的 16 进制为 186A0 。所以我们改造后的哈希算法为:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

再次调用后可以看到,计算后的哈希值都在10万以内。但是分布极不均匀,说明修改数据后这个哈希算法不是一个优秀的哈希算法:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

以上,就是对一致性哈希算法在Dubbo中的实现的解读。需要特殊说明一下的是,一致性哈希负载均衡策略和权重没有任何关系

我又发现了一个BUG

前面我介绍了Dubbo 2.6.5版本之前,最小活跃数算法的两个 bug。

很不幸,这次我又发现了Dubbo 2.7.4.1版本,一致性哈希负载均衡策略的一个bug,我提交了issue 地址如下:

https://github.com/apache/dubbo/issues/5429

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

我在这里详细说一下这个Bug现象、原因和我的解决方案。

现象如下,我们调用三次服务端:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

输出日志如下(有部分删减):

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到,在三次调用的过程中并没有发生服务的上下线操作,但是每一次调用都重新进行了哈希环的映射。而我们预期的结果是应该只有在第一次调用的时候进行哈希环的映射,如果没有服务上下线的操作,后续请求根据已经映射好的哈希环进行处理。

上面输出的原因是由于每次调用的invokers的identityHashCode发生了变化:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

我们看一下三次调用invokers的情况:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

经过debug我们可以看出因为每次调用的invokers地址值不是同一个,所以System.identityHashCode(invokers)方法返回的值都不一样。

接下来的问题就是为什么每次调用的invokers地址值都不一样呢?

经过Debug之后,可以找到这个地方:

org.apache.dubbo.rpc.cluster.RouterChain#route

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

问题就出在这个TagRouter中:

org.apache.dubbo.rpc.cluster.router.tag.TagRouter#filterInvoker

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

所以,在TagRouter中的stream操作,改变了invokers,导致每次调用时其

System.identityHashCode(invokers)返回的值不一样。所以每次调用都会进行哈希环的映射操作,在服务节点多,虚拟节点多的情况下会有一定的性能问题。

到这一步,问题又发生了变化。这个TagRouter怎么来的呢

如果了解Dubbo 2.7.x版本新特性的朋友可能知道,标签路由是Dubbo2.7引入的新功能。

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

通过加载下面的配置加载了RouterFactrory:

META-INFdubbointernal
org.apache.dubbo.rpc.cluster.RouterFactory(Dubbo 2.7.0版本之前)

META-INFdubbointernal
com.alibaba.dubbo.rpc.cluster.RouterFactory(Dubbo 2.7.0之前)

下面是Dubbo 2.6.7(2.6.x的最后一个版本)和Dubbo 2.7.0版本该文件的对比:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到确实是在 Dubbo 2.7.0 之后引入了 TagRouter。

至此,Dubbo 2.7.0 版本之后,一致性哈希负载均衡算法的 Bug 的来龙去脉也介绍清楚了。

解决方案是什么呢?特别简单,把获取 identityHashCode 的方法从 System.identityHashCode(invokers) 修改为 invokers.hashCode() 即可。

此方案是我提的 issue 里面的评论,这里 System.identityHashCode 和 hashCode 之间的联系和区别就不进行展开讲述了,不清楚的大家可以自行了解一下。

(我的另外一篇文章:够强!一行代码就修复了我提的Dubbo的Bug。)

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

改完之后,我们再看看运行效果:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

可以看到第二次调用的时候并没有进行哈希环的映射操作,而是直接取到了值,进行调用。

加入节点,画图分析

最后,我再分析一种情况。在A、B、C三个服务器(20881、20882、20883端口)都在正常运行,哈希映射已经完成的情况下,我们再启动一个D节点(20884端口),这时的日志输出和对应的哈希环变化情况如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

根据日志作图如下:

吐血输出:2万字长文带你细细盘点五种负载均衡策略

 

根据输出日志和上图再加上源码,你再细细回味一下。我个人觉得还是讲的非常详细了。

一致性哈希的应用场景

当大家谈到一致性哈希算法的时候,首先的第一印象应该是在缓存场景下的使用,因为在一个优秀的哈希算法加持下,其上下线节点对整体数据的影响(迁移)都是比较友好的。

但是想一下为什么 Dubbo 在负载均衡策略里面提供了基于一致性哈希的负载均衡策略?它的实际使用场景是什么?

我最开始也想不明白。我想的是在 Dubbo 的场景下,假设需求是想要一个用户的请求一直让一台服务器处理,那我们可以采用一致性哈希负载均衡策略,把用户号进行哈希计算,可以实现这样的需求。但是这样的需求未免有点太牵强了,适用场景略小。

直到有天晚上,我睡觉之前,电光火石之间突然想到了一个稍微适用的场景了。

如果需求是需要保证某一类请求必须顺序处理呢?

如果你用其他负载均衡策略,请求分发到了不同的机器上去,就很难保证请求的顺序处理了。比如A,B请求要求顺序处理,现在A请求先发送,被负载到了A服务器上,B请求后发送,被负载到了B服务器上。而B服务器由于性能好或者当前没有其他请求或者其他原因极有可能在A服务器还在处理A请求之前就把B请求处理完成了。这样不符合我们的要求。

这时,一致性哈希负载均衡策略就上场了,它帮我们保证了某一类请求都发送到固定的机器上去执行。比如把同一个用户的请求发送到同一台机器上去执行,就意味着把某一类请求发送到同一台机器上去执行。所以我们只需要在该机器上运行的程序中保证顺序执行就行了,比如你加一个队列。

一致性哈希算法+队列,可以实现顺序处理的需求。

好了,一致性哈希负载均衡算法就写到这里。

原文链接:
https://juejin.im/post/5ed39adef265da76dc1bb817



Tags:负载均衡   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
负载均衡是将客户端请求访问,通过提前约定好的规则转发给各个server。其中有好几个种经典的算法,下面我们用Java实现这几种算法。 轮询算法轮询算法按顺序把每个新的连接请求...【详细内容】
2021-09-27  Tags: 负载均衡  点击:(52)  评论:(0)  加入收藏
什么是NginxNginx(engine x)是一个高性能的HTTP和反向代理服务器,具有内存少,高并发特点强。1、处理静态文件,索引文件以及自动检索打开文件描述符缓冲2、无缓冲的反向代理加速...【详细内容】
2021-09-02  Tags: 负载均衡  点击:(70)  评论:(0)  加入收藏
1.安装依赖环境yum -y install wget gcc-c++ ncurses ncurses-devel cmake make perl bison openssl openssl-devel gcc* libxml2 libxml2-devel curl-devel libjpeg* libpn...【详细内容】
2021-08-03  Tags: 负载均衡  点击:(63)  评论:(0)  加入收藏
域名解析是客户端访问系统的第一步。在架构设计中,DNS Server除了解析域名,还能干点什么呢?又有哪些“挖坑”的用法需要避免呢?典型的互联网架构中,我们通过nginx的反向代理来做...【详细内容】
2021-07-29  Tags: 负载均衡  点击:(264)  评论:(0)  加入收藏
均衡算法也是多种多样,常见的两大类:即静态负载均衡法和动态负载均衡法。静态算法也是比较简单,主要有有一般轮询算法,基于比例的加权轮询算法,以及基于优先级的轮询算法。动态算...【详细内容】
2021-07-27  Tags: 负载均衡  点击:(72)  评论:(0)  加入收藏
今天总结一下负载均衡中LVS与Nginx的区别,好几篇博文一开始就说LVS是单向的,Nginx是双向的,我个人认为这是不准确的,LVS三种模式中,虽然DR模式以及TUN模式只有请求的报文经过Director,但是NAT模式,Real Server回复的...【详细内容】
2021-06-08  Tags: 负载均衡  点击:(114)  评论:(0)  加入收藏
之前有很多朋友问关于 Nginx 的 upstream 模块中 max_fails 及 fail_timeout,这两个指令,分别是配置关于负载均衡过程中,对于上游(后端)服务器的失败尝试次数和不可用时间,很多...【详细内容】
2021-04-15  Tags: 负载均衡  点击:(206)  评论:(0)  加入收藏
需求在Linux SMP(对称多处理器)环境下,每个CPU对应一个run_queue(可执行队列)。如果一个进程处于TASK_RUNNING状态(可执行状态),则它会被加入到其中一个run_queue(且同一时刻仅会被加...【详细内容】
2021-04-01  Tags: 负载均衡  点击:(225)  评论:(0)  加入收藏
分层模型,每一层实现各自的功能和协议,并完成与相邻层的接口通讯。OSI 的服务定义详细说明了各层所提供的服务,某一层的服务就是该层及其下各层的一种能力,通过接口提供给更高一层。各层所提供的服务与这些服务是怎么实现...【详细内容】
2021-03-16  Tags: 负载均衡  点击:(257)  评论:(0)  加入收藏
Nginx的安装及负载均衡配置在安装完分布式文件系统之后,就可以在应用程序中进行调用了。注意需要在 Web端的页面上进行访问,还必须借助Nginx 提供访问服务。使用Nginx 不仅可...【详细内容】
2021-03-11  Tags: 负载均衡  点击:(159)  评论:(0)  加入收藏
▌简易百科推荐
阿里云镜像源地址及安装网站地址https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b111kK44P更新源之前把之前的国外的镜像先备份一下 切换到yumcd...【详细内容】
2021-12-27  干程序那些事    Tags:CentOS7镜像   点击:(1)  评论:(0)  加入收藏
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  程序猿阿嘴  CSDN  Tags:Netty   点击:(12)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  有云转晴    Tags:chrome   点击:(7)  评论:(0)  加入收藏
一. HTTP gzip压缩,概述 request header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据 response body,同时加入以下header:Content-Encoding: gzip:表明bo...【详细内容】
2021-12-22  java乐园    Tags:gzip压缩   点击:(9)  评论:(0)  加入收藏
yum -y install gcc automake autoconf libtool makeadduser testpasswd testmkdir /tmp/exploitln -s /usr/bin/ping /tmp/exploit/targetexec 3< /tmp/exploit/targetls -...【详细内容】
2021-12-22  SofM    Tags:Centos7   点击:(7)  评论:(0)  加入收藏
Windows操作系统和Linux操作系统有何区别?Windows操作系统:需支付版权费用,(华为云已购买正版版权,在华为云购买云服务器的用户安装系统时无需额外付费),界面化的操作系统对用户使...【详细内容】
2021-12-21  卷毛琴姨    Tags:云服务器   点击:(6)  评论:(0)  加入收藏
参考资料:Hive3.1.2安装指南_厦大数据库实验室博客Hive学习(一) 安装 环境:CentOS 7 + Hadoop3.2 + Hive3.1 - 一个人、一座城 - 博客园1.安装hive1.1下载地址hive镜像路径 ht...【详细内容】
2021-12-20  zebra-08    Tags:Hive   点击:(9)  评论:(0)  加入收藏
以下是服务器安全加固的步骤,本文以腾讯云的CentOS7.7版本为例来介绍,如果你使用的是秘钥登录服务器1-5步骤可以跳过。1、设置复杂密码服务器设置大写、小写、特殊字符、数字...【详细内容】
2021-12-20  网安人    Tags:服务器   点击:(7)  评论:(0)  加入收藏
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  mdong    Tags:Nginx   点击:(7)  评论:(0)  加入收藏
转自: https://kermsite.com/p/wt-ssh/由于格式问题,部分链接、表格可能会失效,若失效请访问原文密码登录 以及 通过密钥实现免密码登录Dec 15, 2021阅读时长: 6 分钟简介Windo...【详细内容】
2021-12-17  LaLiLi    Tags:SSH连接   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条