查看原文
其他

有赞服务化架构演进

徐志毅 搜云库技术团队 2019-04-07
搜云库互联网/架构/开发/运维关注

服务化是互联网公司成长的必经之路。随着微服务的兴起,很多公司如火如荼的搞起了自己的服务化,有兴奋有无奈。那服务化该怎么做,该做什么?本文试图从有赞的发展历程来体会服务化发展。

有赞史

有赞成立于2012年11月,成立初期以社群电商产品为核心,2015年实现商业化,快速发展为一家2000+人的2B Saas服务公司,以电商平台(微商城)和新零售(有赞零售、有赞美业、有赞餐饮)为主要发展方向。技术总是随着业务的繁荣不断演进,从一个差点死掉的初创公司到如今创造的电商+新零售生态,有赞经历了从单体应用到服务化较为成熟演进过程。

从时间跨度上我们可以将其发展大致分为四个阶段:单体应用时期(2013-2015)、服务化初期(2015-2016)、服务化发展(2016-2017),服务化成熟(2017-至今)。

公司创立初期,选择PHP作为核心开发语言,因为其开发速度快,试错成本低。这也是很多创业团队的选择。一旦业务成型,用户体量变大,开发团队扩张,围绕PHP开发的问题便逐渐暴露,如项目过于庞大、难以维护,发布影响面大、开发效率低等问题。

为了解决这些问题,2015年公司开始进行服务化拆分,首先是纵向拆分,将核心的功能从iron(核心的PHP应用)里面拆出来,如用户中心、店铺中心、商品中心等,服务化应用采用java开发。服务拆分后,首先需要解决的便是服务间调用问题,随着新技术语言的引入,以及有赞云业务的发展,跨语言调用的问题也日益突出。如何解决服务化的这些问题呢?下面详细分析有赞的服务化之路。

单体应用时代

为什么开始不把业务拆分好呢?可能有人会有这样的疑惑。就企业而言,追求的是快速底成本验证产品想法并占领市场,进行低成本试错;就开发而言,业务的发展是未知的,过度设计的架构可能会适得其反。有赞从一开始的月饼、代付、送礼等社交营销玩法做到Saas级电商平台,这一路的发展有不少心酸。

在早期,公司的系统架构图如下图所示,核心展示层、业务层都在强耦合在iron应用之中。谈到iron,不知曾让多少有赞人泪崩。“代码又冲突了!?”,“发布又翻车了!”,“服务又回滚!?”。没错,这就是iron。

iron是有赞的核心PHP应用,最初几乎承载着所有的核心业务。目前iron在gitlib上已经有18G+之大,当有一批新同事进来时,如果有多人全量clone(不指定depth)很容易导致gitlib服务器宕机,因此目前clone iron必须指定depth。

为什么iron发展到这么大?为什么不早点拆分呢?主要是因为有赞初期的业务快速发展导致。在拆分老应用时,要保证新功能的快速迭代,对于一个高速发展的创业型公司,在那个历史阶段没有足够的资源与时间去迁移。所以iron的庞大似乎有着历史的必然性。

随着业务的快速增长和研发团队的不断扩张,单体应用的弊端不断暴露出来。如团队协作成本增加,开发、测试、部署不同模块相互耦合,导致系统稳定性下降等。在此背景下,服务化拆分,箭在弦上。

服务化初期

Iron拆分

2015年7月,公司决心启动了“乾坤大挪移”项目。核心目标是便是拆分iron,将核心业务从PHP向Java迁移,并逐步建立完善的服务治理体系,迈向了服务化的第一步。

“乾坤大挪移”项目的启动,标志着有赞正式进入服务化阶段。服务化拆分第一个要解决的就是服务调用的问题,且一开始就遇到了跨语言调用的问题。最初的服务化调用方案如下,Java服务之间调用采用Dubbo协议,PHP与Java服务之间调用采用http协议。然而在该模式下存在不少问题,如Java服务开发者需要维护两套不同的接口,增加了额外的工作量,并不友好;PHP无法支持长链接,会有大量的时间耗费在建立链接上,并且大量的短链接对于后端服务来说也是很大的负担。

服务化初期.jpg

服务化发展

Nova兴衰

随着服务的拆分,公司需要一套跨语言调用的解决方案,于是Nova兴起。Nova是基于thrift协议而制定的有赞RPC协议。通过这个协议,解决公司跨语言交互的问题,从而形成公司的Nova框架。从狭义来讲,Nova是一种私有的通信协议;从广义来讲是有赞SOA架构。对Dubbo、Zan-PHP进行扩展,支持新的Nova协议。

nova.png

Nova似乎解决了跨语言的问题,但却存很多痛点:

第一,需要生成Thrift IDL,过程繁琐,可读性差,开发接受度不高;

第二,入侵性强,扩展性差,须深度定制;

第三,维护成本高,需要专门的团队保障;

除此之外,还有一个原因是公司Java服务化的发展使Java成为核心开发语言(Java开发人员相对来说,在市场上是最好招的)。使用Nova有一定的接入和学习成本,且开发人员水平不一,在Java盛行的时期,Nova逐渐变得累赘。

由于这些痛点,导致Nova的好景不长,一直被开发人员诟病,全面推动困难。因此在这个时期,出现了Dubbo和Nova协议共存的状态,Java内部采用Dubbo协议,跨语言采用Nova协议。回头来看,Nova似乎成为了历史性的过渡协议。

Tether萌芽

由于公司最初是已PHP为核心开发,业务系统还存在不少PHP应用,而PHP的多进程运行方式会带来许多问题。比如无法支持长链接,会有大量的时间耗费在建立链接上,解决后端服务频繁建立链接带来的损耗,并且大量的短链接对于后端服务来说也是很大的负担。未了解决这一问题,公司开始研发Tether。Tether主要实现了以下几大特性:

1.支持以长链接方式进行信令透传;

2.支持负载均衡,如轮询策略;

3.支持服务发现,与name_service对接;

4.支持多协议解析(nova、http等);

Tether作为PHP的长链接解决方案,独立部署在服务器上,与应用解耦,由运维统一部署管理,为后续的Sidecar发展奠定了基础。

服务化成熟

Sidecar

随着应用拆分的不断推进,有赞已从原来的PHP开发模式,形成了Node.js + Java的开发模式,逐步去Zan-PHP框架。并且随着电商云业务的发展,越来越多其他语言的需要接入,此过程需要解决的核心问题是:Node.js等其他语言如何调用Java服务?

有赞之前的跨语言使用的是Nova协议。然而在Nova一直遭诟病的背景下,如何更友好的解决这一问题呢?首先对比一下Nova协议与Dubbo协议:

Dubbo | Nova | | --- | --- | --- | | 开发语言 | Java | 跨语言 | | 序列化 | hessian | thrift RPC调用协议二次封装 | | 友好度 | 不需要IDL,更自然 | 需要IDL,接受度低 |

既然大家都习惯使用Dubbo,能不能在Dubbo的基础上实现跨语言交互呢?

答案是可以的。为了建立更友好的跨语言服务化方案,Tether再次升级。实现了对Dubbo原生协议的解析与转换,支持通过Http协议调用Dubbo服务。这次协议转化的能力升级,也意味着Tether正式成为Sidecar组件。

新协议设计

这种兼容性协议转换似乎解决了跨语言服务调用的问题,然而真正的跨语言需要有灵活高效的通用协议基础。最近Dubbo官方也一直在推动跨语言进程。其核心的难点便是协议。Dubbo协议是私有的,其服务接口都是通过Java Interface描述,其涉及的传输模型DTO也是Java POJO定义,要想成为跨语言的协议标准有一定难度。并且由于Dubbo的Attachment字段在尾部,Sidecar很难解析处理。而Sidecar形态需要面向多语言,协议问题首当其冲。通过Dubbo真正实现跨语言,新协议的设计是未来的关键。

dubbo协议.png

有赞的新协议设计目标如下:

1.多语言支持

电商云的客户可能使用多种语言进行开发,协议必须能够支持各种语言无痛、方便的接入。

2.便于解析的请求header

为提供丰富和完善的服务治理功能,便于Sidecar解析和添加信息的RPC请求header是必不可少的。

3.不改变内部业务的使用方式

有赞内部业务已经习惯了不编写IDL,直接开发微服务接口的开发方式。新的协议不能改变内部业务的开发方式和开发习惯,协议上的升级必须是业务完全无感知的。

4.方便的兼容和适配

推动业务升级是一个漫长的过程,新协议必须能够支持Sidecar自动进行新、旧协议的适配和转换,保证新旧版本协议长时间并存情况下的稳定性。

5.异步支持和高性能

当前dubbo使用的RPC协议通过链接内唯一的request ID实现了异步调用和consumer端的链接复用。新协议应当具备不亚于当前协议的性能,且必须具备支持异步调用和链接复用的能力。

6.使用规范通用的RPC协议

为降低框架的复杂度和学习成本,方便后续接入和使用通用的开源组件,同时保证框架处于规范的生态中,尽量借鉴和使用通用的协议和系列化方式,减少自己设计和开发带来的风险。

7.实现简单

为降低使用新协议带来的风险,新版协议应当避免复杂的实现,Java框架仅需经过简单的改造或增加拓展即可实现,减少实现复杂序列化协议带来的风险。

经过综合考虑,有赞的新rpc协议将以HTTP/2为基础,参考grpc协议。并兼容老的dubbo协议,保证协议的通用性和可拓展性。

总结

如开篇所说,“服务化,只有经历过才能领悟“。作者遗憾没有完整经历过这些发展,本文主要参阅了很多历史文档,试图从过来人的角度简述有赞的服务化发展历程。本文描述的服务化主要在于服务调用问题上,而完整的服务化体系远不止如此,核心至少还包括服务注册与发现、服务监控、服务追踪、服务治理等方面,这些方面,有赞也付出了很多的努力。

现在的岁月静好,是因为有人替你负重前行。如今有赞的服务化体系已经比较完善,但也依然面临挑战。希望日后能在有赞的工作、学习、经历中更好的成长。本文不足之处,还望指出。

原文:https://www.jianshu.com/p/162f21ef68c0

往期精彩文章


理解大型分布式架构的演进历史、技术原理、最佳实践

Oracle推出开源轻量级 Java 微服务框架 Helidon

小型系统如何“微服务”开发

如何找到完美的以太坊区块链开发者

大数据推荐系统实时架构和离线架构

ElasticSearch优化会员列表搜索

Rabbitmq延迟队列实现定时任务

软件做异常测试?必知的22个测试点总结!

Java SQL注入危害这么大,该如何来防止呢?

还没用上 JDK 11吧,JDK 12 早期访问构建版使用

Dubbo 整合 Pinpoint 做分布式服务请求跟踪

Java并发:分布式应用限流实践

长按:二维码关注

专注于开发技术研究与知识分享

公众号回复:”进群” 加微信群深入交流

回复 JavaDocker等关键字可获得学习资料

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存