面试官:要不我们聊一下“心跳”的设计? (上)

简介: 面试官:要不我们聊一下“心跳”的设计? (上)

你好呀,我是歪歪。

是这样的,我最近又看到了这篇文章《工商银行分布式服务 C10K 场景解决方案 》。

为什么是又呢?

因为这篇文章最开始发布的时候我就看过了,当时就觉得写得挺好的,宇宙行(工商银行)果然是很叼的样子。

但是看过了也就看过了,当时没去细琢磨。

这次看到的时候,刚好是在下班路上,就仔仔细细的又看了一遍。

嗯,常读常新,还是很有收获的。

所以写篇文章,给大家汇报一下我再次阅读之后的一下收获。

image.png


文章提要


我知道很多同学应该都没有看过这篇文章,所以我先放个链接,《工商银行分布式服务 C10K 场景解决方案 》

先给大家提炼一下文章的内容,但是如果你有时间的话,也可以先去细细的读一下这篇文章,感受一下宇宙行的实力。

文章内容大概是这样的。

在宇宙行的架构中,随着业务的发展,在可预见的未来,会出现一个提供方为数千个、甚至上万个消费方提供服务的场景。

在如此高负载量下,若服务端程序设计不够良好,网络服务在处理数以万计的客户端连接时、可能会出现效率低下甚至完全瘫痪的情况,即为 C10K 问题。

C10K 问题就不展开讲了,网上查一下,非常著名的程序相关问题,只不过该问题已经成为历史了。

而宇宙行的 RPC 框架使用的是 Dubbo,所以他们那篇文章就是基于这个问题去展开的:

基于 Dubbo 的分布式服务平台能否应对复杂的 C10K 场景?

为此,他们搭建了大规模连接环境、模拟服务调用进行了一系列探索和验证。

首先他们使用的 Dubbo 版本是 2.5.9。版本确实有点低,但是银行嘛,懂的都懂,架构升级是能不动就不动,稳当运行才是王道。

在这个版本里面,他们搞了一个服务端,服务端的逻辑就是 sleep 100ms,模拟业务调用,部署在一台 8C16G 的服务器上。

对应的消费方配置服务超时时间为 5s,然后把消费方部署在数百台 8C16G 的服务器上(我滴个乖乖,数百台 8C16G 的服务器,这都是白花花的银子啊,有钱真好),以容器化方式部署 7000 个服务消费方。


image.png

每个消费方启动后每分钟调用 1 次服务。

然后他们定制了两个测试的场景:

image.png

场景 2 先暂时不说,异常是必然的,因为只有一个提供方嘛,重启期间消费方还在发请求,这必然是要凉的。

但是场景 1 按理来说不应该的啊。

你想,消费方配置的超时时间是 5s,而提供方业务逻辑只处理 100ms。再怎么说时间也是够够的了。

需要额外多说一句的是:本文也只聚焦于场景 1。

但是,朋友们,但是啊。

虽然调用方一分钟发一次请求的频率不高,但是架不住调用方有 7000 个啊,这 7000 个调用方,这就是传说中的突发流量,只是这个“突发”是每分钟一次。

所以,偶现超时也是可以理解的,毕竟服务端处理能力有限,有任务在队列里面稍微等等就超时了。

可以写个小例子示意一下,是这样的:

image.png

就是搞个线程池,线程数是 200。然后提交 7000 个任务,每个任务耗时 100ms,用 CountDownLatch 模拟了一下并发,在我的 12 核的机器上运行耗时 3.8s 的样子。

也就是说如果在 Dubbo 的场景下,每一个请求再加上一点点网络传输的时间,一点点框架内部的消耗,这一点点时间再乘以 7000,最后被执行的任务理论上来说,是有可能超过 5s 的。

所以偶现超时是可以理解的。

但是,朋友们,又来但是了啊。

我前面都说的是理论上,然而实践才是检验真理的唯一办法。

看一下宇宙行的验证结果:


微信图片_20220428225230.png


首先我们可以看到消费方不论是发起请求还是处理响应都是非常迅速的,但是卡壳就卡在服务方从收到请求到处理请求之间。

经过抓包分析,他们得出结论:导致交易超时的原因不在消费方侧,而在提供方侧。

这个结论其实也很好理解,因为压力都在服务提供方这边,所以阻塞也应该是在它这里。

其实到这里我们基本上就可以确认,肯定是 Dubbo 框架里面的某一些操作导致了耗时的增加。

难的就是定位到,到底是什么操作呢?

宇宙行通过一系列操作,经过缜密的分析,得出了一个结论:

心跳密集导致 netty worker 线程忙碌,从而导致交易耗时增长。

也就是结论中提到的这一点:

image.png

有了结论,找到了病灶就好办了,对症下药嘛。

因为前面说过,本文只聚焦于场景一,所以我们看一下对于场景一宇宙行给出的解决方案:

image.png

全都是围绕着心跳的优化处理,处理完成后的效果如下:


image.png


其中效果最显著的操作是“心跳绕过序列化”。

消费方与提供方之间平均处理时差由 27ms 降低至 3m,提升了 89%。

前 99% 的交易耗时从 191ms 下降至 133ms,提升了 30%。

好了,写到这,就差不多是把那篇文章里面我当时看到的一些东西复述了一遍,没啥大营养。

只是我还记得第一次看到这篇文章的时候,我是这样的:

image.png

我觉得挺牛逼的,一个小小的心跳,在 C10K 的场景下竟然演变成了一个性能隐患。

我得去研究一下,顺便宇宙行给出的方案中最重要的是“心跳绕过序列化”,我还得去研究一下 Dubbo 怎么去实现这个功能,研究明白了这玩意就是我的了啊。

但是...


image.png

我忘记当时为啥没去看了,但是没关系,我现在想起来了嘛,马上就开始研究。



心跳如何绕过序列化


我是怎么去研究呢?

直接往源码里面冲吗?

是的,就是往源码里面冲。

但是冲之前,我先去 Dubb 的 github 上逛了一圈:

https://github.com/apache/dubbo

然后在 Pull request 里面先搜索了一下“Heartbeat”,这一搜还搜出不少好东西呢:

image.png

我一眼看到这两个 pr 的时候,眼睛都在放光。

好家伙,我本来只是想随便看看,没想到直接定位了我要研究的东西了。

我只需要看看这两个 pr,就知道是怎么实现的“心跳绕过序列化”,这直接就让我少走了很多弯路。

首先看这个:

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


image.png

从这段描述中可以知道,我找到对的地方了。而从他的描述中知道“心跳跳过序列化”,就是用 null 来代替了序列化的这个过程。

同时这个 pr 里面还说明了自己的改造思路:

image.png

接着就带大家看一下这一次提交的代码。

怎么看呢?

可以在 git 上看到他对应这次提交的文件:

image.png

到源码里面找到对应地方即可,这也是一个去找源码的方法。

我比较熟悉 Dubbo 框架,不看这个 pr 我也大概知道去哪里找对应的代码。但是如果换成另外一个我不熟悉的框架呢?

从它的 git 入手其实是一个很好的角度。

一个翻阅源码的小技巧,送给你。

如果你不了解 Dubbo 框架也没有关系,我们只是聚焦于“心跳是如何跳过序列化”的这一个点。至于心跳是由谁如何在什么时间发起的,这一节暂时不讲。

接着,我们从这个类下手:

org.apache.dubbo.rpc.protocol.dubbo.DubboCodec

目录
相关文章
|
3月前
|
Java 程序员
反问面试官:如何实现集群内选主
这个示例展示了多个节点通过投票选举一个新的主节点的过程。Netty 用于节点间的通信,而每个节点则负责发起和响应选举消息。
反问面试官:如何实现集群内选主
|
消息中间件 存储 网络协议
面试跳槽季惊艳面试官的回答:谈谈你对RabbitMQ工作原理的理解?
一个5年工作经验的小伙伴,在面试的时候被这样一个问题。谈谈你对RabbitMQ架构原理的理解。当时,这位小伙伴只解答说,我只会用,原理并没有关注过。那今天我给大家来分享一下我的理解。
98 1
|
7月前
|
Java 调度
金三银四面试必问:线程有几种状态
金三银四面试必问:线程有几种状态
37 0
|
算法 Java BI
Sentinel为什么这么强,我忍不住扒了扒背后的实现原理
大家好,我是三友~~ 最近我在整理代码仓库的时候突然发现了被尘封了接近两年之久的Sentinel源码库 两年前我出于好奇心扒了一下Sentinel的源码,但是由于Sentinel本身源码并不复杂,在简单扒了扒之后几乎就再没扒过了 那么既然现在又让我看到了,所以我准备再来好好地扒一扒,然后顺带写篇文章来总结一下。
Sentinel为什么这么强,我忍不住扒了扒背后的实现原理
|
消息中间件 存储 Kafka
这是面试官最想听到的回答:谈谈你对Kafka数据存储原理的理解?
一位5年工作经验的小伙伴面试的时候被问到这样一个问题,说”谈谈你对Kafka数据存储原理的理解“。然后,这位小伙伴突然愣住了,什么是零拷贝,零拷贝跟Kafka有关系吗? 那么今天,我给大家来聊一聊我对Kafka零拷贝原理的理解。
98 0
|
NoSQL 安全 Redis
分布式锁原理没搞懂,错失大厂offer
分布式锁原理没搞懂,错失大厂offer
62 0
|
消息中间件 算法 架构师
盘点那些IT技术面试官常用的10个挂人套路
最近几个朋友找我聊天,给我讲述了面试过程中遇到的一些不太理解的事情。作为一个技术面试官,今天来分享 10 个面试相关的套路。
|
存储 Prometheus 监控
腾讯二面:你们线程池是怎么做监控的?
大部分情况下,线程池的运行情况对于使用者来说是个黑盒 运行情况不可知,会导致 生产出现事故问题排查困难,以及线程池参数难以定义 文章围绕线程池监控展开,讨论 线程池如何监控、监控的指标以及监控数据的存储展示
|
消息中间件 算法 JavaScript
面试官:谈谈分布式一致性机制,我一脸懵逼。。
面试官:谈谈分布式一致性机制,我一脸懵逼。。
|
程序员
5分钟掌握如何做面试官
5分钟掌握如何做面试官
190 0
5分钟掌握如何做面试官