场景题和系统设计
分布式id
- 唯一
- 高可用
- 高性能:生成速度快、资源消耗小
- 有序性:趋势递增
- 安全:需要脱敏,不能包含订单数量等敏感信息
数据库主键自增
数据库号段
其实就是批量获取一批号,current_max_id
到current_max_id + step
,减少数据库的访问次数
1 |
|
上面两种都存在单点问题和安全问题(可以推算出订单量),而且id没有业务含义
redis incr
UUID
- 优点:生成速度快
- 缺点:存储消耗空间大、无序、基于mac地址生成的uuid不安全、无业务含义、重复问题
snowflake
1 |
|
- sign:默认为0,表示正数
- timestamp:时间戳,默认为ms
- sequence:单台机器每毫秒能产生的最大id数
优缺点
- 优点:生成速度快,id有序递增
- 缺点:重复id(时间回拨),依赖机器id对分布式环境不友好
分布式锁实现
条件
- 存储空间,可以访问到
- 唯一标识
- 至少两种状态
典型实现
- Zookeeper:先创建临时顺序节点,然后get得到所有创建的子节点,如果序号最小,认为得到锁,否则监视minmax节点,尝试继续获取锁,释放锁则删除节点。临时节点可以在网络故障的时候自动解锁,防止死锁。
- Redis:setnx,判断超时,getset设置新值返回旧值,如果还是超时说明获取了锁,否则获取失败。(会有全局时钟问题)
- MySQL
MySQL分布式锁
建表
1 |
|
加锁
1 |
|
解锁
1 |
|
select for update
加锁
1 |
|
解锁
1 |
|
设计秒杀系统
高性能
热key二级缓存:热点数据可以在redis写一份,jvm内存写一份(访问最快)
如何检测热key,京东的解决方案?
- etcd集群:worker ip和规则配置,例如userId_ 开头的key,每2s出现20次算热key之类的,过期时间之类的
- worker:上报ip,监听和计算client发来的key,达到规则的阈值后推送到client和etcd
- client:获取规则,worker ip等,定时任务每500ms批量发送一批待测key到worker(经过shard能保证固定的key的到同一个机器),已经热了的key不会再发送。收到worker推送的热key后,本地caffeine缓存。
高可用
- Redis集群,哨兵
- 限流
- 根据ip、用户限流
- 验证码
- 提前预约
- 流量削峰
- 降级:优先保障核心功能,比如关闭视频评论,保留播放功能
- 熔断:比如A要调B的接口,但是B出故障了,当A调B的失败次数到阈值后,停止A对B的调用
一致性
- 减库存方案:下单减库存(即使不付款)
- 不超卖:秒杀商品在缓存中,lua脚本,Redis中减库存成功,通过MQ异步更新到MySQL,达到最终一致性
- 余额扣减方案:悲观锁,MySQL的select for update,并发量不高可以使用乐观锁
- 接口幂等:悲观锁、乐观锁、token、唯一索引、分布式锁
- token:第一次请求时,服务器生成token带过期时间的,存入redis,第二次请求header带上token,后面先删除token再执行请求(大不了重写生成token,好过带着token再进行第二次非法操作)
Feed流实现
什么是Feed流
知乎、抖音首页推荐,朋友圈动态等。
- 纯智能推荐:兴趣点
- 纯Timeline:时间线
- 两者结合
架构设计
- 推模式:写入数据库太多
- 拉模式:存储成本低,但是实时性差
- 推拉结合:推模式写入活跃用户的数据库,不活跃的用户自己去拉
短链系统
为什么要有短链
- 短信字数限制
- 微博字数限制
- 长链生成的二维码太过复杂
短链生成
比较一般的方法
- 现在redis中查找长链,找到则说明已经生成
- 没找到就MD5或者murmurhash生成,转成62进制短码,拼成短网址,检查短网址是否存在于redis
- 如果不存在,保存长链到短链和短链到长链的映射,返回,结束
- 存在说明发生哈希冲突,加盐生成短码直到没有冲突
存在的问题?
- 外部操作太多,访问redis,hbase等
- 随着数量增加,哈希碰撞增加
- 大部分短链的有效期很短,1个月后就不再访问了,可以优化生成服务
如何优化?
- 采用自增算法生成短码
- 去掉长短映射(没必要)
- 内存自增+缓存批量区号(比如一次取10000个)
- 30天内有一次访问重置30天有效期,否则删除
第三方授权登录
OAuth 2.0
为第三方应用颁发一个有时效性的token,使第三方应用能通过token得到用户的信息
- 客户端向用户发送授权申请
- 用户同意授权
- 客户端使用获得的授权码,向认证服务器申请access token
- 认证服务器认证后,发放token
- 客户端使用token,向资源服务器申请资源
- 资源服务器确认token有效,发放资源
授权码有效期一般为5-20min,只能使用一次
二维码登录
扫码登录可以分为三个阶段:未扫描、已扫描待确认、已确认
- pc携带设备信息发送生成二维码请求至服务器
- 服务器生成二维码id,并和设备绑定,返回二维码id
- pc启动定时任务轮询服务器二维码状态,直到成功
- 用户扫描二维码,将手机登录凭证(token)和二维码id发送给服务器
- 服务器将二维码id和用户身份信息绑定,返回临时token至用户
- 用户携带临时token确认登录
- 服务器更改二维码状态为已确认,生成pc端token
- pc由于一直在轮询二维码状态,所以会得到token,后续可以凭借token访问服务端api
优惠券系统
券模板、券记录都需要持久化
场景题和系统设计
http://hhubibi.github.io/2024/08/26/system-design/