高并发系统设计 -- 贴子(post)的设计

news/2023/6/9 19:47:13

一般存储贴子,通常都是在MySQL中进行存储。大概有几个字段:postId, userId, postTime, content。

其中:

  • userId记录这个贴子是谁发的
  • postTime记录发布的时间。这里只需要精确到秒即可。
  • content记录贴子的内容

我们可以对userId+postTime建立二级索引,使得查看特定用户按照时间排列的所有贴子的操作变得更快。

关于MySQL性能调优我后续会专门写一篇文章

select * from post where postId = ?(查询详情)
select * from post where userId = ? and postTime between ? and ?(根据用户和事件查询)

但是采用上面的查询的话,会有一个严重的问题就是:会产生严重的回表(对二级索引查到的每一条记录都需要聚集索引中重新查询主数据),降低DB的吞吐量。所以可以将userId和postTime信息冗余到postId中,去掉二级索引减少回表。

这里可能有人会问了,那插入效率就大打折扣了!!

对,但是无所谓,你发布贴子,博客的时候,慢一点是无所谓的,这就是业务容忍

postId可用采用首6位位userId,每一位是0-9/A-Z这36个字符中的某一个,6位可以表示21个不同的用户,6位表示时间戳,后续时间戳(精确到秒)可以标识70年范围内的任意一秒,单个用户每秒发放的帖子不超过两位seq表达的最大值。14位的postId可以适用于本设计系统的规模。其中对于timeCompress的计算,可以设计为:

  • 贴子发布的时间减去sns系统初次发布的时间点中间间隔的秒,进行36进制编码
  • 这样设计之后,timeCompress的字母序随着时间(粒度为秒)连续递增,可以充分用DB的范围扫描。

所以我们查询某个用户发送的贴子的列表的场景,SQL变成了:

select * from post where postId between postId1 and postId2
或者
select * from post where postId like "xx%"

由于查询的是同一个用户的帖子,所以所有postId的前缀是相同的,如果查询这个用户某个时间范围内的帖子,那么6位timeCompress的前面几位也相同。这么一来就避免了回表的尴尬。

随着贴子数量的增加,单机DB的数据量和吞吐量达到了上限,因此我们需要进行水平拆分。

由于postId的前缀中完全包含了userId的信息。所以postId可以独立作为路由运算的单元。

但是某些热点的user的读取量巨大,他们被路由到相同的DB上,后者也可能存在读取瓶颈。为此,常见的方式为:读写分离。采用1写N读,利用DB自身同步机制做主备复制。每次读取随机选取N个读库中的一个。

基于读写分离的DB解法存在两个问题:

  1. 采用读写分离之后存在数据延迟问题
  2. 较早的数据极少访问。而一旦读写分离,意味着每一条记录都需要存储多份。当这些数据刚发布的时候,访问频繁,随着时间的推移,他们就不再被访问了。那么百分之99的数据副本不会被读取到,存储效率低。

因此这里我们引入缓存,缓存的数据过期机制天然避免了陈旧数据对空间的占用。

这里我们如何设计Redis的key-value呢?我们不难发现,同一个用户一天发出的帖子数量是有限的,通常不超过10条,平均3条左右,单个用户一周发的帖子很难超过100KB,极端情况下1MB,远低于Redisvalue大小的上限。所以:

key:userId+时间戳(精确到星期)

value:Redis为hash类型,field为postId,value为帖子内容

expire设置为一个星期,即最多同时存在两个星期的数据(假设每贴平均长度0.1KB,1亿用户每天发3贴预计数量为400GB)

对某个用户一段时间范围的查找变为针对该用户本周时间戳的hscan命令,用户发帖等操作同时同步更新DB和缓存,DB的变更操作记录保证一致性。

但是,有些热用户的follower数量极高,意味着这个热点用户所在Redis服务器的查询频率为1000万每秒。

所以这里我们再进一步引入本地缓存来缓解服务端缓存压力。当一些比较热点的用户查询比较频繁的时候,我们可以直接把热点用户存入本地缓存中。用来缓解服务端的缓存的压力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-4564818.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

ps修改字体步骤

先打开图片放大使用字体工具字体对齐 然后隐藏写好的字 选中背景图层接着使用矩形工具在背景上画一个矩形 点击ctrlT矩形框 ctrlT 左侧的横拉 按住enter键确认 选中Home背景转载于:https://blog.51cto.com/2366666666/1340778

(小甲鱼python)函数笔记合集四 函数(IV)总结 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解

一、基础复习 函数的基本用法 创建和调用函数 函数的形参与实参等等函数的几种参数 位置参数、关键字参数、默认参数等函数的收集参数*args **args 解包参数详解 二、函数中参数的作用域 作用域:一个变量可以被访问的范围,一个变量的作用域总是由它在代…

OneDrive - 新建Office文件后无法同步的解决方案

今天接到用户反馈的一个问题,在OneDrive配置的本机上打开编辑一个Office文件,然后save as保存到OneDrive之后,新建的文件无法正常同步到OneDrive。当Sync时提示下面错误“A file is in use by another applicaiton”。 Caption经过测试对于其…

【论文阅读记录】RepMet(原文全名太长这里放不下)(1)

前言: { 前几天在看傅立叶变换,本来也想就此在这做些记录,但一想到现在还有很多新动向我没有了解,就很想再看看最近的论文。所以这次还是论文阅读记录。 论文地址:[1]。 } 正文: { 论文的第一节首先提到…

AS、VSCode中实时显示代码的变更记录

简介 阅读下面内容开始之前,假设你已经在使用 git 管理自己的代码了。 阅读本篇,可以看到如下内容: 1、如何在 Android Studio 中实时显示每行代码的提交历史记录; 2、如何在 Android Studio 中查看单个文件的修改历史记录&am…

Veeam ONE v10.0.2.1094 安装教程+许可证

https://www.ittel.cn/archives/3858.html 作者: 无欢不爱 发布: 2020年10月13日 6,384阅读 0评论 目录 介绍安装过程 1 双击运行2 许可协议3 安装类型选择高级安装;4 功能选择 5 账户密码6 数据库信息7 许可信息8 缓存设置9 结构类型10 数据收集11 安装预览12…

win10计算机同步在哪个文件夹,win10系统中onedrive怎么实现同步任意一个文件夹?...

我们平时还不使用这个onedrive的一个原因是设置麻烦,还不能同步文件夹,只能备份一个文件,上传一个文件,实在是心累。打开onedrive设置之后你就会清楚地发现,选择文件夹一项根本没有给你任何添加其他文件夹的机会&#…

MacOS 下 Nginx 安装记录

之前写过: CentOS6.5下Nginx1.7.4安装记录 CentOS 6.5 下 Tengine 安装记录 最近工作办公电脑换了 Mac,刚好有机会实践一下。 安装非常简单:sudo port install nginx或者使用:sudo brew install nginx使用brew可能还需要&#xff…