-
当我们刚毕业时,我们会刷八股文
- Mysql binlog undolog
- 乐观锁、悲观锁、Compare And Swap
- 分布式事务
-
八股文对于当时来说,可能是老开发从英文版oracle jdk那复制来的,因为不问这个也没别的问,直接问你实际上手的才是问死了。
-
八股文在经历自身的业务洗礼后,应当做到可以问出问题并举出场景和面试者聊处理。
- 实际上会有吐槽面试官不会问,那你可以反思下,是不是自己没东西讲,你没能力发起业务/项目推进过程中的一个个小点话题发散聊八股聊设计聊思路聊方法?
-
回归正题
-
版本控制为什么/在哪里出现的?
- 出现于M域管理类系统居多,常涉及数据敏感/政策导向/金钱流动的业务
-
其和传统事务的相似性
- 原子性:不相关
- 一致性:要求具备,每次手动的对于数据的操作回滚/JUMP都应当保证多方数据一致。
- 隔离性:不相关
- 持久性:必须的,每次手动都要求持久。 ↑这个其实硬套了,主要类似事务的回滚和版本控制内容。
-
一般的选择实现方式?
- 八股文中的binlog,undolog,理解其原理:记录操作的元信息,记录谁在什么时候,干了什么,from what to what。数据不消失,只是版本变了。
- 实践中出现了一个分歧:我们到底需不需要主键?那些老开发还有写C面向过程的,还有现场外包运维开发,他们的想法是不需要,按照什么账期租户信息去定位去update,至于是否唯一?说的好听叫源头上游数据保证了唯一了,说的难听就是完全不考虑健壮可靠。再深点就是他们完全没去理解一个个涉及数据的业务,也就没法给出明确的主键描述定义。属于是写的时候一时爽,后续功能迭代改断腿,这个已经实践,他们埋得雷在2年后寸步难行,没得辩。
- 我们的业务操作也必须记录/日志先行,比较舒服的点是,我们可以基于DB事务,保证操作原子,不需要再手搓轮子,像数据库一样做一堆定时任务保障日志和数据的一致性。
- 每次操作时,加锁,但对于宏观的业务来说,八股上的什么乐观悲观CAS就太细了,大道至简Redis Lock or Update lock
- 八股文中的binlog,undolog,理解其原理:记录操作的元信息,记录谁在什么时候,干了什么,from what to what。数据不消失,只是版本变了。
-
二般实现方式:分布式多方数据库场景下,持久伪事务,怎么保障?
- Seata框架:重量级
- TCC:土就是好,需求特化定时任务保证最终一致,也许可以称之为……对账?
-
三般实现方式:用户操作性能敏感
-
一拍脑袋就是要多线程,不划水就知道该拆,把主流程的各类日志、记录、检查,和重量级的大数据量纵向多版本表的update version then insert粗分2个线程去跑。
- 这里建议是借鉴Redisson的写法,入参都是Promise:一个承诺,按照业务诚实实现就好了。
- 前端比如vue也是一堆promise
-
子问题就是大数据量的batch操作性能提升,瓶颈不在于数据库,在于发起方(JAVA应用)
-
具体怎么写多线程最好就不说了。问题在于怎么保证多线程的事务一致RollBack/Commit
-
这个问题需要具体场景具体分析
-
业务数据的设计实现方式是否是增量的?(带版本号的)
- 如果是,那么就出现任何异常,delete new data+revert old data status 即可
- 对应可以不在多线程内开启事务,事务会影响性能,我们手动控制就不需要了
-
如果现实困难不适合做增量的
- 那么我们实际上将丢失对于数据归属的掌控,必须开始事务保证安全
- 实现就变成了,每个线程都是一个独立的事务……吗?
- 当然是,底层就是connection start commit rollback,每个线程提速的基础就是每个线程的connection不同
- 所以应设计一个全局变量作为某次版本控制的元数据存储,任何线程可感知本次是否完成、是否有异常
-
再优化-兄弟线程间quick fail
- 没什么好说的,提前埋好点,每批次校验全局变量
-
-
如何代码设计
- 定义上:线程类定义为 复数线程&同步事务&快速失败able Thread
- 实现上:最基础最好用最常见的模板模式,实现run,封装抽象beforeRun0\run0\afterRun0,做好标准批处理逻辑定义。
-
-
二拍脑袋就是内存调优,java内存效率不高,所以大批数据导致频繁gc必然,虽然这类批处理任务中的几秒中断都算不上多大损耗
- 但如果老应用设计不合理呢?业务接口也在一个应用里,就会导致假死几秒。
- 该优化优化:内存即使不引用可回收,减少重复对象创建,小步快跑
- 比如把外包写的一次读取全部,改为响应式读取批次触发用完即弃
- 八股文就可以问面试者sublist的使用场景,我不想创建新对象浪费还想只用到list的一段,而其他工具组件都是基于迭代器的,所以需要Arraylist.sublist
- 太低级了。。。。
-