武汉的开发者们注意啦!AI技术战略、框架以及最佳实战尽在Azure OpenAI Day 了解详情
写点什么

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

  • 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:007206

评论 1 条评论

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

☕【权限设计系列】「认证授权专题」史上最全的权限认证服务的权限模型大全

洛神灬殇

架构设计 12月日更 权限设计 功能设计

物联网之智慧农业应用分析&大数据之数据挖掘技术的应用

亚马逊云科技 (Amazon Web Services)

人工智能 云计算 大数据 物联网

58 K8S之集群日志系统

穿过生命散发芬芳

k8s 28天写作 12月日更

25年,初心未改。

澳鹏Appen

人工智能 机器学习 训练数据 数据训练

百度APP视频播放中的解码优化

百度开发者中心

视频 解码技术

Token机制相对于Cookie机制的优势

郑州埃文科技

数据库 IP Token API

艾瑞发布《2021 年全球互联网通信云行业研究报告》,融云持续领跑市场

融云 RongCloud

2022年之前,你不得不了解的一些 DevOps 趋势

SoFlu软件机器人

融云荣获“2021 数字化服务创新成长企业”奖

融云 RongCloud

直播连麦的人工智能回声消除技术探索

融云 RongCloud

Linux之find命令

入门小站

Linux

深入Java线程池:从设计思想到源码解读

Ayue、

线程池

实现一个javaagent需要几步?

BUG侦探

Java javaagent IAST

模型黑盒|机器学习模型的“可解释性”研究

索信达控股

神经网络 机器学习 神经网络模型

带你熟悉鸿蒙轻内核Kconfig使用指南

华为云开发者联盟

Python 鸿蒙 LiteOS-M Kconfig kconfiglib

前端开发SpringBoot之接口文档的生成

@零度

前端开发 springboot

有没有好用的低代码平台,支持本地私有化部署的?

优秀

低代码 私有化部署

白帽近距离|TimeLine Sec安全团队威猛先生

火线安全

泉州有几家正规等保测评公司?在哪里?叫什么名字?

行云管家

网络安全 等保 等级保护 等保测评

多因子认证是什么意思?与双因子认证有什么区别?

行云管家

身份认证 双因子认证 账户安全

恒源云(GPUSHARE)_有关【图像平滑】的论文小记

恒源云

深度学习 CV 图像处理

大数据埋点如何实现、验证和管理

融云 RongCloud

Linux中如何设置SSH密钥提升登陆安全性

恒生LIGHT云社区

Linux SSH

在线JSON转Mongoose工具

入门小站

工具

Orillusion | 第一个WebGPU中文社区

Orillusion

WebGL 渲染 元宇宙 Metaverse webgpu

从了解洞态 IAST 到加入开源社区

火线安全

DevSecOps IAST

风云再起之国产数据库风云榜-2021年12月

墨天轮

数据库 opengauss TiDB 国产数据库

遥遥无期

Tiger

28天写作

基于DataX的数据同步(上)-DataX介绍以及安装

恒生LIGHT云社区

MySQL 数据库 数据同步 DataX

应用落地 智创未来 | 2021新一代人工智能院士高峰论坛昇腾人工智能应用专场成功举办

OpenI启智社区

人工智能 昇腾

【架构师训练营】模块三作业

樰巳-堕~Horry

架构实战营 「架构实战营」

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