java系统设计 面试题
系统设计 面试题
高可用、高并发、高性能。
可用性、一致性。
分布式、高并发场景
遇到高并发场景,可以使用Redis缓存、Redis限流、MQ异步、MQ削峰等。
Q:在实践中,遇到过哪些并发的业务场景?
秒杀。比如抢商品,抢红包。
秒杀
Q:如何设计一个秒杀/抢券系统?
可以通过队列配合异步处理实现秒杀。
使用redis的list,将商品push进队列,pop出队列。
异步操作不会阻塞,不会消耗太多时间。
Q:如何提高抢券系统的性能?
使用多个list。
使用多线程从队列中拉取数据。
集群提高可用性。
MQ异步处理,削峰。
Q:秒杀怎么避免少卖或超卖?
redis是单进程单线程的,操作具有原子性,不会导致少卖或者超卖。
另外,也可以设置一个版本号version,乐观锁机制。
- 并发量不大,可以使用乐观锁,简单实用:
update tb_sku_stock set stock = stock - num where sku_Id = '具体id' and stock - num >= 0;
- 并发量大,将库存放到 redis 缓存,利用redis的incrby特性来扣减库存。
异步处理逻辑?
** Q:应该在什么时候扣除库存,是下单后扣除库存还是支付后扣除库存呢?为什么?**
答:应该在下单的时候扣除库存,如果在支付成功再扣除库存的话会出现下单请求成功数量大于库存的情况。
可以在提交订单时扣减库存。
签到系统
Q:考勤打卡,假如高峰期有几万人同时打卡,那么怎么应对这种高并发?
使用Redis缓存。
员工点击签到,可以在缓存中set状态。将工号作为key,打卡状态作为value,打卡成功为01,未打卡或者打卡失败为00,然后再将数据异步地写入到数据库里面就可以了。
缺陷是如果我们用redis的string存储,一年就要存10000*365个key,会占用大量的内存。。
更好的方案。使用MQ削峰。
员工点击签到,把打卡的数据发到MQ里面,包括工号,姓名,打卡时间,打卡成功的状态,然后再将数据异步地写入到数据库里面就可以了。
其他思路,使用BitMap数据结构,详情见: https://blog.csdn.net/qq_35620342/article/details/119480213
Q:如何应对高峰期的超高并发量?
Redis限流。
Redis可以用计数器限流。使用INCR命令,每次都加一,处理完业务逻辑就减一。然后设置一个最大值,当达到最大值后就直接返回,不处理后续的逻辑。
Redis还可以用令牌桶限流。使用Redis队列,每十个数据中push一个令牌桶,每个请求进入后会先从队列中pop数据,如果是令牌就可以通行,不是令牌就直接返回。
延时队列
Q:如何用 Redis 实现一个延迟队列?
Redis的 zset ,具有去重有序(分数排序)的功能。
可以使用 zset(sortedset)这个命令,用设置好的时间戳作为score进行排序,使用 zadd score1 value1 ....命令就可以一直往内存中生产消息。再利用 zrangebysocre 查询符合条件的所有待处理的任务,通过循环执行队列任务即可。
也可以通过 zrangebyscore key min max withscores limit 0 1 查询最早的一条任务,来进行消费。
短链接
Q:如何将长链接转换成短链接,并发送短信?
短URL从生成到使用分为以下几步:
- 有一个服务,将要发送给你的长URL对应到一个短URL上.例如www.baidu.com -> www.t.cn/1
- 把短url拼接到短信等的内容上发送.
- 用户点击短URL,浏览器用301/302进行重定向,访问到对应的长URL.
- 展示对应的内容.
Q:长链接和短链接如何互相转换?
思路是建立一个发号器,每次有一个新的长URL进来,我们就增加一,并且将新的数值返回.第一个来的url返回"www.x.cn/0",第二个返回"www.x.cn/1".
参考资料:https://blog.csdn.net/xlgen157387/article/details/80026452
Q:长链接和短链接的对应关系如何存储?
如果数据量小且qps低,直接使用数据库的自增主键就可以实现.
还可以将最近/最热门的对应关系存储在K-V数据库中,这样子可以节省空间的同时,加快响应速度.
微博feed流
Q:设计一个微博、朋友圈之类的feed流系统。
一、消息可靠性要求高。
发送了消息之后,不能丢数据。
二、消息的排序。
- 按发布的时间顺序排序,先发布的先看到,后发布的排列在最顶端。Feed流中的Feed不多,可以选择这种方式。
- 按某个非时间的因子排序,一般是按照用户的喜好度排序,用户最喜欢的排在最前面,次喜欢的排在后面。这种一般假定用户可能看到的 Feed 非常多,而用户花费在这里的时间有限,那么就为用户选择出用户最想看的 Top N 结果,场景的应用场景有图片分享、新闻推荐类、商品推荐等。
三、存储
Feed数据量比较少,就类比于空间说说,这种可以直接用 MySQL存储和查询。复杂的 Feed 流还要加上 NoSQL 数据库做缓存。
四、推送
(1)拉模式
也称为读扩散,用户主动去拉取关注人的 Feed 内容。
即当一个用户(特别是关注了很多人)触发行为时,拉取自己动态,检索用户的关注表,然后根据关注表检索新发的feed。如果一个用户关注过多的时候,查询该用户的关注列表也是有很大数据成本。
(2)推模式
也成为写扩散,当用户添加 Feed 时,会自动将 Feed 通知给关注的人(优选)。
即当一个用户触发行为(比如发微博),自身行为记录到行为表中,同时也对应到这个用户的粉丝表,为每个粉丝插入一条feed。但是对于粉丝过万的大V,为每个粉丝插入一条feed对存储数据成本很大。
使用 Redis Sorted Sets(方便按时间排序 Timeline)维护粉丝的 Feed 集合,当博主添加 Feed 时,主动将内容推送到粉丝的 Feed 集合中,这样用户可以很方便快速从集合中读取。
(3)推拉结合
比如微博,大部分用户的账号关系都是几百个,但是有个别用户是 1000 万以上才使用。
(4)在线推,离线拉
参考资料:https://blog.csdn.net/m0_69378598/article/details/124126280
系统架构与设计
Q:如何提高系统的并发能力?
使用分布式系统。
部署多台服务器,并做负载均衡。
使用缓存(Redis)集群。
数据库分库分表 + 读写分离。
引入消息中间件集群。
Q:海量数据业务有哪些优化手段?
- 缓存加速
- 读写分离
- 垂直拆分
- 分库分表
- 冷热数据分离
- ES助力复杂搜索
- NoSQL
- NewSQL
详情见: https://mp.weixin.qq.com/s/plI3wkLqtremcIkjz8hPaQ
Q:设计一个红包系统,需要考虑哪些问题,如何解决?(本质上也是秒杀系统)
Q:如果让你设计一个消息队列,你会怎么设计?