在我们网站的可自定义首页上,我们为用户提供了显示最近更新内容的模块的选项,从超过100个模块中进行选择。
所有数据都是由MySQL查询生成的,其结果通过memcached缓存。我们当前的系统工作方式如下:当用户加载包含模块,模块的页面时,它们立即从缓存中提供数据,并将查询添加到队列中以通过单独的齿轮工艺进程更新(以便页面加载不等待mysql查询)。然后每15分钟运行一次该查询以刷新缓存中的数据。定期清除查询队列本身,以便我们不会不断刷新最近未请求的数据。
问题是当缓存为空时由于某种原因该怎么办。这不会经常发生,但是当它发生时,用户当前显示为空模块,并且数据在齿轮过程中刷新,以便稍后,当相同(或不同)用户重新加载页面时,是要显示的数据。
我们的流量是这样的,如果我们在缓存为空时尝试为用户实时运行查询,我们就会遇到严重的加盖问题 - 我们将运行相同(可能很慢)的查询用户加载页面的次数很多。有没有办法解决“空白模块”问题,而不会开辟冲压的风险?
答案 0 :(得分:2)
这是一个有趣的实现,虽然与MySQL最常见的实现memcached的方式有所不同。
在大多数情况下,用户会将事务设置到memcached首次评估查询的位置,以查看是否有可用条目。如果是这样,他们从memcached服务它,从不查询数据库。如果存在高速缓存未命中,则对数据库进行查询,将结果添加到memcached,并将信息返回给调用者。这就是通常为读取查询构建缓存的方法。
在更新数据的情况下,将对数据库进行更新,然后memcached中的相应数据无效和/或更新。类似地,对于插入,您可以对缓存执行任何操作(并让该记录上的下一个读取填充缓存),或者您可以主动将与插入相关的数据添加到缓存中,具体取决于您的应用程序需求。
通过这种方式,您无需采取额外的步骤来调用数据库,以便在从memcached获取初始数据后获取权威数据。 memcached中的数据将是权威数据的副本,在更新/插入时更新/无效。
根据您的评论,您可能想要尝试在缓存未命中时阻止对数据库进行大量查询的一件事是使用各种互斥锁。例如,当第一个客户端命中memcached并获得该查找的缓存未命中时,您可以在memcached中插入一个临时值,指示数据处于挂起状态,然后对数据库进行查询,并使用以下内容更新memcached数据。结果
在客户端,当您收到缓存未命中或“待处理”结果时,您可以在一段时间后(您可能希望以指数方式增加)重新启动缓存。所以也许首先嘿等待1秒,然后如果他们仍然得到“待定”结果,则在2秒内尝试增益,然后在4秒内重试,依此类推。
这可能会对memcached服务器提出更多请求,但应解决数据库层上的任何问题。