写点什么

Redis 不止缓存!原来在微服务领域也做出了这么大的贡献

发布于: 2021 年 06 月 12 日
Redis不止缓存!原来在微服务领域也做出了这么大的贡献

前言

说到 redis,可能大家的脑海中蹦出的关键词是:NoSQL、KV、高性能、缓存等。但今天的文章从另一个角度——微服务来展开。

这篇文章的起因也是源自一次面试经历,在面试一位来自陌陌的候选人(就是那个交友的陌陌)时,他提到一点让我觉得很有意思,他说 redis 在陌陌被使用得非常广泛,除了常规的缓存外,某些场景下也当 NoSQL 数据库来使用,还用 redis 作为微服务的注册中心,甚至连 RPC 的调用协议都用了 redis 协议。

注册中心

最早了解到 redis 可以作为注册中心是从 dubbo 的源码中看到,但一直也没有过多的了解,因为从没听说哪家公司使用 redis 来做服务发现。

在 dubbo 中使用 redis 来做服务发现还是挺简单的,引入 jedis 依赖,将注册中心地址改为 redis 地址即可:

<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version></dependency>
复制代码


dubbo.registry.address=redis://127.0.0.1:6379
复制代码

注册上来的数据是这样,类型是 hash

/dubbo/${service}/${category}
复制代码

/dubbo/com.newboo.sample.api.DemoService/consumers/dubbo/com.newboo.sample.api.DemoService/providers
复制代码

hash 数据结构下保存的 key 是注册上来的 url,value 是过期时间

127.0.0.1:6379> hgetall /dubbo/com.newboo.sample.api.DemoService/providers1) "dubbo://172.23.233.142:20881/com.newboo.sample.api.DemoService?anyhost=true&application=boot-samples-dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.newboo.sample.api.DemoService&metadata-type=remote&methods=sayHello&pid=19807&release=2.7.8&side=provider×tamp=1621857955355"2) "1621858734778"
复制代码

从理论上来说,注册中心只要符合数据存储、监听推送变更、心跳检测这几个基本的功能即可。

以 dubbo 为例看下 redis 是如何利用自身特性来完成注册中心的功能( 以 dubbo 2.7.8 版本为例):

  • 服务注册 provider 在服务注册时,将服务提供方的 url 写入/dubbo/${service}/providers 下,数据类型为 hash,key 为提供方 url,value 为 key 的过期时间,默认为 60s,可配置写入完成后以/dubbo/${service}/providers 为 key 调用 publish 命令发布一个 register 事件 provider 在初始化时起一个单独的线程每隔 1/2 过期时间(默认 30s)时对 provider 进行重新重新注册并发布 register 事件

  • 服务发现获取匹配/dubbo/${service}/*的 key(此处用到了 keys 命令),拿到的有这几种:/dubbo/${service}/providers/dubbo/${service}/routers/dubbo/${service}/configuators /dubbo/${service}/*拿到的 key 进行 hgetall,拿到真实的 provider 列表以及配置等数据,进行组装、匹配同时对每个 subscribe 的服务单独开一个线程,对/dubbo/${service}执行 psubscribe 命令阻塞等待有事件发生

从源码和测试来看,dubbo 的 redis 注册中心不能直接用于生产环境,原因有如下两点:

  • 使用了 keys 命令,会阻塞单线程的 redis,keys 执行期间,其他命令都得排队

  • 没有心跳检测这个功能,我测试了 provider 被 kill -9 杀死后,consumer 是无法感知的。但从实现上来看是想通过存储的过期时间来判断服务是否可用,即需要对比 url 对应的 value 与当前的时间,如果过期应被剔除,但这部分貌似没有实现完整

虽然 dubbo 的 redis 注册中心生产不可用,但这并不影响他可以构建一个生产可用的注册中心,陌陌就是个很好的例子。

RPC 调用协议

redis 协议作为 RPC 调用协议也是陌陌同学告诉我的,当时我问了他两个问题:

  • 为什么选择 redis 协议作为 RPC 调用协议

  • redis 协议如何透传类似 header 的隐式参数

第一个问题的答案也比较出乎意料,他说是为了跨语言调用,当时觉得只有 http、gRPC 等协议做到了跨语言,redis 协议跨语言也是第一次听说。但仔细一想,确实没毛病,现在哪个后端语言没有实现 redis 的客户端呢?

之所以 redis 协议能够做到跨语言,这也全仰仗它的设计非常简洁,易于实现,详细协议内容可以参考这个链接:

http://redisdoc.com/topic/protocol.html

我就举一个例子来证明 redis 协议简洁到了什么程度,这是我很久之前就关注的一个项目

https://github.com/jdp/redisent

它是一个 php 实现的 redis 客户端,只有一个 php 文件,共 196 行,这 196 行包含了注释,变量定义,链接建立等,真正解析协议的代码非常少,请求的编码和发送只用了 17 行代码,解析返回的代码只有 58 行!正如项目的介绍那样:simple, no-nonsense

第二个问题回答的和我的预期一致,从 redis 协议的层面暂时无法支持类似 header 的隐式参数,但陌陌的 RPC 框架是自研的,所以他们在框架层解决了这个问题,序列化他们选择了 json,如果要透传 header 参数,框架将参数组装到传输体中去。

遗憾的是 dubbo 中的 redis 协议实现并不完整,无法暴露 redis 协议,只能调用,所以测试也只能测试 client 连接到 redis 服务器进行 get、set 调用,意义不大。

总结

redis 目前是个用途非常广泛的存储组件,虽然在微服务领域它不是主流,但这也给我们提供了一种思路,至少这条路是可以走通的。

原文链接:https://mp.weixin.qq.com/s/kKAAf_6vKn-KHvr9YMNDQQ

前言

说到 redis,可能大家的脑海中蹦出的关键词是:NoSQL、KV、高性能、缓存等。但今天的文章从另一个角度——微服务来展开。

这篇文章的起因也是源自一次面试经历,在面试一位来自陌陌的候选人(就是那个交友的陌陌)时,他提到一点让我觉得很有意思,他说 redis 在陌陌被使用得非常广泛,除了常规的缓存外,某些场景下也当 NoSQL 数据库来使用,还用 redis 作为微服务的注册中心,甚至连 RPC 的调用协议都用了 redis 协议。

注册中心

最早了解到 redis 可以作为注册中心是从 dubbo 的源码中看到,但一直也没有过多的了解,因为从没听说哪家公司使用 redis 来做服务发现。

在 dubbo 中使用 redis 来做服务发现还是挺简单的,引入 jedis 依赖,将注册中心地址改为 redis 地址即可:

<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version></dependency>
复制代码


dubbo.registry.address=redis://127.0.0.1:6379
复制代码

注册上来的数据是这样,类型是 hash

/dubbo/${service}/${category}
复制代码

/dubbo/com.newboo.sample.api.DemoService/consumers/dubbo/com.newboo.sample.api.DemoService/providers
复制代码

hash 数据结构下保存的 key 是注册上来的 url,value 是过期时间

127.0.0.1:6379> hgetall /dubbo/com.newboo.sample.api.DemoService/providers1) "dubbo://172.23.233.142:20881/com.newboo.sample.api.DemoService?anyhost=true&application=boot-samples-dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.newboo.sample.api.DemoService&metadata-type=remote&methods=sayHello&pid=19807&release=2.7.8&side=provider×tamp=1621857955355"2) "1621858734778"
复制代码

从理论上来说,注册中心只要符合数据存储、监听推送变更、心跳检测这几个基本的功能即可。

以 dubbo 为例看下 redis 是如何利用自身特性来完成注册中心的功能( 以 dubbo 2.7.8 版本为例):

  • 服务注册 provider 在服务注册时,将服务提供方的 url 写入/dubbo/${service}/providers 下,数据类型为 hash,key 为提供方 url,value 为 key 的过期时间,默认为 60s,可配置写入完成后以/dubbo/${service}/providers 为 key 调用 publish 命令发布一个 register 事件 provider 在初始化时起一个单独的线程每隔 1/2 过期时间(默认 30s)时对 provider 进行重新重新注册并发布 register 事件

  • 服务发现获取匹配/dubbo/${service}/*的 key(此处用到了 keys 命令),拿到的有这几种:/dubbo/${service}/providers/dubbo/${service}/routers/dubbo/${service}/configuators /dubbo/${service}/*拿到的 key 进行 hgetall,拿到真实的 provider 列表以及配置等数据,进行组装、匹配同时对每个 subscribe 的服务单独开一个线程,对/dubbo/${service}执行 psubscribe 命令阻塞等待有事件发生

从源码和测试来看,dubbo 的 redis 注册中心不能直接用于生产环境,原因有如下两点:

  • 使用了 keys 命令,会阻塞单线程的 redis,keys 执行期间,其他命令都得排队

  • 没有心跳检测这个功能,我测试了 provider 被 kill -9 杀死后,consumer 是无法感知的。但从实现上来看是想通过存储的过期时间来判断服务是否可用,即需要对比 url 对应的 value 与当前的时间,如果过期应被剔除,但这部分貌似没有实现完整

虽然 dubbo 的 redis 注册中心生产不可用,但这并不影响他可以构建一个生产可用的注册中心,陌陌就是个很好的例子。

RPC 调用协议

redis 协议作为 RPC 调用协议也是陌陌同学告诉我的,当时我问了他两个问题:

  • 为什么选择 redis 协议作为 RPC 调用协议

  • redis 协议如何透传类似 header 的隐式参数

第一个问题的答案也比较出乎意料,他说是为了跨语言调用,当时觉得只有 http、gRPC 等协议做到了跨语言,redis 协议跨语言也是第一次听说。但仔细一想,确实没毛病,现在哪个后端语言没有实现 redis 的客户端呢?

之所以 redis 协议能够做到跨语言,这也全仰仗它的设计非常简洁,易于实现,详细协议内容可以参考这个链接:

http://redisdoc.com/topic/protocol.html

我就举一个例子来证明 redis 协议简洁到了什么程度,这是我很久之前就关注的一个项目

https://github.com/jdp/redisent

它是一个 php 实现的 redis 客户端,只有一个 php 文件,共 196 行,这 196 行包含了注释,变量定义,链接建立等,真正解析协议的代码非常少,请求的编码和发送只用了 17 行代码,解析返回的代码只有 58 行!正如项目的介绍那样:simple, no-nonsense

第二个问题回答的和我的预期一致,从 redis 协议的层面暂时无法支持类似 header 的隐式参数,但陌陌的 RPC 框架是自研的,所以他们在框架层解决了这个问题,序列化他们选择了 json,如果要透传 header 参数,框架将参数组装到传输体中去。

遗憾的是 dubbo 中的 redis 协议实现并不完整,无法暴露 redis 协议,只能调用,所以测试也只能测试 client 连接到 redis 服务器进行 get、set 调用,意义不大。

总结

redis 目前是个用途非常广泛的存储组件,虽然在微服务领域它不是主流,但这也给我们提供了一种思路,至少这条路是可以走通的。

原文链接:https://mp.weixin.qq.com/s/kKAAf_6vKn-KHvr9YMNDQQ

如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【面试】即可得到一份 Java 核心知识点整理与一份面试大礼包!另有更多技术干货文章以及相关资料共享,大家一起学习进步!


发布于: 2021 年 06 月 12 日阅读数: 18
用户头像

领取资料添加小助理vx:bjmsb2020 2020.12.19 加入

Java领域;架构知识;面试心得;互联网行业最新资讯

评论

发布
暂无评论
Redis不止缓存!原来在微服务领域也做出了这么大的贡献