探讨一下微服务,考虑用数据缓存代替服务调用。

2020-04-03 09:54:31 +08:00
 bfbd

全文链接如下:

https://aiportal.github.io/data-driven-service

简单说就是: 每个微服务仅可引用另一个微服务释放出来的数据缓存,不允许直接调用另一个微服务。至于数据缓存何时更新,完全取决于维护该部分数据的那个微服务。

优点: 微服务与微服务之间没有直接调用,不会互相影响,即使某一个或某几个微服务当掉了,其他微服务仍可使用旧版的缓存数据继续运行。

缺点: 设计和划分微服务的时候难度较大,必须让各个微服务之间不依赖同步调用,仅依赖异步数据。

补足: 特殊情况必须做同步调用时,可以用消息队列加等待异步操作完成的伪同步来实现同步操作。

4088 次点击
所在节点    程序员
38 条回复
bfbd
2020-04-03 15:43:57 +08:00
@xuanbg

是的,消息队列和异步操作可以解决微服务间紧密耦合的问题。

的确是想解决服务间耦合依赖的问题,同时也想降低系统向微服务迁移的难度。

用数据层缓存的方式,可以让程序员不关心微服务调用,不处理微服务依赖,仅使用原始的开发模式,开发 [数据库 -> Restful -> 前端] 即可。这样开发人员的技术门槛就降低了,培训成本也降低了。框架的部分交给框架工程师去处理,普通程序员 CRUD 就可以了。
bfbd
2020-04-03 15:48:17 +08:00
@kkeiko

微服务与微服务之间没有网络调用。

Distribute Service 把数据写入到目标磁盘上就不管了,微服务自己读数据,自己用。如果需要跨机房,那就是 Distribute Service 需要跨机房把数据远程写进去,写不进去就先用旧数据将就,直到故障排除。
xsen
2020-04-03 15:57:09 +08:00
明明本来就非常简单的时期,非得做成那么复杂
还有,你说的这些不就是 mq 或者 rpc 的机制么?建议你了解下 grpc 先,然后再反省反省你的这个思路

用传统的数据库做消息机制,亏你想的出来
iisky1121
2020-04-03 16:05:18 +08:00
这个,我看懂了,其实就是把面向数据库编程变成面向缓存数据编程嘛,难道记忆 key 的名称不是一个门槛吗?最后会发现相似的业务,会出现不同的 key 缓存,而且开发人员还相互不知道,那么你用 MQ 机制来修改缓存的时候,你怎么知道要修改哪一些 key 的缓存值?
stevenkang
2020-04-03 16:11:33 +08:00
数据写入硬盘,让其他微服务读硬盘。

数据写入数据库,让其他微服务读数据库。

明显后者具有优势吧。
miao1007
2020-04-03 19:29:44 +08:00
cps 技术嘛
fcten
2020-04-03 20:24:48 +08:00
有一个微服务提供十亿用户信息的查询服务,如何实现数据缓存?
退一步,假设读的问题解决了,那么写呢?要更新用户信息的时候怎么做?
CoderGeek
2020-04-03 20:33:39 +08:00
你是想说弱数据库 弱依赖吧...
fcten
2020-04-03 20:39:55 +08:00
更新一下,看到前面楼主回复说写入操作只在服务内部,只能说楼主根本不了解微服务。
首先,微服务不能承担从接入层网关到数据库整条链路的操作,这种设计无法实现高可用。接入层,业务层,数据层是非常常见的分层模式。
再者,举个例子:在金融系统中,更新余额是一个几乎任何功能都会用到的操作,难道我们把所有这些功能都写到同一个服务中?你能想象支付宝把所有与更新余额相关的功能都写在一个服务里吗?
bfbd
2020-04-06 18:15:56 +08:00
@xsen

grpc 也是 RPC 的一种吧。就像楼上有朋友讲的,如果被调用的服务挂了,就返回错误。没错,这样是对的。但有些时候,在数据一致性要求没那么高的情况下,其实可以不返回错误,用旧版的数据继续服务的。grpc 好像实现不了这个目的。

至于说何时不要求那么高的数据一致性,这就看如何进行领域的划分了,只能具体问题具体分析。
bfbd
2020-04-06 18:17:57 +08:00
@iisky1121

在 Generic Rest API 一文里,查询数据的 url 就可以作为 key,当然 key 太长了可以 hash 一下,ETag Cache Service 里就是这么用的。
bfbd
2020-04-06 18:22:48 +08:00
@stevenkang

直接写入数据库的方案的确考虑过,但有两点顾虑:一是数据的频繁更新是否会给数据库造成负担,影响数据库响应其他请求的效率,二是数据库里新旧版本数据的替换速度如何?磁盘文件可以先写个新的,然后交换下文件名,再把旧的删掉。这样数据文件仅改名期间不可用,是瞬时的。

当然,写磁盘文件也有缺点,数据库自带的缓存优化就失效了,查询速度可能受影响。这一点要想改进,可能就得自己打造定制版的 file_fdw 插件了。
bfbd
2020-04-06 18:23:56 +08:00
@miao1007

CPS 不了解,有空学习下,谢谢。
bfbd
2020-04-06 18:25:35 +08:00
@CoderGeek

差不多吧,主要目的是隔离。
或者也可以看成是多个子系统,而不是多个微服务,后面可以在子系统内部再进行分层的微服务划分。
bfbd
2020-04-06 18:32:56 +08:00
@fcten

海量数据的缓存问题在 [Series data cache] 这篇里有提(好像贴不了网址)。
核心思想就是用某个键值做分块,然后分块缓存,这个参考的 Redis 分布式策略。

所有的缓存都是面向结果的,换句话说,缓存的就是查询结果。
如果查询结果的组合有一千种,就要生成一千份缓存。理论上就是这样的。
但实际上可以二八法则,80% 的常用查询结果能命中缓存就可以了,剩下的 20% 慢点也没关系,可以待预算充足时再加以补足。

更新的时候就是更新了哪个块,就触发哪个块的缓存替换过程。
举个例子:十亿用户分成一千块,查询条件一百种。改了两个用户,触发两个块的缓存更新,就要修改两百个缓存文件。就是这样。
bfbd
2020-04-06 18:37:21 +08:00
@fcten

是的,的确不能把一整套逻辑都写到一个服务里。
不过微服务里也提到说微服务的划分是可以嵌套的,如果按嵌套的方式去设计呢?

比如:先按领域划分大块,就把你说的更新余额相关的,要求实时响应和数据一致的部分,都划分到一个领域,然后再在这个领域里,划分出多个层级的微服务。
至于其他的领域,应该与这个更新余额相关的领域没有强依赖,没有强相关,可以容忍一定程度的异步延迟。
fishioon
2020-04-06 21:18:35 +08:00
哈哈,有意思的想法;楼主再换个思路想想,读取结果数据总是需要调用 API 的对不对?这个 API 可以是一个读取本地文件 /远程数据库 /远程服务等等;如果是远程服务,那这个 API 就是一个 RPC 调用了,又回到了微服务模式;另外数据总是多变的,而接口可以保持相对稳定
bfbd
2020-04-10 10:07:29 +08:00
@fishioon

读取结果数据是 Distribute Service 集中调用 API,成功失败无所谓。
如果成功了,更新缓存数据供其他微服务使用。
如果失败了,记录失败信息,供系统管理员参考,有点儿类似于微服务的健康监控。

所以,也可以看作是在微服务与微服务之间的直接调用路径中加了个间接层,这个间接层顺便还实现了微服务的可用性监控。

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

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

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

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

© 2021 V2EX