当人们访问我们构建的网站,与它们互动,甚至从中购买东西时,我们可以学到有价值的信息。 例如,如果我们只关注获得最多浏览量的页面,我们可以尝试改变页面的格式、使用的颜色,甚至改变页面上显示的其他链接。 这些变化中的每一个都可能导致页面或后续页面上更好或更差的体验,甚至影响购买行为。
在第 2.1 节和第 2.2 节中,我们讨论了收集有关用户查看或添加到购物车中的商品的信息。 在第 2.3 节中,我们讨论了缓存生成的网页,以减少页面加载时间和提高响应速度。 不幸的是,我们对 Fake Web Retailer 的缓存做得太过火了; 我们缓存了所有 100,000 个可用的产品页面,现在我们的内存快用完了。 经过一些工作,我们确定我们只能合理地在缓存中保存大约 10,000 个页面。
如果您还记得第 2.1 节,我们保留了对每个被访问项目的引用。 虽然我们可以直接使用该信息来帮助我们决定要缓存哪些页面,但实际上计算出这些数字可能需要很长时间才能获得良好的数字。 相反,让我们在列表 2.2 中的 update_token() 函数中添加一行,我们将在下面看到该函数。
def update_token(conn, token, user, item=None): timestamp = time.time() conn.hset('login:', token, user) conn.zadd('recent:', token, timestamp) if item: conn.zadd('viewed:' + token, item, timestamp) conn.zremrangebyrank('viewed:' + token, 0, -26)
conn.zincrby('viewed:', item, -1)
我们需要添加到 update_token() 的行
添加了这一行,我们现在有了所有被查看项目的记录。 更有用的是,该项目列表按人们查看项目的次数排序,查看次数最多的项目得分最低,因此索引为 0。 随着时间的推移,某些项目将被多次查看,而另一些项目则很少。 显然,我们只想缓存常见的项目,但我们也希望能够发现正在变得流行的新项目,以便我们知道何时缓存它们。
为了保持我们的顶级页面列表的新鲜度,我们需要修剪我们的浏览项目列表,同时调整分数以允许新项目变得流行。 您已经知道如何从第 2.1 节中的 ZSET 中删除项目,但重新缩放是新的。 ZSET 具有一个名为 ZINTERSTORE 的函数,它允许我们组合一个或多个 ZSET,并将输入 ZSET 中的每个分数乘以给定的数字。 (每个输入 ZSET 可以乘以不同的数字。)每 5 分钟,让我们删除不在前 20,000 个项目中的任何项目,并将查看次数重新缩放为之前的 1/2。 以下列表将删除项目并重新缩放剩余分数。
def rescale_viewed(conn): while not QUIT:
conn.zremrangebyrank('viewed:', 20000, -1)
删除不在前 20,000 个查看项目中的任何项目。
conn.zinterstore('viewed:', {'viewed:': .5})
将所有计数重新缩放为之前的 1/2。
time.sleep(300)
5 分钟后再次执行。
通过重新缩放和计数,我们现在有一个不断更新的 Fake Web Retailer 上最常查看的项目列表。 现在我们需要做的就是更新我们的 can_cache() 函数,以考虑我们新的决定页面是否可以缓存的方法,我们就完成了。 您可以在此处看到我们新的 can_cache() 函数。
def can_cache(conn, request):
item_id = extract_item_id(request)
获取页面的项目 ID(如果有)。
if not item_id or is_dynamic(request):
检查页面是否可以静态缓存以及这是否是项目页面。
return False
rank = conn.zrank('viewed:', item_id)
获取项目的排名。
return rank is not None and rank < 10000
返回项目是否具有足够高的浏览量以进行缓存。
有了最后一块,我们现在能够获取我们实际的浏览统计信息,并且仅缓存那些在前 10,000 个产品页面中的页面。 如果我们想以最小的努力存储更多页面,我们可以压缩页面,然后再将它们存储在 Redis 中,使用一种名为边缘端包含的技术来删除页面的一部分,或者我们可以预先优化我们的模板以摆脱不必要的空格。 这些技术中的每一种以及更多技术都可以减少内存使用,并增加我们可以在 Redis 中存储的页面数量,所有这些都为了在我们的站点增长时获得额外的性能改进。