我的微服务之路

还记得在14年的某一天,为生活所迫,走上了程序员这条路。到如今,已是第六个年头了。所幸的是,写代码是我人生所经历的各种职业中最喜欢的职业。如无意外,我会一直做下去,直到生命终止。2019年即将过去,写下这篇文字以作纪念,也希望给阅读这篇文字的同学们一些启发。特别是想要转行程序员的,或者.NET、PHP想转Java方向的程序员,希望能够给你们一点鼓励和帮助。

微服务是一个热门的话题,作为一个在微服务上面实践了4年多的老司机,说一下我的经历。

15年我入职了一家新公司,负责一个商城系统的开发。鉴于以往的小小经验,为了解决多业务系统共用一套用户的需求。把用户、用户组、组织机构、角色权限和Token从整个系统中独立了出来。商城以及管理系统作为另外一个独立的系统存在。后面又陆续开发了几个系统,他们之间采用http协议进行接口的调用。无疑,这个仅仅是一个非常简陋和原始的多服务架构。为什么不算微服务架构呢?首先,单个服务仍然比较庞大。然后也没有RPC框架,就是httpClient直接上。更没有什么服务注册/发现、配置中心、网关、限流/熔断、监控了,简直要啥没啥。不过这次把各个业务拆开来,为后面真正的微服务化奠定了基础,同时也走出了重要的一步。由于采用的是.NET技术栈,所以后面在往真正的微服务系统转化的路上踩了不少坑。真是说来话长,这里暂且略过不表。

17年我从北京回到了杭州,进入了一家互联网初创公司担任架构师。初创公司嘛,前期都很简陋,包括公司的业务系统也是。我的任务就是重新设计公司的业务系统,要满足xxx和yyy,还有zzz。总之,要求相当地高大上。那个时候,微服务的概念已经蛮流行了,对于微服务,我也有了一些自己的理解和那么一丢丢的实践经验。为了满足老板这个宏大的远景蓝图,没说的,就是微服务,就是前后端分离。几个架构图一画,果不其然,老板非常满意,转头就拿去忽悠投资人去了……

我们一个规划了四个中心:
用户中心,包含资源、用户、用户组、组织机构、角色权限、租户、验证,共拆了7个服务。
消息中心,负责消息通知、短信、邮件、应用内消息等,没有进一步拆分服务。
支付中心,负责对接支付宝、微信、银联等支付通道,也没有更多的拆分。
订单中心,拆分成订单领域服务和订单管理服务两个服务。

因为技术团队是Java向,所以自然而然地采用了Spring全家桶,里面什么都有,真香。消息中心和支付中心我负责了接口设计,订单中心则只提出了领域服务和管理服务分离的原则,具体的设计是另一个架构师负责的。用户中心对我而言轻车熟路,只是增加了租户的概念,以支持多租户平台的需求。另外把资源服务搞起来,使得资源可配置。总体来说相当于用Java重新写一遍代码。在重写的过程中,由于Java语言的特性和C#还是有很多不同的地方,实现的思路也有所变化。用不同的语言来实现同一个需求,还是比较有趣的。感觉就像打开了一扇门,发现了一个新的世界。Spring boot也给了我很多的惊喜,经常会发现一些新的玩法,然后感叹一声:卧槽,居然还可以这样搞!

这一次实践,最大的问题是基础强而业务弱。那时候阿里还没有明确提出它的中台战略,而我们的系统 ,就已经有点中台的意思了。从业务需求来看,其实根本不需要微服务,有点过度设计了。事实上仅仅1年之后,这家公司就呜呼哀哉,烟消云散了。当然这个结局的主要原因在于老板而不在技术。而这些基础服务的好处,则在我之后入职的新公司得到了体现。业务所依赖的基础设施都已经建设好了,剩下的只需要关心业务的实现就够了。就像国家已经给你通了高速公路网和高铁、机场、港口什么的都建好了,地方政府只需要一门心思搞经济建设就好了。如果一个小国、穷国也这么搞,估计会把自己搞死掉。基建真的烧钱啊,咱们国家也是攒了20多年的家当,抓住了国际形势天时地利人和的机会才能这么玩一次。

对于微服务系统来说,我们关注这三点就足够了:一是微服务组件的选型,二是服务如何划分,三是数据一致性问题如何解决。

微服务组件的选型问题,其实我也没有太多的建议,因为我也仅仅接触过Spring Cloud这一套。对我而言,Spring Cloud是比较成熟、易用的解决方案。支持的语言也很多,即使不支持,也很容易自己照着别的语言造个轮子来用。不过我到现在都没有用过任何的配置中心,而是简单搞了个配置数据库,在jenkins里面通过脚本根据环境来替换配置。一直想自己搞个简单的配置中心,但一直没想好实现哪些功能,就一直搁置了。

第二个问题和第三个问题其实是存在相关性的。我的建议是,服务可以按逻辑是否完备(和其他服务不存在逻辑依赖)的标准进行最小粒度的划分。特别是领域服务和领域上的业务管理服务,建议分拆成多个服务。因为领域数据相对稳定,而业务逻辑则很容易发生变化,分拆后既能有效提升领域服务的稳定性,同时也方便业务需求的随时变更。数据分库可以按领域来,譬如订单数据 和订单流程处理数据就没必要分。也就是说,正常情况下,应该是多个服务共享一个数据库。

对于数据一致性问题,我的经验就是:
1、能够使用数据库事务保证的,就用数据库事务。这也是为什么数据库按领域分的原因。
2、跨库数据就是MQ一把梭,保证数据的最终一致性就可以了。如果是服务器掉电之类的意外导致的丢数据引起的数据不一致,我的方案就是人工修复。只要数据可推导,就不存在不可修复的数据,人工跑个脚本,分分钟修好。

最后,我要和大家分享一下我的开源项目:xuanbg (Brian Xan) · GitHub。目前已经完成了上文提到的消息中心的服务端和用户中心的大部分服务端,后续还会增加一个财务中心以及它们的客户端。我希望这个项目能够为大家提供一些可组合的、开箱即用的微服务基础设施,以降低转换到微服务架构的开发成本。

已完成部分清单如下:
用户服务:https://github.com/xuanbg/insight_user
租户服务:GitHub – xuanbg/insight_tenant: 租户服务
角色服务:https://github.com/xuanbg/insight_role
身份认证:GitHub – xuanbg/insight_auth: 身份验证服务
网关:GitHub – xuanbg/gateway: 基于Spring Cloud Gateway的微服务网关
消息中心:GitHub – xuanbg/insight_message: 消息中心服务

未完成:
资源管理服务
组织机构服务
第三方支付统一接入
结算服务(收款、付款、退款)
资金账户服务
用户账户服务
钱包管理服务

多租户平台管理客户端
租户系统管理客户端
财务中心管理客户端