20260107-Akka之Actor编程模型使用与反思
1,背景资料
在2022~2024期间,产品有了一个关于版本回溯的需求:
有一个病例单,里面有很多数据并且有很多层级,医生可以将某个旧版本分享给其他医生(产品同学的原话)
当时有2种技术方案:
1,直接使用快照模式,分享一次直接保存一次快照
优点:技术复杂度低
缺点:只能查看被保存的版本;多层级(父子关联关系)的实体对象保存会比较麻烦
2,版本回溯模式,这个类似于Redis中AOF(Append Only File),会将没有的修改操作全部都记录在案,下次重建的时候,直接重新演绎一遍即可
优点:可以回溯到任意版本对象;分享时只用分享某个实体对象的版本号和标识id即可;
缺点:需要引入非常规的版本回溯编程架构(技术上可以实现)
我们和产品沟通的2种技术方案后,产品同学眼前一亮,可以查看多版本更好!然后,我们技术同学又深入调研讨论了一下,最后就选定了:Java、Akka Cluster、Cansendra、Postgres、Protocol Buffer、云原生的技术架构
2,技术细节
| 关键词 | 解释 |
|---|---|
| Java | Akka系统底层使用Scala语言编写,但是可以同时使用Java与Scala编写业务代码 我们约定使用Java编写业务代码,因为公司原有的技术栈就是Java,并且Java程序员人数众多 |
| Akka Cluster | 使用Actor模型的Akka系统来作为框架底层,高并发、高可用、快速响应 |
| Cansendra | 分布式数据库用于Actor对象的修改日志、快照日志的保存 |
| Postgres | 实体对象的范围查询数据库,其实这里我一直觉得有问题,Actor模型难道就没有更好的范围查询方案吗 |
| Protocol Buffer | 这个是对应与产品的消息主动通知需求,专门使用的请求交互机制,同时也是Akka天生支持的 |
| 云原生 | 我们设置5个Akka节点以防止系统崩溃 |
3,反思
| 关键词 | 解释 |
|---|---|
| 范围查询 | 实体对象的范围查询需求,导致我们其实有2份可以进行版本重构的数据源 1,Akka自带的版本回溯、快照(可以设置多少次修改保存1次快照,避免重演太慢)回复 2,PostgresSQL数据库的最新快照,这个用于范围查询的需求 其实,可以将Akka中的快照数据直接存储到Postgres中,避免多地冗余存储 |
| 对象操作 | 这个是真的不应该,因为业务发展太快,实体对象的计算修改业务太多、太杂 我们增加了一个Update实体对象的全量字段的消息类型, 这样做的优点很明显,业务代码不再需要每一种操作都生成一种消息类型了; 缺点也很明显,原本不能直接操作Actor对象,但是这种又间接变成可以操作实体对象了,这完全不对了! |
| 实时修改 严重威胁 |
Akka系统修改后,会先存储修改日志,然后执行PG库的最新版本的修改,中间存在时间延迟 然而,我们的业务又要求范围查询必须实时输出!GG 能怎么办?难办,好好的一个非阻塞框架被业务搞成了阻塞系统!!! 为了在后端实现这个需求,我们在LOG写入时,阻塞了一个PG库修改的操作 由于这个阻塞的存在导致我们的系统性能大打折扣,甚至业务量上来时出现过大量Actor响应超时,快速失败 这个太影响性能了,其实有其他更好的解决方案,但是需要前端技术强才行,但是懂得都懂 |
| 妥协团队效率 | 因为招聘到的程序员,很多都不会Akka,为了他们编写需求方便,我在代码层级封装了一层Spring! 他们编写时,理论上只需要关注自己的业务即可 但是这个妥协方案也导致系统冗余! |
| 是否真需求? | 随着业务逐步发展,我们技术也发现,其实这个版本控制的需求并不是我们软件体系的核心需求 这个功能特性的多与少,并非软件的核心竞争力 另外,我们的业务实体层级众多、关联关系众多,其实纯粹的CURD模型就可以解决所有的需求了 现在使用Actor模型纯属,没事找事;如果是游戏业务或者其他状态机业务模式,可以使用这种模型 |
| 请求被套壳 | 原本我们使用Protocol Buffer技术,但是由于前端临时需求太多,导致他们不愿意学习与适配 于是,我们后端同学又为他们套了一层http请求的壳! |
以上所有的甩锅给业务太复杂的问题,其本质都是本人没有严格坚持Akka编程中的Actor模型,把整个系统变成了面向对象编程的一种变体
因为这个系统,我也在后续领悟到这些教训:
1,技术并非最新、最快、最强,就最好!只有适合的技术,没有落后的技术。
以Akka技术为例,其实小众的技术都是有其局限性,我从来没有否认过Akka编程思想的先进性;但是,它就是有它的使用区域
2,技术同学也应该是产品。
对所有人祛魅,所有的人都是草台班子,要与产品确认需求的真伪性以及均衡成本与风险,而不是盲目服从产品的要求;但同时也要注意保持团队团结
3,技术要考虑到整体团队的适应性。
某一项技术很强,但是对接团队各种各样的原因无法对接,那么这项技术也失去了意义
4,后端同学要提前与其他技术部门协调规划好所有的技术路线。