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

提到“微服务”,我相信网上各种“微服务”的演变案例都会给人一种“因大而分”的前提错觉,这可能会导致许多的“小白”产生没有机会接触“大项目”而对“微服务”可望而不可及也。当然,这种错觉的产生可能更多来源自于各种“微技术”的“层出不穷”所以“眼花缭乱”,例如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进行分离,同样可以以面向“消费对象”的角度进行分解:

服务灵活扩展范例

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

服务编排实施范例

学习总结

如果细心点可以从以上案例发现,我的整个项目开发过程跟传统的可能会有点区别,什么区别呢?这里没有突出太多的实体对象设计或者表结构设计,更没有突出所谓的“三层结构”设计,而是直接从业务角度触发划分“业务对象”,而我们的服务呈现的是根据业务领域划分的“对象”描述,与传统按“数据实体”划分的设计模式还是有一定的区别,从需求设计到软件设计和开发都是“业务模型”最原始和最直观的呈现,保证了业务准确性并减少了变更的风险成本,同还大大地降低了项目的沟通成本。这种思想有一个更加专业的术语叫“领域驱动设计”。我深知自己距离所谓的“微服务”或者“领域驱动设计”还有一大段距离,并且以上案例还可能存在诸多的细节问题,但这种类似的思想确实是我自身从业务中摸爬滚打并逐步思考和沉淀而形成的设计习惯。不是别人说什么就做什么,而是通过实践去思考和领悟并向真正的源头的“大师们”学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容