一份热乎乎的字节面试真题(二)

chujichenxuyuan
发布于 2022-6-29 11:19
浏览
0收藏

8. 说说你做过最有挑战性的项目, 你负责那个模块,哪些最有挑战性,说说你做了哪些优化

 

项目这块的话,大家可以结合自己实际做的项目说哈。也可以加我微信,跟我一起交流哈,加油加油。

 

9.秒杀采用什么方案。


设计一个秒杀系统,需要考虑这些问题:一份热乎乎的字节面试真题(二)-鸿蒙开发者社区如何解决这些问题呢?

 

 •  页面静态化
 •  按钮至灰控制
 •  服务单一职责
 •  秒杀链接加盐
 •  限流
 •  分布式锁
 •  MQ异步处理
 •  限流&降级&熔断


9.1 页面静态化


秒杀活动的页面,大多数内容都是固定不变的,如商品名称,商品图片等等,可以对活动页面做静态化处理,减少访问服务端的请求。秒杀用户会分布在全国各地,有的在上海,有的在深圳,地域相差很远,网速也各不相同。为了让用户最快访问到活动页面,可以使用CDN(Content Delivery Network,内容分发网络)。CDN可以让用户就近获取所需内容。

 

9.2 按钮至灰控制


秒杀活动开始前,按钮一般需要置灰的。只有时间到了,才能变得可以点击。这是防止,秒杀用户在时间快到的前几秒,疯狂请求服务器,然后秒杀时间点还没到,服务器就自己挂了。

 

9.3 服务单一职责


我们都知道微服务设计思想,也就是把各个功能模块拆分,功能那个类似的放一起,再用分布式的部署方式。

 

如用户登录相关的,就设计个用户服务,订单相关的就搞个订单服务,再到礼物相关的就搞个礼物服务等等。那么,秒杀相关的业务逻辑也可以放到一起,搞个秒杀服务,单独给它搞个秒杀数据库。” 服务单一职责有个好处:如果秒杀没抗住高并发的压力,秒杀库崩了,服务挂了,也不会影响到系统的其他服务。

 

9.4 秒杀链接加盐


链接如果明文暴露的话,会有人获取到请求Url,提前秒杀了。因此,需要给秒杀链接加盐。可以把URL动态化,如通过MD5加密算法加密随机的字符串去做url。

 

9.5 限流


一般有两种方式限流:nginx限流和redis限流。

 

 •  为了防止某个用户请求过于频繁,我们可以对同一用户限流;
 •  为了防止黄牛模拟几个用户请求,我们可以对某个IP进行限流;
 •  为了防止有人使用代理,每次请求都更换IP请求,我们可以对接口进行限流。
 •  为了防止瞬时过大的流量压垮系统,还可以使用阿里的Sentinel、Hystrix组件进行限流。


9.6 分布式锁


可以使用redis分布式锁解决超卖问题。

 

使用Redis的SET EX PX NX + 校验唯一随机值,再删除释放锁。

if(jedis.set(key_resource_id, uni_request_id, "NX", "EX", 100s) == 1){ //加锁
    try {
        do something  //业务处理
    }catch(){
  }
  finally {
       //判断是不是当前线程加的锁,是才释放
       if (uni_request_id.equals(jedis.get(key_resource_id))) {
        jedis.del(lockKey); //释放锁
        }
    }
}

在这里,判断是不是当前线程加的锁和释放锁不是一个原子操作。如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁。一份热乎乎的字节面试真题(二)-鸿蒙开发者社区为了更严谨,一般也是用lua脚本代替。lua脚本如下:

if redis.call('get',KEYS[1]) == ARGV[1] then 
   return redis.call('del',KEYS[1]) 
else
   return 0
end;

9.7 MQ异步处理


如果瞬间流量特别大,可以使用消息队列削峰,异步处理。用户请求过来的时候,先放到消息队列,再拿出来消费。

 

9.8 限流&降级&熔断


 •  限流,就是限制请求,防止过大的请求压垮服务器;
 •  降级,就是秒杀服务有问题了,就降级处理,不要影响别的服务;
 •  熔断,服务有问题就熔断,一般熔断降级是一起出现。


10. 聊聊分库分表,分表为什么要停服这种操作,如果不停服可以怎么做


10.1 分库分表方案


 •  水平分库:以字段为依据,按照一定策略(hash、range等),将一个库中的数据拆分到多个库中。


 •  水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。


 •  垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。


 •  垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。


10.2 常用的分库分表中间件:


 •  sharding-jdbc(当当)


 •  Mycat


 •  TDDL(淘宝)


 •  Oceanus(58同城数据库中间件)


 •  vitess(谷歌开发的数据库中间件)


 •  Atlas(Qihoo 360)


10.3 分库分表可能遇到的问题


 •  事务问题:需要用分布式事务啦


 •  跨节点Join的问题:解决这一问题可以分两次查询实现


 •  跨节点的count,order by,group by以及聚合函数问题:分别在各个节点上得到结果后在应用程序端进行合并。


 •  数据迁移,容量规划,扩容等问题


 •  ID问题:数据库被切分后,不能再依赖数据库自身的主键生成机制啦,最简单可以考虑UUID


 •  跨分片的排序分页问题(后台加大pagesize处理?)


10.4 分表要停服嘛?不停服怎么做?


不用。不停服的时候,应该怎么做呢,分五个步骤:

 

1.编写代理层,加个开关(控制访问新的DAO还是老的DAO,或者是都访问),灰度期间,还是访问老的DAO。

2.发版全量后,开启双写,既在旧表新增和修改,也在新表新增和修改。日志或者临时表记下新表ID起始值,旧表中小于这个值的数据就是存量数据,这批数据就是要迁移的。
3.通过脚本把旧表的存量数据写入新表。
4.停读旧表改读新表,此时新表已经承载了所有读写业务,但是这时候不要立刻停写旧表,需要保持双写一段时间。
5.当读写新表一段时间之后,如果没有业务问题,就可以停写旧表啦

标签
已于2022-6-29 11:19:06修改
收藏
回复
举报
回复
    相关推荐