redis作为mysql的回写视图计数缓存

One*_*oob 7 mysql caching redis

我有一个非常高的吞吐量站点,我正在尝试为mySQL数据库中的每个页面存储"查看计数"(由于遗留原因,它们最终必须最终在mySQL中).

大量的视图使得执行SQL"UPDATE ITEM SET VIEW_COUNT = VIEW_COUNT + 1"类型的语句变得不切实际.有数百万的项目,但大多数只被观看了很少次,其他项目被观看了很多次.

所以我正在考虑使用Redis来收集视图计数,后台线程将计数写入mySQL.这样做的推荐方法是什么?该方法存在一些问题:

  • 后台线程多久运行一次?
  • 它如何确定写回mySQL的内容?
  • 我应该为每个被击中的ITEM存储一个Redis KEY吗?
  • 我应该使用什么TTL?
  • 是否已经有一些预先构建的解决方案或powerpoint演示文稿,让我在那里,等等.

我在StackOverflow上看到了非常类似的问题,但没有一个有很好的答案...... 希望此时有更多的Redis知识.

The*_*ill 7

我认为您需要退后一步,从不同的角度看待您的一些问题,以获得您的答案.

"后台线程多久运行一次?" 要回答这个问题,您需要回答以下问题:您可以丢失多少数据?数据在MySQL中的原因是什么,以及访问数据的频率是多少?例如,如果只需要每天为报告查询一次数据库,您可能只需要每天更新一次.另一方面,如果Redis实例死了怎么办?你可以失去多少增量并仍然"正常"?这些将提供更新MySQL实例的频率问题的答案,而不是我们可以为您解答的问题.

我会使用一种非常不同的策略将其存储在redis中.为了便于讨论,我们假设您需要每小时"刷新到数据库".

使用这些行中的键名结构将每个匹配存储在哈希中:

interval_counter:DD:HH
interval_counter:total
Run Code Online (Sandbox Code Playgroud)

使用页面ID(例如,URI的MD5总和,URI本身或您当前使用的任何ID)作为哈希键,并在页面视图上执行两个增量; 每个哈希一个.这为您提供了每个页面的当前总数以及要更新的页面子集.

然后,您可以在小时开始后大约一分钟左右运行您的cron作业,通过抓取前一小时的哈希来下拉所有具有更新视图计数的页面.这为您提供了一种非常快速的方法来获取数据以更新MySQL数据库,同时避免任何需要进行数学运算或使用时间戳等操作的技巧.通过从不再增加的键中提取数据,您可以避免竞争条件到期钟歪斜.

您可以在每日密钥上设置到期日期,但在成功更新数据库时,我宁愿使用cron作业将其删除.这意味着如果cron作业失败或无法执行,您的数据仍然存在.它还通过不改变的键为前端提供一整套已知的命中计数器数据.如果您愿意,您甚至可以保留每日数据,以便能够对页面的受欢迎程度进行窗口视图.例如,如果通过cron作业设置过期而不是删除,将每日哈希值保留7天,则可以显示上一页每页每天的流量.

执行两个hincr操作可以完成独奏或流水线仍然执行得很好,并且比在代码中进行计算和调整数据更有效.

现在针对低流量页面与内存使用到期的问题.首先,您的数据集听起来不像需要大量内存的数据集.当然,其中很大一部分取决于您如何识别每个页面.如果您有数字ID,则内存要求会相当小.如果你仍然有太多的内存,你可以通过配置调整它,如果需要甚至可以使用32位编译redis来减少内存使用量.例如,我在这个答案中描述的数据我过去常常管理互联网上十个最繁忙的论坛之一,它消耗的数据少于3GB.我还将计数器存储在比我在这里描述的更多"时间窗"键中.

也就是说,在这个用例中,Redis是缓存.如果在上述选项之后仍然使用太多内存,则可以设置密钥到期并为每个ht添加expire命令.更具体地说,如果您遵循上述模式,您将按每次点击执行以下操作:

hincr -> total
hincr -> daily
expire -> total
Run Code Online (Sandbox Code Playgroud)

这样,每次访问时都可以通过延长它的到期时间来保留积极使用的新内容.当然,要做到这一点,你需要包装你的显示调用以捕获总数哈希上的hget的空答案,并从MySQL数据库中填充它,然后递增.你甚至可以做两个增量.这将保留上述结构,如果Redis节点需要重新填充,则可能与从MySQL Db更新Redis服务器所需的代码库相同.为此,您需要考虑并决定哪些数据源将被视为具有权威性.

您可以根据您从早期问题中确定的数据完整性参数修改间隔来调整cron作业的性能.要获得更快速运行的cron nob,请减少窗口.使用此方法减少窗口意味着您应该有一个较小的页面集合来更新.这里的一大优势是你不需要弄清楚你需要更新哪些密钥然后去获取它们.你可以做一个hgetall并迭代哈希的密钥来做更新.通过一次检索所有数据,这也可以节省许多往返次数.在任何一种情况下,如果您可能想要考虑第二个Redis实例从属于第一个进行读取.您仍然会对主服务器执行删除操作,但这些操作会更快,并且不太可能在写入繁重的实例中引入延迟.

如果你需要Redis DB的磁盘持久性,那么肯定把它放在一个从属实例上.否则,如果您确实经常更改大量数据,则RDB转储将持续运行.

我希望有所帮助.没有"罐装"答案,因为要正确使用Redis,您需要首先考虑如何访问数据,这在用户和项目与项目之间存在很大差异.这里我基于此描述所采用的路线:两个消费者访问数据,一个仅显示,另一个确定更新另一个数据源.