关于微服务设计的一个问题

2020-03-11 07:19:30 +08:00
 Aliberter

公司关于微服务项目的设计中,打算把所有关于数据库的操作都集中到单独的服务中,每一个其他微服务有数据的增删改查都要去调用这个服务获取,我想问这有必要吗,甚至说这是不是已经违背了微服务的设计原则了?我感觉除了带来服务之间耦合性之外,也让数据事务的控制变得很难,增加了网络消耗,甚至也让开发层面变得异常困难与繁琐,想不通为什么要这么搞,感觉毫无优点可言。请大佬们指点一下。

8496 次点击
所在节点    程序员
64 条回复
gemini767
2020-03-11 14:42:54 +08:00
只能说🦐**设计。。微服务解耦业务,不是解耦代码设计
neilq
2020-03-11 15:19:24 +08:00
很巧,之前我在一家公司就是搞得你说的这种模式,主要有两个几个原因:

1. 人多,项目大,合作开发,我们大概有 15 个人搞一个系统的 crud 后端,为了抢时间。但是这么多人搞同一个项目,哪怕你代码分支管理的再好,也很有各种合并啊,冲突啊,而且人员水平层次不齐,很难管好所有人都按照标准执行,浪费很多精力,干脆分开来。我们大概分了什么通用服务,人事服务,工作流服务,产品服务,订单服务等等,3 人一组,水平差的开发简单的服务,水平高一点的开发难一点的服务。开发时先定接口标准,这样有业务耦合时不用等其他人。

2. 各个服务请求量不等,像人事服务这种基本没什么量,用差一点的服务器,像产品服务请求量就相对比较大,用好一点配置的服务器,遇到性能优化什么的,代码、架构改起来不会影响其他服务,部署万一出问题也不会影响其他服务,万一宕机,这个服务不能用了,但人事那边业务也会正常展开。

3. 为了试一试新技术新架构,体验体验,就这么简单。

我的理解是,不要为了用微服务而去用微服务,而是因为单体服务对这个项目,在当前这个时间点,有这样那样问题,才要去考虑用微服务。如果你很难说出现在用单体应用有什么问题,那我不推荐用微服务。
wingyiu
2020-03-11 15:19:37 +08:00
看看 DDD 啊
neilq
2020-03-11 15:28:38 +08:00
有同学提到 DDD,其实微服务应该就是领域模型在架构层次的拆分,我看现在网上的博客,很多都是在同一个项目里搞代码层级的划分。甚至有些人在某一个单独的微服务里面还在搞 ddd 划分,我觉得没有意义
purensong
2020-03-11 15:49:35 +08:00
说下 我之前公司的微服务架构吧
就是数据中台。
数据中台有很多服务,用户权限, 供应链,CMS 等等
然后是各种网关,主要分两种,一种 API 网关,一种 filter 网关,用 groovy 开发的,上线后可以在控台修改脚本立即生效。
利用 spring cloud 的 kv 存储去上报下载接口的权限配置信息。
微服务框架是 dubbo sc 混用,后面多数迁移到了 sc 上,代码用 feign 调用 。

对于开发者来说,每个微服务使用都是根据模块去划分。将一个大中台分割成多个模块,我没遇到数据库中台,各自项目里数据库还是独立的,如果用到别的数据库数据基本都有微服务去包装。
顺便问大家,因为微服务调用就跟本地方法调用一样,但是微服务变更上线了新版本,该怎么友好的通知使用者呢。我遇到有的方法 deprecated 但是没注解,导致我一直用错,带来的影响是数据有差异,这不坑爹嘛
uleh
2020-03-11 16:14:19 +08:00
还是要看你们实际的环境。
标准的“微服务”只是一种实践方式。
实践是没有对错,只有“适合”和“不适合”。
如果你们按照单体模式进行开发 /部署 /运维,只是通过微服务获取了一些团队解耦、数据解耦的话,这样做也未尝不可……
不过全部依赖一个“数据操作微服务”,容易造成系统整体单点故障和性能瓶颈。
lolizeppelin
2020-03-11 16:48:17 +08:00
不要纠结微服务的名词, 这里提供一个具体项目的实现给你参考,这个项目就做了类似你说的事

openstack 的 nova, nova 之前也是服务自写数据库,后来拆分出了一个叫 conductor 的服务,后续版本各个服务都通过 conductor 来处理数据。

虽然我没参加过大型的项目开发,但是 openstack 就反馈出了大型项目开发会遇到的问题以及产生的解决办法
这个 conductor 解决的问题就是

大型项目中会产生很多版本迭代,对应的数据表结构会有各种变化
在微服务时代产生的更大的问题是, 大家不能一起升级!!还要一起跑!

举两个例子:
例 1:
比如说服务 A 和服务 B 都要写同一个表, 服务 A 有需求在表上变更的字段
最好的解决办法当然是服务 A、服务 B 同步表结构,但是因为各种问题 B 目前不能更新,这下咋办?

例 2:
有 1000 台服务器在跑服务 A,如果服务 A 升级变更表结构,怎么做到无缝升级?


为了解决问题, openstack 弄了一个叫 versioned objects 的玩意来解决上面的问题
通常的 orm 都是 model 映射到数据库的表,对 model 对象操作直接反馈到表上
而 versioned object 就是 model 上再加了一层(作用并不是简单的类似 java 的那个叫 dao 层的东西)
代码不在操作 model 层转而操作 versioned object 对象

versioned object 对象的操作落地操作就是将 versioned object 对象序列化后,rpc 到数据落地服务,也就是上面说的 conductor, conductor 还原 versioned object 对象再进行 model 的对应操作

versioned object 的主要属性就是 model 字段和对应值,以及 versioned object 的版本号, conductor 会根据 versioned object 版本的不同做对应兼容操作以便正确映射到 model 上, 对不兼容的版本报告错误


这样的结构就解决了上面的问题,兼容了不同版本的服务,也让升级变得平滑


微服务很多做法都是解决大型项目版本迭代而产生的,不一定是为了解决性能问题,从性能上找原因方向就错了
lolizeppelin
2020-03-11 16:54:02 +08:00
顺便,versioned object 的 rpc 是可选项,一般情况 select 操作是不启用 rpc 也就是不走 conductor 的

并不是有了 conductor,就要所有数据库操作都走 conductor 的,要酌情考虑
tom
2020-03-11 17:09:00 +08:00
我想问一下,微服务是划分成多个工程吗?那那些工具类、组件怎么复用呢?
v2Geeker
2020-03-11 17:41:33 +08:00
你们公司这样的原因我不知道,单从局外人来看这种设计,感觉好奇葩,没用。这样玩风险很大,会影响整体服务的稳定性!
kosmosr
2020-03-11 17:52:27 +08:00
@tom 打包成 maven jar 包
wengang285
2020-03-11 21:37:14 +08:00
如果所有的服务都访问数据库,有以下几个问题:
1、日志,流水不能集中管理,当然你可以用远程日志解决;
2、访问权限问题,比如 A 服务需要扩容,那么扩容的机器都要申请访问 db 的权限,如果通过集中的数据操作服务 B,则无需申请权限,在线扩容的时候,很容易忽略这一步;
3、增加的那点网络消耗其实无关紧要;
wengang285
2020-03-11 21:38:30 +08:00
@uleh 数据操作服务肯定需要多机部署啊,怎么会成为单点呢?
Xbluer
2020-03-11 22:29:11 +08:00
@wengang285 #52 #53 我看你的意思似乎是整个系统就一套数据库系统。微服务中推荐的设计方式是每个服务有独自的数据库系统。所以不会存在你提出的第二个问题。A 服务要扩容,扩自己的数据库服务器就好了。

如果数据库访问都集中到了一个专门的 DaoService 里面,会被所有其他服务依赖,这就存在单点问题。
psirnull
2020-03-12 01:41:22 +08:00
只要那个 db 服务是 HA 高可靠的, 你管他让你联到哪干什么。 没必要浪费那么多脑细胞。
wengang285
2020-03-12 09:36:09 +08:00
@Xbluer 理论是工程是两回事,就像数据库的范式,外键这种东西,在工程领域几乎没人用,至少我见到的微服务系统,没有说每个独立的服务,都有一个自己的 db,而且,即使一个服务,被其他服务依赖,也不能表示这个服务就是单点,你可以通过多机热备来解决这个问题,极端点的例子,所有的服务都依赖接入层,那接入层也存在单点问题吗?
fuxiuyin
2020-03-12 09:47:10 +08:00
我的理解是,这就跟设计电路板的时候,是按照升压模块、显示模块等划分还是按照所有电阻放一块、所有电容放另一块等这样划分的问题一样。
tairan2006
2020-03-12 11:22:00 +08:00
大哥,你这么设计,数据库还是瓶颈啊
TingHaiJamiE
2020-03-12 11:40:34 +08:00
@tairan2006 这么设计不光数据库瓶颈了,这个操作数据库的服务本身也成了潜在的瓶颈。
mreasonyang
2020-03-12 11:45:31 +08:00
把数据库操作抽象为服务已经是比较高阶的领域实践了,本质是不同领域在存储层也需要做到隔离,如果不同上下文需要操作其他上下文的数据则需要通过服务间调用。这样的好处就是各个领域切实被隔离开了,各限界上下文间只关心其他上下文提供的接口不关心存储方式,存储的逻辑也不再需要共享,在团队人员进行拆分时也可以彻底解耦,而在你的 DB 数据量巨大时也方便了你分库分表。坏处也显而易见,如果你的项目不够复杂或者领域的划分不够稳定,那性能、维护的开销会大大增加。所以这个操作本身没问题,主要还是要看你们的使用场景是否合理。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/651727

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX