me
me copied to clipboard
学习笔记: 分布式系统案例课 (杨波)
如何设计一个分布式计数服务
面试官提出需要为一个类似B站视频网站在视频下方增加观看数量。
这个题有很多解法,如果不清楚需求,就会根据自身喜好产生很多解法:
- SQL DB: MySQL, Oracle
- NoSQL: MongoDB, Cassandra
- Batch: Hadoop MR
- NewSQL: TIDB
- Cache: Redis
- Stream: Kafka+Flink
- Stream Cloud: Alibaba Cloud Realtime Compute
所以前提是对需求的澄清,包括:
- 场景用例: 谁用这个系统? 用户如何使用这个系统?
- 量级规模: 每秒查询请求? 每个请求查询多少数据? 每秒处理多少个视频观看记录? 流量模式? 是否有流量峰值?
- 性能: 预期从写入到读取数据的延迟? 预期p99(99百分位)读请求延迟是多少? 高可用性(一般是隐含,即必须)
- 成本: 开发成本有限制? 运维成本有限制?
接下来明确功能需求,即API
- 处理需求: 对视频观看数进行计数
- countViewEvent(videoId)
- countEvent(videoId, eventType), eventTypes: view, like, share
- processEvent(videoId, eventType, func), func: count, sum, avg
- processEvents(listOfEvents)
- 查询需求: 根据时间段返回视频观看数量
- getViewsCount(videoId, startTime, endTime)
- getCount(videoId, eventType, startTime, endTime)
- getStats(videoId, eventType, func, startTime, endTime)
现在假定非功能需求:
- 规模: 每秒处理1w+视频点击观看记录
- 性能1: 写入/读取毫秒级延迟
- 性能2: 写入到读取更新分钟级延迟,近实时流处理,最终一致
- 高可用: 无单点失败
- 水平按需扩展
- 开源低成本
存储设计
- 存什么?
- 点击明细还是每分钟聚合数据?
- 还是两个都存储? (好处不说了,缺点就是耗存储)
- 数据库选型
- 可扩展: 根据读写规模按需扩展
- 高性能: 快速读写
- 高可用: 不丢数据, 灾难恢复
- 一致性折衷
- 数据模型易于升级
- 成本
- MySQL 方案
- sharding: 将A-M的存在MySQL A上,N-Z的存在MySQL B上
- replication: A和A',B和B'分别做主从,实践中一般采用一主一从或一主二从
- 读写分离: A负责写,A'负责读,分摊压力
- 通过ShardingSphere(原ShardingJDBC)在客户端实现MySQL代理,避免让程序员直接面对数据库复杂度。也可以通过ShardingProxy来做独立部署,等同于配置中心加服务发现。
- Cassandra
- 去中心,采用gossip
- 支持按需动态增加节点
- 支持多数据中心
- 运维复杂性还是比较高