hotkey
hotkey(https://gitee.com/jd-platform-opensource/hotkey)是京东的一个 热 key 发现系统,他能够感知系统中访问频繁的资源,比如Redis key,接口url等,在发现此类情况后,能够通知到相关的应用,应用可采取一些自定义的措施。 hotkey 系统注释都比较清楚,文档也比较详细。 这里就不展开说了。
广义上讲,hotkey 也是一个系统问题,其中比较有代表性的是 redis 热 key 问题。对互联网应用来说,无法提前预测热点数据,我们一般也只是会对有可能是热点的数据使用 redis 进行缓存,每次请求都会请求 redis,正常情况下 redis 也基本能抗住,但是如果请求特别频繁, 就会让 redis 压力变大,此时可以使用 guava cache 等本地缓存工具做进程的缓存,一个请求会先在本地内存中查找,查找不到再到 redis 查找。
使用 本地缓存+远程缓存有两个要注意的点:
- 本地内存:一般应用程序的内存普遍比较小,如果所有的redis缓存数据都先在本地保存,对本地内存也会造成不小的压力,严重的会影响到应用本身的运行。
- 一致性问题:当缓存发生变化,如何保证 redis 缓存的数据和本地的一致,一般的做法是本地缓存配置一个比较短的有效期,当本地缓存失效后,再到 redis 中获取,这样可以尽可能的保证一致。 但是当应用身处一个集群的时候,应用在不同的机器上,缓存数据不可能做到一起失效,此时一个用户的请求第一次可能请求在 A 机器上,第二次请求到 B 机器上,就会有脏数据的可能。
针对上面的问题,这里介绍两个系统:TMC,hotkey
TMC是有赞公司的一个多级缓存解决方案,针对redis热点 key,进行了多级缓存。正常情况下数据是保存到 redis 的,但当key 变为热点 key 后,数据就会被缓存到本地。这段逻辑包装在了 jedis客户端,所以基本对应用是透明的。
hotkey是京东零售的一个解决方案, 不仅仅针对的是 redis 缓存 key 问题,而是对资源进行了一次抽象,比如页面请求,接口等,只需要将这些资源抽象为一个 key, 然后调用 SDK, 这个 SDK 会就会返回你这是否是一个热 key,根据结果可以做自定义的处理。 因此这个 SDK 是侵入的。
两个系统有一些相似的地方,都是上传 key 调用情况,然后由 server 端根据预先定义的 rule进行判断,如果符合了热 key 条件,就通知到到所有使用这个 key 的应用。由应用做进一步的处理。
思考
以上两个应用都是不错的解决方案,但都需要提前定义规则或者阈值,这个阈值的定义就需要经验了,定的大了不行,定的小了也不行。 可是每个系统情况不一样,对于redis来说,不同的 Key有不同的数据结构,即使数据结构相同,数据值的大小也不一样,所以相同 QPS下,对 redis 的压力也不一样,
对于一个高并发系统来说,熔断,降级,限流,超时控制是保护系统的不二法门,但是基本都需要提前设置一个阈值,如果对系统不熟悉,很难预估这个阈值,所以需要一种机制,可以根据程序运行时的一些情况,来实时计算这些阈值,比如我们可以定义一些指标,比如响应时间,QPS,错误率, CPU,内存使用等,当随着请求量的增加,上面的指标开始恶化的时候,再开启相应的保护。