系统设计

- 高并发系统提性能#

读优化
多级缓存:让数据靠近计算
链路优化:合并batch请求缩短整体耗时

写优化
流量漏⽃:缓存预扣减少数据库的⽆效访问
分库分表:提升数据库的整体写⼊能⼒( 窄表设计下单分片物理机可承载4500,云服务器可承载3000,仅供参考,具体以业务测试为准 )
并⾏扣减:降低库存扣减的响应时间
分库存:解决单行更新能力不足问题,(一般单行更新的QPS在500以内)
合并请求:异步批量,将多次扣减累计计数,集中成一次扣减,从而实现了将串行处理变成了批处理。大大减轻更新压力。

扩展

  1. 如果某个sku_id的库存扣减过热,单台实例支撑不了(mysql官方测评:一般单行更新的QPS在500以内),可以考虑将一个sku的大库存拆分成N份,放在不同的库中(也就是说所有子库的库存数总和才是一件sku的真实库存),由于前台的访问流量非常大,按照均分原则,每个子库分到的流量应该差不多。上层路由时只需要在sku_id后面拼接一个范围内的随机数,即可找到对应的子库,有效减轻系统压力。
  2. 单条sku库存记录更新过热,也可以采用批量提交方式,将多次扣减累计计数,集中成一次扣减,从而实现了将串行处理变成了批处理,也可以大大减轻数据库压力。
  3. 引入RocketMQ消息队列,经过前置校验后,如果有剩余库存,则把创建订单的操作封装成消息发送给MQ,订单系统从RocketMQ中以特定的频率消费,创建订单,该方案有一定的延迟性。

- 请求幂等性#

请求幂等性总结:
1.是否需要幂等。比如查询,insert含唯一索引的表,update set数据,delete by id 等简单场景是天然幂等。不需要额外做幂等操作。无法这样的比如要做数据的累加,就要做幂等。
2.如何判断重复。
业务唯一键,查记录表或流水表,根据记录的有无和状态来判断。
3.实现。

  1. 简单的话接口直接实现, 但通常幂等逻辑是有通用性的
  2. 如果服务多接口使用写幂等工具类
  3. 如果多服务使用一套幂等逻辑,写sdk
  4. 最复杂的多服务间幂等,还无法都获取到记录结果,就要在sdk统一读写幂等表,读写相同的幂等记录做幂等
  5. 并发处理
  6. 单机情况下,使用java锁synchronized
  7. 使用数据库锁,悲观锁:select for update,乐观锁:update set XXX and version = 2 where version = 1
  8. 使用分布式锁:
    redis锁:1.过期时间导致并发问题,2.主从切换时锁丢失
    zookeeper锁:写能力不如redis

幂等设计

- 分布式锁#

方案1、基于数据库唯一主键
原理:在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。

方案2、基于redis实现分布式锁
原理:通过redis 中的命信setNx 来实现 (当key不存在则设置值并返回true,否则返回失败)

方案3、基于Zookeeper来实现分布式锁
原理:1、先建一个目录lock 2、线程A想获取锁就在lock目录下创建一个带顺序的临时节点 3、然后获取比当前顺序号小的顺序号,获取到则获取锁失败,获取不到则获取锁成功。 4、解锁则是删除这个临时节点。

- 分布式主键生成方案选择#

分布式自增ID的实现

1.uuid
组成部分:当前日期和时间、时钟序列、机器识别码

缺点:
UUID长度128bit,32个16进制字符,占用存储空间多,且生成的ID是无序的

对于InnoDB这种聚集主键类型的引擎来说,数据会按照主键进行排序,由于UUID的无序性,InnoDB会产生巨大的IO压力,此时不适合使用UUID做物理主键。

2.号段模式,底层proxy服务+数据库分段获取id
结合数据库维护一个Sequence表,每当需要为某个表的新纪录生成ID时就从Sequence表中取出对应的nextid,将其+1后更新到数据库中以备下次使用。

缺点:由于所有的插入都要访问该表,很容易造成性能瓶颈。
在高并发场景下,无法保证高性能。

3.Snowflake
使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

长度为64bit,占用存储空间多
存在时钟回拨问题, leaf已解决

- 如何实现延迟队列#

delaymq

- 高并发系统的稳定性保证#

限流,单机限流动态扩容,集群限流保护存储
隔离,业务与业务隔离,避免多业务之间互相影响。读写服务隔离,关注点不一样。环节隔离,查询和交易环节在流量和响应时间上有很大差异(api, order)。
监控,业务量级、成功失败原因、活动量级上报,尤其是失败原因。
降级

  • 非核心功能,容量问题,非核心功能。比如压力过大,先限流降级查询功能,减少入口流量,避免雪崩。
  • 非核心依赖,功能异常问题,熔断降级。eg: 直播视频制作,依赖算法,mmu,ytech,音视频,区分非核心依赖:mmu,ytech,即可做区别降级处理。发第三方券。
    全链路压测
    定期进行全链路压测评估链路流量负载能力
    总结
    事前:链路梳理,明确强弱依赖
    性能评估,容量评估,负载评估
    完善监控,明确因果,建设大盘
    降级预案,区分场景,区分等级
    事中:扩容、限流、降级、熔断
    事后:性能优化,问题修复,复盘总结

redis监控:读写qps,内存使用率,响应耗时,缓存命中率,慢查询,大key
kafka监控:消费延迟量,消费失败数量,生产&消费速率

- 双写服务迁移#

  1. 迁移模式:老服务代理新服务完成内部迁移,再推业务方做sdk迁移
  2. 双写操作:以谁为主,就同步写为主一侧,异步写另一侧,减少耗时
  3. 路由策略
    查询以灰度为准,下单以灰度为准
    退款、回滚固定以下单为准。防止一单交易不同环节分别走到新老,新老数据可能不一致。 退款回滚时,请求新老流水,根据流水路由信息,判断退款路由策略
  4. 实时响应比对:双写完, 整合两侧结果上报mq, 消费mq做结果比对,打点,告警,问题及时发现
  5. 离线数据最终一致校正:离线任务跑新老流水,判断以谁为主,以谁为主就用谁的流水校正另一侧的流水

- 领域划分#

营销平台领域划分
业务领域:触达,感知,转化,留存。
工具域:立减,拼团,积分,优惠券
基础域:选品,选人,规则,库存,预算

基建平台领域划分
前台: 代理商平台、crm平台、财务平台
业务编排:代理商引入、广告主引入、转账充值
基础域:客户域、财务域、报表分析域、销售管理域
支撑域:upm、计费、dsi、passport、审核

直播剪辑的整体流程
近实时、配置化、异步制作

  1. 自动剪辑配置,开启时段,剪辑时长,字幕,配乐,片头片尾
  2. 自动剪辑,定时任务时间驱动,每10min, 异步制作
    定时任务

-> mq异步 ( 算法视频切片 -> mmu语音转文字 -> ytech视频特效 )
-> mq复用 ( 音视频片头片尾)
注:mmu、ytech、音视频可降级。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×