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

作者

wc的一些事一些情

来源

https://www.cnblogs.com/wcd144140/p/9782823.html

提到“微服务”,我相信网上各种“微服务”的演变案例都会给人一种“因大而分”的前提错觉,这可能会导致许多的“小白”产生没有机会接触“大项目”而对“微服务”可望而不可及也。当然,这种错觉的产生可能更多来源自于各种“微技术”的“层出不穷”所以“眼花缭乱”,例如Spring Cloud。虽然“大项目”机会不多,但也阻止不了“钉子们”通过教程把微技术跑一遍来装饰自己可以“微”起来的自信。

“微”只是一种正常思维逻辑

想当年,入行如赶集,同样作为小白,能把SSH框架跑一遍竟然能给自己带来无比强大的工作自信。谁没个“资本”年龄,只可惜自身的“浮躁”逼退了当年追求“本质”的淡定和沉稳。在网互联网崭露头角的年代,系统的焦点可能不在于“单体”应用的“横向分布”,更多在于对整体业务的“竖向分层”。无论横分还是竖分,“分”的本质其实就是因为“重”。“分而治之”应该算是人类最基本的思维逻辑。只不过“分”的具体实现还得归咎于站在我们对立面的是什么问题。

互联网是把“业务”从线下往线上迁移的主要推力,在这个互联网初始发展阶段,需要体现的可能是线上业务的完整性,因此业务的厚度成为了瓶颈,所以对业务逻辑层次的垂直划分可能是当时的关键解。随着移动互联网的普及,“线上业务”已经成为主流,业务的“厚重”已经积累到了另外一种层次,单纯的“竖向分层”已经无法满足厚重业务的积累和支撑。业务横向分解成为了突破口。大量“分布式”方案油然而生,包括“微服务”。

从许多“大而微”的初始现象来看,确实很容易把“大”和“微”联系在一起,这也是“大”企业走在时代前沿面对“不确定性机会”所“创造”的现象。历史可以很轻易地给人一种“知其所行”的大局视野,但时代演员却很容易被局限当前。我个人觉得“微服务”的本质就是一种正常的思维,是一种基本解决问题的思路。

“微服务”并非新招式,跟二十六种常用面向对象设计模式一样,随着时代经验的积累会成为我们解决问题的“基准招式”。因此也可以大概推测,未来的发展离不开“微服务”思维模式的导向,例如项目或组织的管理模式都可能会发生变化,或者说已经在悄悄地改变。如果说“微服务”确实像我分析的是一种思维模式,那就不会有大项目和小项目之分了。

逻辑思维

“微服务”模式小案例

在工作过程中,大项目毕竟少数,小项目才是考验技术人“接地气”的表现所在。有一天,我接到了一个小规模的“话费充值系统”需求,没有太多复杂功能和逻辑的描述,就是一个能让用户在上面自助充值的系统。剩下的理解,靠的就是自身工作经验的功力了。面对这样的需求,我首先想到的就是这个关键业务流程:

话费充值流程

这个流程说简单可以简单,说复杂可以“媲美”电商系统,例如“充值金额”相当于商品,“充值”相当于购物,“订单”跑不掉,“充值话费”类比物流。各种电商该有的“边界问题”几乎都要考虑,规模虽小,但五脏都得要有。至于“五脏”有哪些,这得根据业务的边界范围去划分“业务领域”了,先来根据自己的经验尝试一把:

话费充值系统领域划分

这种业务划分方式多少跟电商系统有点类似,直接呈现的是业务模型。根据“微服务”思维,每个领域都是一个独立的服务个体单元,每个服务“对象”又有自己的“属性”和“行为”:

系统服务设计

每个服务的属性有“服务标识”、“服务名称”等,当然服务有自身的各种行为(更多以API体现),各种系统外部动作都是通过服务之间的“合作”来完成:

业务流程设计

用户查看充值金额:接查询商品服务(“充值10元到账12元”,“充值100元到账106元”,......);

用户发起话费充值:订单服务接收请求→订单服务查询商品信息(商品ID)→订单服务向支付服务下支付订单→订单服务向充值服务下充值订单→订单服务自身下商品订单;

用户支付:支付网关(外围)接受请求→回调支付服务通知支付结果→支付服务更新支付订单状态→支付服务向充值服务发起充值→充值服务向充值网关(外围)发起充值并更改充值订单状态;

订单对账:定时支付网关对账、定时充值订单对账:

对账服务行为

从以上流程可以看出,每个服务都有自己专注的“职能”,每个应用业务流程有需要1或N个服务的交互才能完成,每个服务都有自己独立的“数据源”,互不干扰。由于系统的初期规模预期比较小,可能每天就那么数百笔订单甚至可能更少,如果我们每个服务都需要“物理隔离”,未免有点大题小做。因此,项目初期我们按“单体”模式实施:

“单体”应用实施

所谓的“单体”,即把所有服务代码结合一个“项目”打包发布,也就是一个“普通”的项目并且共用一个数据库,但每个服务的表名都有服务的标识(约定),例如商品服务的相关表名以“KW_GOODS_XXX”命名,订单服务的相关表名以“KW_ORDER_XXX”命名,支付服务的相关表名以“KW_PAYMENT_XXX”命名,充值服务的相关表名以“KW_RECHARGE_XXX”命名,对账服务的相关表名以“KW_ACCOUNT_XXX”命名,服务之间决不能跨越服务操作数据库表,必须按照“业务流程设计”调用,所以“单体”只是体现在物理实施层面,逻辑层面始终保持着“微服务”的分布式特性,保留了各种不用修改一行代码即可灵活扩展的可能性:

服务协作示范

可能有人会问,“单体”模式的服务调用怎么调?“分布式”模式又是怎么调?怎么确保扩展时服务代码调用层面的不变?用的是什么技术?这篇随笔就先不谈太多的技术,服务的调用过程我大概通过伪代码图术一下:

服务调用代理

服务之间协作的“透明化”关键在于把“微服务”灵活特性所导致的“变化”打包封装起来,就是以上伪代码的DiscoveryClient调用代理。DiscoveryClient在技术框架内维护了所有服务的信息(Service Data Cache Container),而服务信息的加载方式是服务解耦的关键所在。

首先,框架通过本地扫描的方式把所有本地服务信息扫描并加载至“服务容器”(本地扫描LocalService)。其次,框架会检测本地的“服务信息”配置文件并加载至容器(静态解析)。最后,框架会根据配置前两步所加载的服务信息判断是否存在“发现中心服务”并动态地周期性向“发现中心”更新服务信息(动态解析)。

因此,无论是单体应用部署还是分布式应用部署,对服务调用是透明的,保留了整个系统的灵活扩展性。到这里,整个系统的设计基本完,完整的系统架构图如下所示:

单体实施

以上系统在无任何优惠的正常运行下,确实只能算得上小规模,一台服务器的单体部署模式足以支撑,但在每月会员日所推出“充100元送10元”商品的时候,单体应用就显得有点力力不从心了,商品服务访问量的增加(看得人多了)已经影响到了其它服务的稳定性,并且考虑对账的稳定性(以免充值不到账引起投诉),决定把商品服务和对账服务独立(进程)部署。通过加入网关(Nginx)进行服务分发(服务解耦):

分布式实施-1

在运营过程中,公司为了“流量经营”,不惜下血本推出“充100元送50元”的商品,系统再一次受到严峻的考验,为了业务质量,不得不把所有服务独立(进程)部署,增加支撑力度:

分布式实施-2

不知道是不是老板喝多了还是运营短路了,竟然提个“充值100元送100元”的商品,并明天上线,系统峰值支撑并发量的预测已经超出了我的想象力,我能做的只有这样了:

分布式实施-3

系统从业务规模来看确实存在大小之分,但从设计思想层面,系统是没有大小之分。以上“戏路”都是以服务为单元进行灵活扩展,其实业务的最小力度是服务的具体行为—API,每个API都是服务的一个独立行为,例如查询、变更等,完全符合“命令查询职责分离(CQRS)模式”的设计,按服务这种API粒度进行横向分解同样可行,例如“支付服务”存在支付订单查询API、支付订单下单API、支付结果通知接收API,我们可以通过读写特性把查询API和变更类API进行分离,同样可以以面向“消费对象”的角度进行分解:

服务灵活扩展范例

如果某些业务存在服务链复杂的话(例如商品订单),还可以自定义“编排服务”解耦“基础服务”的复杂度:

服务编排实施范例

学习总结

如果细心点可以从以上案例发现,我的整个项目开发过程跟传统的可能会有点区别,什么区别呢?这里没有突出太多的实体对象设计或者表结构设计,更没有突出所谓的“三层结构”设计,而是直接从业务角度触发划分“业务对象”,而我们的服务呈现的是根据业务领域划分的“对象”描述,与传统按“数据实体”划分的设计模式还是有一定的区别,从需求设计到软件设计和开发都是“业务模型”最原始和最直观的呈现,保证了业务准确性并减少了变更的风险成本,同还大大地降低了项目的沟通成本。

这种思想有一个更加专业的术语叫“领域驱动设计”。我深知自己距离所谓的“微服务”或者“领域驱动设计”还有一大段距离,并且以上案例还可能存在诸多的细节问题,但这种类似的思想确实是我自身从业务中摸爬滚打并逐步思考和沉淀而形成的设计习惯。不是别人说什么就做什么,而是通过实践去思考和领悟并向真正的源头的“大师们”学习。

END

原文发布于微信公众号 - 纯洁的微笑(keeppuresmile)

原文发表时间:2018-10-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏理论坞

尼尔森十大可用性原则知多少?

尼尔森(Jakob Nielsen)是一位人机交互学博士(Technical University of Denmark in Copenhagen), 于19...

19930
来自专栏带你撸出一手好代码

做游戏与web的区别 - 服务器篇【1】

在一间游戏公司的两个部门待过, 前一个部门以做web开发为主,后一个部门做游戏开发,我在两边都是做后端的。

27720
来自专栏开源优测

从0到1:测试工程师应该具备的基本功底

今天就测试基础知识进行分享,从几个层面来分享软件测试从业者应该具备什么样的基本功底。 笔者针对测试从业者必须掌握的基本功做了个分层: 1、操作系统层 在这个层面...

304100
来自专栏Kirito的技术分享

以Dubbo为例,聊聊如何为开源项目做贡献

Github 上有众多优秀的开源项目,大多数 IT 从业者将其当做了予取予求的工具库,遇到什么需求,先去 Github 搜一把,但有没有想过有一天自己也可以给开...

15130
来自专栏云计算认知升级

【腾讯云的1001种玩法】十分钟轻松搞定云架构之一 :从上云开始

本文是 【十分钟轻松搞定云架构】的第一节:从上云开始,从这节开始,我们来一起学习云端架构。

336110
来自专栏鹅厂网事

海量数据存储硬件平台解决思路

"鹅厂网事"由深圳市腾讯计算机系统有限公司技术工程事业群网络平台部运营,我们希望与业界各位志同道合的伙伴交流切磋最新的网络、服务器行业动态信息,同时分享腾讯在网...

70450
来自专栏DevOps时代的专栏

利用 Jenkins Pipline 来编排 DevOps 工具链

讲师 | 林栗 编辑 | 黄晓轩 讲师简介 林栗 Micro Focus DevOps工程师 擅长组织级持续集成架构设计与实施,专注于软件配置管理、DevOp...

65260
来自专栏编程坑太多

『高级篇』docker容器来说软件架构的进化(二)

13020
来自专栏纯洁的微笑

微服务2.0技术栈选型手册

一晃三年过去,微服务技术生态又发生了巨大变化,容器,PaaS,Cloud Native,gRPC,ServiceMesh,Serverless等新技术新理念你方...

53330
来自专栏企鹅号快讯

年前爆炸一波!小程序视频功能来了!

好久不见,昨天小指南才说了小程序很久没有大动作,这不昨晚的深夜更新又啪啪啪的打脸了。一口气来了四个能力更新,赶紧听小指南说说吧~ ? --升级实时音视频录制及播...

27970

扫码关注云+社区

领取腾讯云代金券