「微服务的细节」—— 如何支持多协议?
在实际场景中,你有很多理由需要在微服务体系中支持多协议,如何支持呢?
1. 端口偏移
设想一个场景
你的微服务体系中已经有一套统一的 RPC 协议,
但是不能满足新的需求了,你需要引入一种全新的协议,并且无法在当前协议上进行扩展,
那么就可以采用端口偏移的方式。
实现方式也很简单,例如当前协议的端口号为 port,那么就可以约定 port+5 为新协议的端口号。
2. 协议探测
设想一个场景
你的微服务体系比较乱,不同的业务线使用不同的 RPC 协议,
但是不同业务线互调的需求越来越多了,你需要提供一套统一的体系来治理这个问题,
那么就可以在统一的框架中采用协议探测的方式。
brpc是个典型案例,记得戈君老师在一次直播中也谈到:同一端口多协议支持这一特性为 brpc 在百度内的推广扫清了很多障碍。
实现方式在官方文档中也有清晰的描述:
brpc server 一个端口支持多种协议,大部分时候这对部署和运维更加方便。由于不同协议的格式大相径庭,严格地来说,一个端口很难无二义地支持所有协议。出于解耦和可扩展性的考虑,也不太可能集中式地构建一个针对所有协议的分类器。我们的做法就是把协议归三类后逐个尝试:
第一类协议:标记或特殊字符在最前面,比如baidu_std,hulu_pbrpc 的前 4 个字符分别是 PRPC 和 HULU,解析代码只需要检查前 4 个字节就可以知道协议是否匹配,最先尝试这类协议。这些协议在同一个连接上也可以共存。
第二类协议:有较为复杂的语法,没有固定的协议标记或特殊字符,可能在解析一段输入后才能判断是否匹配,目前此类协议只有 http。
第三类协议:协议标记或特殊字符在中间,比如 nshead 的 magic_num 在第 25-28 字节。由于之前的字段均为二进制,难以判断正确性,在没有读取完 28 字节前,我们无法判定消息是不是 nshead 格式的,所以处理起来很麻烦,若其解析排在 http 之前,那么<=28 字节的 http 消息便可能无法被解析,因为程序以为是“还未完整的 nshead 消息”。
考虑到大多数链接上只会有一种协议,我们会记录前一次的协议选择结果,下次首先尝试。对于长连接,这几乎把甄别协议的开销降到了 0;虽然短连接每次都得运行这段逻辑,但由于短连接的瓶颈也往往不在于此,这套方法仍旧是足够快的。在未来如果有大量的协议加入,我们可能得考虑一些更复杂的启发式的区分方法。
代码也写的很优雅:https://github.com/apache/brpc/blob/master/src/brpc/input_messenger.cpp#L76-L167
3. 元数据路由
如果是公有云产品,例如 MSE 和 TSF,需要考虑标准化和兼容性,那么可以基于元数据路由来实现。
在实例注册时将支持的“协议”和“端口”作为“元数据”带上来,在调用的时候通过元数据路由筛选出支持该协议的实例。
版权声明: 本文为 InfoQ 作者【袁世超】的原创文章。
原文链接:【http://xie.infoq.cn/article/c536d686fb8b5531850be0812】。文章转载请联系作者。
评论