背景
有一个需求,在查询产品列表的时候,需要针对部分指定用户进行屏蔽操作,而一个用户能否可见需要根据userId调用第三方接口判断.
做法
在查询列表的时候,调用接口判断用户是否需要被屏蔽,如果要屏蔽,查询就排除这四个产品。
Bug现象
用户多次刷新列表,有时能看到这四个产品,有时看不到这四个产品.
原因
列表service层入口 有缓存C1,这个C1的缓存是基于入参的,入参中只有人组和查询条件,没有用户userId等信息.也就是说,C1缓存的粒度并不是到用户级别的。
在service内部调用第三方接口判断用户是否可见产品的时候,使用了用户的userId值,第三方接口返回结果会改变service内部的查询结果值.这个时候C1缓存会将这个结果值给缓存起来,但是key中是不带userId信息的,只有人组等. 如果这时候有一个其它一样人组的用户来调用,就会得到这个缓存结果,但是这个用户究竟能不能看到四个产品不应该取决于人组,而应该取决于第三方接口调用结果,等到下次没有缓存,用户直接进入service内部调用第三方接口判断的时候,就可能会出现和使用缓存不一样的结果。当用户量很大的时候,就会出现显示混乱的问题,因为同一个KEY,但是缓存的value确总是在变化,自然用户刷新后结果就会变来变去。
解决方案:
这个问题的根本就在于缓存的key上,key的粒度决定了缓存的命中率,如果直接将service缓存中加上userId,那么粒度变小,缓存命中就会变差,接口性能就会降低.
因此,最终决定将缓存从service上移除,把缓存放到service内部调的各种接口上,使相同入参的调用可以直接得到结果,内存计算还是比较快,减少HTTP调用即可.
网友评论