问题记录

实时刷新分布式缓存:

产品信息采用的分级存储的策略,分布式缓存-DB, 有使用本地缓存,这里忽略

DB每10分钟,同步产品信息到redis

这样产品配置变更生效的时间为10分钟, 满足业务需求,但存在的问题是

当产品配置出错时,错误配置被redis缓存后,10分钟才会恢复,业务无法接受

所以需要提供一种策略,可以使本地缓存和redis立刻失效

 

解决方案:

1)分析业务场景,产品信息变动的频率比较低,而单次同步的数据量也不大,可以通过将

10min同步间隔改为3min, 该方案可以满足当前的业务需求,但不实时

2)采用异步刷新的方式:

a.产品信息变更时,变更方推送变更通知到消息队列

b.异步刷新系统轮询消息队列(pull方式),收到变更通知后,主动失效分布式缓存

c.业务在未命中分布式cache时,从DB中读取,并缓存

 

一般的流程是按2)来的,结合我们的业务场景,我们此处,不失效分布式缓存,而是需要更新缓存的内容, 

这样操作,引入了业务逻辑,导致这个系统跟业务逻辑紧耦合,不如2)通用,因为2)进行的只是删除操作.

 

并发更新的问题:

多个写端,更新数据库中保存的售卖额度,相互无顺序,存在相互覆盖的可能

解决方案:

1.分析业务场景:发现都是update操作,而且是数字运算,只有增减,请求是无序的,想到可以使用增量update的方式, 这样即使乱序,只要增量的操作都送到后,可以保证结果最终是正确的.

这个方案可以解决业务需求,缺点是导致update失去了幂等的能力,也就是说update失去了重试的能力, 一旦有请求丢失,结果就不准了,

而我们的业务场景中,额度值不需要精确,有一定的偏差是可以接受,所以采用了这种方案

 

2.更好的方案

现在的难点在于请求是无序的,update无序会相互覆盖,是否有办法可以使请求有序,

这里我们想到了版本号的机制,

a.数据库记录中需保存版本号

b.每次更新前,需要查询更新对象当前的版本号

c.更新时,在where条件中指定版本号

d.更新成功后,版本号+1

这种方式利用了数据库update的原子性(行级锁),就像svn提交代码一样,版本号不符合的就更新不到. 也就避免了相互覆盖的问题.

同时,update操作是幂等的,更新失败时,需要重试,直到更新成功或超过重试的次数.

 

方案2 和 方案1相比,

方案2通过版本号解决竞争的问题,但冲突的可能性提高,并且存在重试的开销。

a.当更新频率较高时,随着冲突增多,重试次数也增多,开销增加, 性能不如方案1, 但是它的优点是保证了数据的正确性。

方案1对数据的正确性不保证,但是应对高频更新时,因为没有重试的开销,性能更好

b.当更新频率较低时,方案2和方案1性能差距不大,所以方案2更适合. 

 

事务的问题:

背景:

两阶段提交过重,性能太低

 

解决方案:

1.结合业务场景, 两阶段提交对我们过于复杂,性能较低,我们考虑使用 异步+记账+补偿的方式,

简单说就是, 要完成一个事务, 我们可以先把操作记录下来,存放在文件或数据库中, 然后起一个定时任务,轮询操作记录,有该定时任务负责事务的处理,

其进行事务处理事,采用幂等重试的方式,不断轮询,保证事务处理成功. 

成功后,再通知业务,事务处理完成,业务再回复客户.  

优点:异步--a.业务不会阻塞在事务上, 定时任务通过消息队列通知业务 b.业务设定一个超时时间,超时后,更新操作记录的状态, 定时任务看到任务超时后,就不继续操作了.  c.定时任务操作成功时,推送通知给业务.

缺点:业务的事务处理逻辑 和 事务处理被剥离开了,能否剥离出来,要看业务场景。 通常如果只是数据库的操作,是可以剥离出来。

posted @ 2016-08-23 15:17  JinleiZhang  阅读(263)  评论(0编辑  收藏  举报