换个数据结构,一不小心节约了 591 台机器

前段时间,我在 B 站上看到一个技术视频,题目叫做《机票报价高并发场景下的一些解决方案》。

up 主是 Qunar技术大本营,也就是我们耳熟能详的“去哪儿”。

视频链接在这里:

www.bilibili.com/video/BV1eX…

当时其实我是被他的这个图片给吸引到了(里面的 12 qps 应该是 12k qps):

他介绍了两个核心系统在经过一个“数据压缩”的操作之后,分别节约了 204C 和 2160C 的服务器资源。

共计就是 2364C 的服务器资源。

如果按照一般标配的 4C8G 服务器,好家伙,这就是节约了 591 台机器啊,你想想一年就节约了多大一笔开销。

视频中介绍了几种数据压缩的方案,其中方案之一就是用了高性能集合:

因为他们的系统设计中大量用到“本地缓存”,而本地缓存大多就是使用 HashMap 来帮忙。

所以他们把 HashMap 换成了性能更好的 IntObjectHashMap,这个类出自 Netty。

为什么换了一个类之后,就节约了这么多的资源呢?

换言之,IntObjectHashMap 性能更好的原因是什么呢?

我也不知道,所以我去研究了一下。

拉源码

研究的第一步肯定是要找到对应的源码。

你可以去找个 Netty 依赖,然后找到里面的 IntObjectHashMap。

我这边本地刚好有我之前拉下来的 Netty 源码,只需要同步一下最新的代码就行了。

但是我在 4.1 分支里面找这个类的时候并没有找到,只看到了一个相关的 Benchmark 类:

点进去一看,确实没有 IntObjectHashMap 这个类:

很纳闷啊,我反正也没搞懂为啥,但是我直接就是一个不纠结了,反正我现在只是想找到一个 IntObjectHashMap 类而已。

4.1 分支如果没有的话,那么就 4.0 上看看呗:

于是我切到了 4.0 分支里面去找了一下,很顺利就找到了对应的类和测试类:

能看到测试类,其实也是我喜欢把项目源码拉下来的原因。如果你是通过引入 Netty 的 Maven 依赖的方式找到对应类的,就看不到测试类了。

有时候配合着测试类看源码,事半功倍,一个看源码的小技巧,送给你。

而我要拉源码的最重要的一个目的其实是这个:

可以看到这个类的提交记录,观察到这个类的演变过程,这个是很重要的。

因为一次提交绝大部分情况下对应着一次 bug 修改或者性能优化,都是我们应该关注的地方。

比如,我们可以看到这个小哥针对 hashIndex 方法提交了三次:

在正式研究 IntObjectHashMap 源码之前,我们先看看只关注 hashIndex 这个局部的方法。

首先,这个地方现在的代码是这样的:

我知道这个方法是获取 int 类型的 key 在 keys 这个数组中的下标,支持 key 是负数的情况。

那么为啥这一行代码就提交了三次呢?

我们先看第一次提交:

非常清晰,左边是最原始的代码,如果 key 是负数的话,那么返回的 index 就是负数,很明显不符合逻辑。

所以有人提交了右边的代码,在算出 hash 值为负数的时候,加上数组的长度,最终得到一个正数。

很快,提交代码的哥们,发现了一个更好的写法,进行了一次优化提交:

拿掉了小于零的判断。不管 key%length 算出的值是正还是负,都将结果加上一个数组的长度后再次对数组的长度进行 % 运行。

这样保证算出来的 index 一定是一个正数。

第三次提交的代码就很好理解了,代入变量:

所以,最终的代码就是这样的:

return (key % keys.length + keys.length) % keys.length;

这样的写法,不比判断小于零优雅的多且性能也好一点吗?而且这也是一个常规的优化方案。

如果你看不到代码提交记录,你就看不到这个方法的演变过程。我想表达的是:在代码提交记录中能挖掘到非常多比源码更有价值的信息。

又是一个小技巧,送给你。

IntObjectHashMap

接下来我们一起探索一下 IntObjectHashMap 的奥秘。

关于这个 Map,其实有两个相关的类:

其中 IntObjectMap 是个接口。

它们不依赖除了 JDK 之外的任何东西,所以你搞懂原理之后,如果发现自己的业务场景下有合适的场景,完全可以把这两个类粘贴到自己的项目中去,一行代码都不用改,拿来就用。

在研究了官方的测试用例和代码提交记录之后,我选择先把这两个类粘出来,自己写个代码调试一下,这样的好处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值