Xiang Mu Wen Shi Mo

项目一般问什么 #

项目问题因人而异,但是这些问题是共性的,可以思考一下 #

  • 你最有成就感,或者最有挑战的项目经过,解决什么样的问题
  • 数据量很大还是并发量很高,并发量体现在哪里?QPS是多少?
  • 怎么提高可用性的?
  • 技术难点体现在哪里?
  • 你的项目有没有出现什么重大事故/故障,是怎么解决的,具体是什么原因
  • 有没有什么印象深刻的Bug

分布式锁如何实现 #

分布式锁,一般为了达到分布式加锁需要通过投票的机制,依次向所有节点申请加锁,半数以上节点投票通过完成加锁,可以避免单点故障(Redis称为Redlock算法)

  • 加锁的动作需要保证原子性,Redis通过Lua脚本来保证
  • 谁加的锁谁来释放锁,所以需要标记锁来源
  • 预防加锁程序挂掉导致的锁不释放,所以需要设置过期时间
  • 加锁成功需要判断获取锁总耗时没有超过锁有效时间,这才判定为加锁成功

注意:假如程序处理速度比锁过期时间要长,是不合理的设计,超时时间的设置就很精细,一般都是远大于处理的时间,如果真的处理时间太长应该判定失败并告警

redis

如何实现一个分布式id生成器 #

首先要知道自增主键出现的问题

  • 在高并发的情况下加入事务执行失败回滚,会跳过当前插入ID,使ID不连续
  • 所有数据库中的自增字段或者自增序列都要记录日志,会产生磁盘IO,会成为性能瓶颈
  • 假如数据库使用的是Range分片,自增ID可能会集中写入集群中的一个节点,出现数据访问热地世,性能退化成单机写入

解决方案

  • 随机主键UUID方案(32 个的 16 进制数字,16^32 = 2^128 就是128位),虽然可以保证每次随机都不一样,但缺点是键值长度过长,存储和计算的代价增加,uuid只能保证不重复,但数据页可能会分裂,影响查询性能
  • 号段模式,每个业务批量获取数据库中的号段,比如一次获取1000个,然后内存生成1000个自增ID,使用完再获取1000个;只需要插入一条记录,步长设置为1000,注意使用乐观锁(维护版本号),记录字段有业务类型、当前最大可用id、号段步长,version号;缺点服务重启时重新申请号段,不够随机有被猜到的风险
  • TiDB 里提供了一种AutoRandom的算法,生成64位整型随机ID1bit符号位、5bit事务开始时间,58bit自增序列号,还是有可能出现尾部热点
  • 雪花算法Snowflake,时间戳精确到毫秒,10位长度机器码最大规模1024个节点(2^10), 12位序列代表1毫秒能产生的id数量最多4096个。所以 TPS 可以达到 419 万左右(2^22*1000), 每秒那么多大多系统都够了

注意雪花算法,对时间的要求比较高,如果时间不同步,时钟回拨时 ID 有可能出现重复

引用: 分布式数据库30讲

如何优化雪花算法的问题 #

雪花算法的问题主要在于时间回拨出现id重复、机器id有上限

时钟回拨就是本机时间略快,完成时间服务器的校准(NTP或者闰秒回拨)以后,会出现时间倒退,导致生成ID重复

时钟回拨解决办法:

机器id有上限的解决办法(雪花算法优化)

  • 百度(uid-generator)的解决办法是可以自定义各部分的位数,工作机器ID需要数据库中创建一个表,插入机器相关信息(hostport),再根据表的自增ID作为workID,重启服务就另申请workID
  • 美团使用Leaf算法,可以基于号段模式或雪花算法,对号段模式优化 双buffer方案,提前加载下一号段;雪花算法借助zookeeper的持久顺序节点的特性配置workID(我想上容器的话直接使用hostname或者使用k8s中的sts也不错)

注意雪花算法实际上是趋势递增,而不是绝对递增,这是为了保证性能

如何实现秒杀系统 #

漏斗的思路,是架构上设计,客户端,网关,后台服务,层层限流,保证业务处理不被流量洪峰打挂了

客户端侧降低服务端压力:

  • 动静分离,静态资源放到cdn(某些服务为了更新及时不能放cdn)、前端文件webpack打包减少请求量
  • 减少后端请求数量,只保留抢按钮的请求
  • 时间使用客户端时间,不到时候无法点击
  • 增加互动游戏再降低并发请求量
  • 秒杀活动一旦发起,不允许修改详情等信息
  • 保证web安全,防止xss与重放(随机数、时间戳、序列号)、CSRF等攻击方式

部署架构:

  • 后端服务部署多个可用区,防止单可用区故障导致整体不可用
  • 需要配置安全策略:防火墙、防DDOS、API网关、WAF;接入风控挡掉不合法请求
  • 使用负载均衡SLB,根据不同节点负载情况分发流量
  • 硬件上使用SSD

后端防护:

  • 防止超卖,推动库存确认流程到支付阶段
  • 库存信息放到内存中(redis)
  • 使用另外的数据库集群

过载保护(有损保护):

  • 服务降级:秒杀期间关闭某些服务,比如淘宝关闭退款流程,微信抢红包延迟到账
  • 熔断:接入监控系统,根据系统节点的承载能力和服务质量有关,比如 CPU 的使用率超过 90%,请求错误率超过 5%,请求延迟超过 500ms, 它们中的任意一个满足条件就会出现熔断,主动拒绝请求;
  • 限流:速度过快时加入验证码流程,接入API网关可以进行流量控制,请求过滤和控制,并过滤的请求,前端根据错误码返回友好的页面(已抢完之类)常见限流算法:漏桶>令牌桶>滑动窗口>计数器

容灾 #

假如某个节点无法拉起,或者量级大被打挂了

追踪链的traceid是怎么生成的 #

traceID 一般由请求经过的第一个服务器生成,参考 服务器 IP + 生成 ID 的时间 + 自增序列,它的作用是把各个服务器上的调用日志串联起来

  • 前 8 位 0ad1348f 为生成 TraceId 的服务器 IP,这是一个十六进制的数字,每两位代表 IP 中的一段,把这个数字按每两位转成十进制即可得到常见的 IP 10.209.52.143,可以根据此规律来寻找请求经过的第一个服务器。
  • 后 13 位 1403169275002 是生成 TraceId 的时间。
  • 最后四位 1003 是一个自增序列,范围是 1000 到 9000,到达 9000 后回到 1000 再重新开始自增。

TraceID生成规则-蚂蚁集团方案



本图书由小熊©2021 版权所有,所有文章采用知识署名-非商业性使用-禁止演绎 4.0 国际进行许可。