有一个实时排名预计的pv 1kw 高峰qps 1k 请画出此服务的技术及网络架构图

296 阅读6分钟

计算1kw pv时的正常qps

计算公式: QPS = (PV * 0.8) / (86400 * 0.2)
1kw PV 的 QPS 约为 463 ; (1kw * 0.8) / (86400 * 0.2) = 462.9629629..
对于最高峰值 1k QPS 可暂时忽略,视为双十一的秒杀特殊场景

机器的选择

  • 假设选择的是8核的机器
// 假设
// cpu线程的运行时间是0.5s(可以测试出来)
// 线程的平均等待时间是1.5s(可以测试出来)
// cpu的利用率是80%
// RT是200ms

image_reD9etSV8WyyozMjQqACNg.png

  • 1.计算最佳线程数
公式:(1 + 线程等待时间/线程运行时间) * cpu利用率 * cpu核数
最佳线程数: (1 + 1.5/0.5) * 0.8 * 8 = 25.6 ~= 26
  • 2.计算单线程的QPS
公式:1000ms/RT, 1000ms = 1s
单线程的QPS : 1000/200 = 5
  • 3.当前机器的理论QPS
单线程QPS * 最佳线程数 = 5 * 26 = 130(可选:我们可以在这个理论的基础上再减去10个点; 因为
实际程序的运行还会因io/请求/业务/网络/内存等因素影响)
  • 计算基本机器数量
机器约为4463/120 ~= 4

实时排名:对业务的分析与思考

  • 思考1(排序的权重存储位置)
可以将排序的的信息(浏览量/访问量/点击量/评论量)存入redis中
  • 思考2(实时的延时容忍度控制在多少时间范围以内,另外用户对排行的浏览是刷新更新还是实时推送更新)
1.如果是页面刷新排行--》点击页面的时候去查询即可(一般做法)
2.如果是也是在线刷新--》 需要考虑利用websocket推送,可以考虑单独构建一个推送信息的服务器
  • 思考3(显示多少排名)
外排名一般是指前10、程序需要加载前2050的数据;
可以考虑先把热点数据加载进入Redis中,利用zset存储

  • 思考4(聚合统计规则查询性能问题,一般这种查询排行的性能都不是特别好)
可以考虑,在mysql层面设计物化视图统计表,记录性能较快的数据;并利用异步的脚本进行监控,mysql的binlog日志的数据信息变化;
定期对mysql进行数据的聚合更新物化视图的数据

基本设计

假设以文章的点赞为排序的规则

  • 基础结构
redis:用于存储排行的文章id/短标题/排行字段(点赞数)
mongodb:存储文章的详细信息,包括id/用户/文章内容等聚合信息
mysql:可以利用物化视图,额外建立一个统计表存在热点排行数据
app server(服务):在在访问的时候,会更新排行的数据信息(入库,或者缓存统计)

image_uv4DS9ejRdaWVkCyaG7WDe.png

  • 日常流量QPS的满足和实时推送
1.app server: 我们以816G或32G的机器,部署4台(建议是5台这样可以提高系统的高可用)
用户行为与排行: 对于排行的规则不明确,但是可以设置合理的缓冲,如果只是评论量排序则可以考虑写入到mysql,如果是像点击量浏览量的更新则推荐异步更新
2.数据同步服务: 该服务会在系统启动的时候就会去mysql中聚合排序的结果并存入到redis和mongodb中预热(热点,前50条的数据);在有新的排行信息变动的时候,根据binlog日志信息,同步到redis中即可更新顺序,并且通知推送服务推送最新排行给用户
3.推送服务: 在用户访问的时候可利用websocket与推送服务建立连接,在有新的排行更新的时候,推送服务通过websocket推送信息到用户的界面更新
4.nginx+lua: 这一层主要是用于快速响应实时排行的数据信息结果,需要查询的时候可根据id去mongodb中获取对应信息内容

image_iNHUyCfpL1EHVM6siBP2Zv.png

  • 对上图流程的整理
*** 数据的写入和更新:
  1.当一个用户对一个文章点赞时,请求先会经过DNS,在到nginx通过负载均衡在判断出请求到那台服务器上,在上面计算出需要4台服务器,这里加一台备用的服务器,防止其他服务器宕机
  2.当请求进入服务器后,经过一些逻辑,最后将数据写入mysql的主服务器中,在通过binlog同步到2台从mysql中(这里设置的是12从),因为之前设计的redis存储的是排行的数据,所以先存入mysql中在同步到redis和mongodb中 
  3.可以建立一台数据同步服务器或者一个数据同步脚本,通过观察binlog的变化来进行将mysql的排行数据同步到redis中
  4.如果是推送类的实时更新,最后还要经过推送服务推送给用户
*** 数据的读取:
  1.不管是刷新页面或者推送都需要取服务器读取排行信息
  2.方法1:可以在请求到达nginx中,通过lua脚本去redis或者mongodb读取信息,将数据返回给用户(这种是很快的,不用经过app server,当然nginx也不只是一台)
  3.方法2:就是传统的在app server中实现去redis或者mongodb读取数据

最后针对题目的1K的QPS进行处理

// 理论上 1k qps需要9台机器,但如果一次性就9台机器是比较浪费的,平时用不上;因此这个环节主要是考察系统内部是否拥有系统状态的监控以及应对;
// 这个话题我们需要从两个角度来考虑 a. 是特殊活动可达到这么高的QPS、b. 偶然的情况才会出现这么高的QPS
a. 是特殊活动可达到这么高的QPS:
针对这个话题最合理的方案就是加临时服务器,如双十一很多商家都会选择购买临时服务器来应对
b. 偶然的情况才会出现这么高的QPS
监控: 需要自主对系统的流量进行监控(可以购买云产品)
应对: 可以针对监控情况第一个是通知、第二个是应对如降级或者扩容
降级: 比如用户请求的时候我们可以响应已经准备的缓存页面、排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)等等

以上只是本人自己理解的,如果有问题欢迎指出,大家一起讨论,共同进步