写点什么

沈剑聊微服务:先做好你的服务拆分

  • 2017-09-12
  • 本文字数:3820 字

    阅读完需:约 13 分钟

随着自动化运维等相关技术的发展,微服务变得更容易管理,这给了微服务架构良好的发展机会;同时,Docker 等容器技术的发展,使微服务架构的落地变得更加方便,这更是为其成为主流技术铺好了道路。目前各家对微服务架构都有自己的理解与落地实践。

本次 InfoQ 采访到 58 到家技术委员会主席沈剑老师,请他讲讲他对微服务架构的一些思考。沈剑老师之前任职于 58 到家,目前在 58 速运,本次分享涉及到 58 到家与 58 速运的相关内容。本文即由采访整理而成。

本次分享主要从服务化的角度来看待微服务,主要是梳理一下微服务这个概念,不做深入地讲解。

从服务化的角度看微服务

互联网架构发展的过程中,当业务复杂度剧增,数据量剧增,吞吐量剧增的时候,就会出现一些技术痛点,下边几个都是最常见的:

痛点一:代码到处拷贝

举一个最常见的业务的例子:用户数据的访问。

绝大部分公司都有一个数据库用来存储用户数据,而各个业务都有访问用户数据的需求。

各个业务线都是自己通过 DAO(Data Access Object)写 SQL 访问 user 库来存取用户数据,这无形中就导致了代码的拷贝。

抽象出一个服务层之后,有统一的一份代码,那么就解决了代码复用的问题。同时业务方通过 RPC 访问用户数据,就像调用一个本地函数一样,比如使用

复制代码
User = UserService::GetUserById(uid);

传入一个 uid,得到一个 User 实体,就像调用本地函数一样,不需要关心序列化、后端执行、网络传输、反序列化等复杂性,方便高效。

痛点二:复杂性扩散

这个内容主要讲一下下边两个点:

1、缓存导致的复杂性

随着访问量越来越高,数据库成了瓶颈,需要加入缓存来降低数据库的读写压力,于是架构中引入了缓存,由于没有统一的服务层,各个业务线都需要关注缓存的引入导致的复杂性:

  • 对于用户数据的写请求,所有业务线都要升级代码:
  1. 先淘汰 cache
  2. 再写数据
  • 对于用户数据的读请求,所有业务线也都要升级代码:
  1. 先读 cache,命中则返回
  2. 没命中则读数据库
  3. 再把数据放入 cache

这个复杂性是典型的“业务无关”的复杂性,业务方需要被迫升级。

2、分库分表导致的复杂性

数据量越来越大,数据库需要进行水平拆分,于是架构中又引入了分库分表,这时又是由于没有统一的服务层,各个业务线都需要关注分库分表的引入导致的复杂性。

这个复杂性也是典型的“业务无关”的复杂性,业务方需要被迫升级。

有了服务层之后,只有服务层需要专注关注底层的复杂性了,向上游屏蔽了细节。

痛点三:库的复用与耦合

服务化并不是唯一解决上述两个痛点的方法,另一种方法是抽象出统一的“库”。比如抽象出一个 user.so,负责整个用户数据的存取,从而避免代码的拷贝。至于复杂性,现在也只剩下 user.so 这一个地方需要关注了。

但是这时候会引入新的问题:库的版本维护与业务线之间代码的耦合

比如业务线 A 将 user.so 由版本 1 升级至版本 2,如果不兼容业务线 B 的代码,那就会导致 B 业务出现问题;
业务线 A 如果通知了业务线 B 升级,这时的业务线 B 就会去升级,但这是与它“自身业务无关”的升级。

痛点四:SQL 质量得不到保障,业务相互影响

本质上 SQL 语句还是各个业务线拼装的,资深的工程师写出高质量的 SQL 没啥问题,经验没有这么丰富的工程师可能会写出一些低效的 SQL。业务线通过 DAO 访问数据库,假如业务线 A 写了一个全表扫描的 SQL,导致数据库的 CPU100%,影响的不只是这一个业务线,而是所有的业务线

有了服务层之后,所有的 SQL 都是服务层提供的,业务线不能再为所欲为了。底层服务对于稳定性的要求更好的话,可以由更资深的工程师维护,而不是像原来 SQL 难以收口,难以控制。

痛点五:疯狂的 DB 耦合

业务线不只访问 user 数据库,还会结合自己的业务访问自己的数据库。

典型的情况是,通过 join 数据表来实现各自业务线的一些业务逻辑。这样的话,业务线 A 的 table-user 与 table-A 耦合在了一起,业务线 B 的 table-user 与 table-B 耦合在了一起,业务线 C 的 table-user 与 table-C 耦合在了一起,最后的结果就是:table-user,table-A,table-B,table-C 都耦合在了一起

服务化之后,底层的数据库被隔离开了,可以很方便的拆分出来,进行扩容。

像上边说的,服务层就是在这样的情况下被抽象出来的。概括起来,它就是用来统一完成一部分数据访问或者子业务逻辑。这就是指服务化

而从这个角度来看,微服务本质上就是指粒度比较细的服务化的实施

具体到 58 到家 /58 速运

就像上边说的,随着业务越来越复杂,数据量越来越大,并发量越来越大,58 到家因为经历了这些阶段,所以系统架构走上了微服务之路。

具体来说,15 年的时候,58 到家的架构碰到了类似的种种问题:

  • 垂直业务扩展,家政、丽人、速运、平台,一些相似的业务代码拷贝越来越严重
  • 数据量、并发量提升,底层架构复杂性不断向上游扩散,所有调用方都需要关注缓存、分库、存储引擎等,效率逐步降低
  • jar 包耦合,多个系统依赖一个公用的 jar 包,一个业务升级导致兼容性问题,影响其他业务
  • 数据库耦合,多个业务公用一个数据库,相互耦合,相互影响
  • SQL 质量低,业务相互耦合,一个业务撰写了一个低质量的 SQL,导致其他业务受影响

其实我们也不是一开始就直接采用微服务架构,这个也是经过了不同阶段而演进出来的。

简单地说,58 到家刚开始的时候,我们先找到通用痛点,抽象出通用数据访问与子业务,然后将它们下沉成微服务

更具体地,早期 58 到家是抽象出用户中心,订单中心,支付中心等来构建微服务的。

我们从 58 速运的角度来讲,刚开始 58 到家是大一统阶段,就是系统没有进行业务拆分的时候,因为刚开始业务量也小,所以它还是可行的。

后来整个系统拆分成了站点、数据库、缓存这三个部分。

接着我们进行了垂直拆分,将平台、家政、丽人、速运这些业务拆分开来。

然后就具体到速运这一块进行服务化架构。

而最近我们还在演进这样一个架构,我们知道速运这一块其实它本身也有多个业务形态,有对小 C 的,有对小 B 的。小 C 是搬家服务,小 B 是货的服务,大 B 是优配服务。原来这三块它们都是耦合在一起的,现在也在进行拆分。

这其实也就是架构演进过程中必然会出现的,而具体再讨论下去,其实就是在做一些微服务架构上的事情了。

上边这些说的都是业务的垂直拆分,下边看一下我们的系统分层情况是怎么样的。

我们现在的系统分成了四层,如下:

  • 第一层:站点平台
  • 第二层:业务服务层。把基础数据通用的东西往上抽,就像上边说的,比如它解决代码拷备的痛点,不能让代码拷来拷去,所以把这份代码抽象成一个服务。解决库的耦合,如果之前没有服务化,可能用代码库,用 jar 包、DLL、SO 库来解决代码拷备这个问题,一个库,多个服务依赖,那库的版本升级,影响范围很大,可能多个服务因为一个库的原因耦合在一起。上边说的这些就是发生在这个层上,它解决的是底层复杂性屏蔽的问题。如果没有服务层,那么牵一发而动全身
  • 第三层:基础数据服务层。不包含复杂的业务逻辑,只是数据访问的代理,对数据库层的 CRUD。原来设计为相对简单的“DAO 层”。
  • 第四层:数据层。数据层包括缓存和 DB。

最开始的时候是没有业务服务层的,业务应用分别直接访问数据库,导致大量耦合;架构演进到第二个阶段的时候,我们抽象出一些通用的业务无关的基础服务,例如地理位置服务、经纬度服务、短网址服务、短信服务等;到了第三个阶段,我们抽象出一些通用业务的服务,例如 passport 服务、订单中心服务、支付中心服务等;未来,我们会进一步去抽象更多的通用业务服务。总之,整个微服务架构演进的思路就是:“共性 + 通用痛点”抽象下沉

需要关注的问题

很多架构师只看到微服务的好处,但其实微服务会导致增加系统运维的复杂性,增加配置文件的复杂性,加大追查问题与监控系统的难度。为了解决这些问题,需要有配套的技术体系支撑,例如:引入自动化上线平台解决运维复杂性问题,引入配置中心解决配置耦合的问题,引入监控平台与调用链平台解决监控与问题追查的问题。微服务体系,需要有一系列技术基础设施配套,而不只是引入一个简单的服务框架,而这些配套的技术基础设施,往往比服务框架本身复杂得多

微服务体系配套基础设施包括但是不限于以下这些东西:

  • 配置中心,解除系统之间因为配置文件导致的耦合,做逻辑上解耦(但物理上仍然保持上下游连接)
  • 消息中心,解除系统之间调用关系导致的耦合,做逻辑上与物理上的双重解耦(物理上不再相互连接)
  • 监控中心,立体化监控,实施机器、进程、接口、日志、用户层面多维度监控,及早发现问题
  • 调用链跟踪系统,图形化,量化展现请求在系统中的调用路径,及早定位问题

一个重要的原则

像上边提到的,在微服务架构的实施过程中,抓住“共性”与“通用痛点”下沉,是一个最常见的原则。这里简单地再以 58 到家为例做一下总结。家政、丽人、速运各个业务都有自己的账户体系、订单体系、支付体系,这样成本显然是较高的,复杂性成本也是会不断增加的。对于这样的一些通用业务,就应该抽象出 passport 服务统一解决 SSO(Single Sign-On)问题;抽象出订单中心服务解决订单的集中存储与展现问题;抽象出支付中心服务来统一解决微信与支付宝的对接,统一解决对账等问题。

寄语

关注业务比研究架构更重要,任何脱离业务的架构设计都是耍流氓。找痛点、解决痛点比高瞻远瞩重要,架构是演进而来的,而不是设计而来的。几点个人浅见,共勉。


感谢徐川对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-09-12 19:007410

评论 1 条评论

发布
用户头像
很好,点个赞
2019-10-11 17:58
回复
没有更多了
发现更多内容

一文浅谈Mockito使用 | 京东云技术团队

京东科技开发者

测试 Mockito Mock 企业号9月PK榜

第六周作业

大肚皮狒狒

【PPT下载】杭州 Atlassian 社区四周年活动

跟YY哥学Jira

Jira ACE #研发效能 Atlassiam Jira Service Management

国产化运维安全审计系统哪家好?支持信创吗?有哪些功能?

行云管家

国产化 安全运维 运维审计 国产化平台

GPU云服务器有什么优势?

青椒云云电脑

GPU云桌面

一文读懂GPU参数选择

青椒云云电脑

云桌面 GPU算力

为什么GPU引领加速计算时代

青椒云云电脑

GPU算力

艺术与区块链的融合—NFT开发的创意之旅

区块链软件开发推广运营

交易所开发 dapp开发 区块链开发 链游开发 NFT开发

Vulkan并发机制

江湖修行

android 前端 opengl 渲染 vulkan

交易日均千万订单的存储架构设计与实践 | 京东物流技术团队

京东科技开发者

架构设计 订单系统 存储架构 企业号9月PK榜

可观测性成熟度模型介绍(一)

乘云数字DataBuff

为什么GPU在深度学习扮演重要角色?

青椒云云电脑

gpu

后端服务之应用预热 | 京东云技术团队

京东科技开发者

JS防抖 抖动 jsf 企业号9月PK榜 应用预热

人工智能、GPU与云计算的关系和应用

青椒云云电脑

人工智能 GPU算力 AI绘画

规模化、可复制的大模型应用——企业知识管家

九章云极DataCanvas

一个 println 竟然比 volatile 还好使? | 京东云技术团队

京东科技开发者

volatile JIT 企业号9月PK榜 println

3D设计软件Rhinoceros 6 mac(犀牛6中文直装)完美激活版

mac

windows 三维建模软件 苹果mac Rhinoceros 犀牛6

支付宝小程序云,智能开放的增长引擎

TRaaS

支付宝小程序 AI 大模型

怎么选择适合深度学习的GPU

青椒云云电脑

云桌面 AI绘画 云桌面系统

GPU应用:从计算机图形学到人工智能

青椒云云电脑

人工智能 gpu AI绘画

GPT 被曝重大缺陷;腾讯侦破国内首个 AI 游戏外挂;特斯拉人形机器人再进化丨 RTE 开发者日报 Vol.56

声网

QCN9074, QCN9274, QCN6274 - Wi-Fi 6E bands: 2.4 GHz, 5 GHz and 6 GHz

wifi6-yiyi

QCN9074 Wi-Fi 6E

九章云极DataCanvas公司入选人工智能融合发展与安全应用典型案例

九章云极DataCanvas

研究了代码质量后,开发效率提升10倍,bug减少20倍!!

SoFlu-JavaAI开发助手

DeFi/DApp单双币/子母币流动性质押LP挖矿项目系统开发

l8l259l3365

Python Web框架

人工智能的催化剂:GPU高性能计算

青椒云云电脑

人工智能 gpu GPU算力 AI绘画

沈剑聊微服务:先做好你的服务拆分_语言 & 开发_沈剑_InfoQ精选文章