1. 如何设计秒杀系统
前端:
a. 一些防刷单校验,拉长整个交易流程,起到一个削峰作用
b. 静态资源多CDN部署
c. 前端缓存,有些页面的切换,不需要调用后端接口
后端:
接口性能优化:使用缓存,异步,多线程,功能降级等手段
还有些高并发时保证系统稳定性的手段:扩容, 升配,限流,降级
还有是想做系统隔离/数据隔离的方案 这种成本很高。
需要关注的点:读请求/写请求
读请求:
商详页:包括商详接口/促销活动接口/评论接口等。不是交易强依赖的接口可以考虑降级,如评论
商详接口如何支撑更高的qps:本地缓存,redis多数据副本,增加redis副本集群。
后续交易的接口,相比商详会低很多。
写请求:
更多关注库存:库存扣减qps在300左右。要支持的到超过redis单点瓶颈,可能需要考虑多副本的方式。
2. 红包系统怎么设计
1. 模型设计
红包池表,红包账户表,红包池表
2. 怎么支持高并发?
高并发需要考虑这个并发是有多高?拿redis可支撑的写入速度作为分界线,8万/秒。
如果并发低于这个值?这个场景较好处理,使用redis作为主要的存储介质,需要使用lua脚本完成红包金额生成,红包扣减等动作。
如果高于这个值?可以考虑下吗几种方案?
一是. 使用消息队列,异步的方式,处理抢红包的请求,起到一个削峰的作用。配合的玩法,用户抢到红包后,需要一定的时间后才能打开红包。
二是. 一种类似分段id的方式,每个pod都会从db中取到一个子红包落在redis中,后面都可以依赖这个redis缓存进行扣减,如果本pod的缓存处理完,再充db中取一个子红包进行扣减。当db中扣减为0之后,再按照预设的规则尝试获取其它节点的缓存扣减。
最后,为了保证系统的稳定,一定要做限流。预期外的流量,不要接受。
3. 怎么做一个唯一id的生成器
雪花算法
41位的时间戳 + 10位机器码(机房id+机器id) + 12位序列号
时间戳是毫秒级;机器码由用户指定可能有重复的风险;12位序列号的范围是0~4096;
4. 分布式限流怎么做
使用令牌桶。原理:算法以固定的速度向桶中存放令牌;桶有一定的容量,如果桶满了,则将新生成的令牌丢弃;有请求过来会消耗令牌。
主要有4种算法:
固定窗口:边界值,无法精确限流,不可控。
滑动窗口:更为精确,但是没办法处理短时的高峰流量。
漏桶:处理请求的速度是恒定的,没有办法快速处理短暂的高峰流量
令牌:可以处理短暂的高峰流量,并且后面可以做到匀速的处理请求
如何选择QPS限流算法和令牌桶算法_金融分布式架构-阿里云帮助中心
5. 100万考生,高考排名怎么做?
思路1:计数排序
假设最高分是700
700,699,698.。。500。。。。4,3,2,1,0
每个分数一个bucket,然后存储分数对应的学生数量
6. 10亿数组去重排序
思路1:如知数组中的范围,可以按数值范围分成多个组,比如1-10000,10001-20000等。遍历原数组将每个数投递到对应范围的数组中。当然最极致的做法就是每个组一个元素,这样不需要排序就是有序的了。
如果不知道范围:
借助hash算法思想,把一个大文件哈希分割到多个小文件中,而哈希冲突的数字
一定会在同一个小文件中,从而保证了子问题的独立性,小文件可以使用set结构去重,然后就可以单独对小文件通过快速排序来排序。最后再通过多指针的方式进行全局范围的排序
7. 游戏top实时排行榜
思路1:小顶堆
8. 设计微信摇一摇功能(设计微信附近的人功能)
假设自己的位置的经纬度是j,w, i 表示范围。那么附近的人的原理就是检索范围在j-i<经度<j+i, w - i<维度< w + i;
使用数据库来做也是可以的。但是如果直接这么做的话,当用户数上亿后,检索效率会很差。
幸运的是redis中的geo结构,可以解决这个问题。
redis中的geo接口,直接提供附近x公里内,最近的n个人,并支持排序和显示实际距离。
geo,底层实现,使用二刀法,将整个地球切成无数的小块。每个小块都有固定的编码,每个编码都有负责的经纬度范围(使用base32算法)。当向geo结构中加用户时,会根据用户的经纬度确定用户在的区域块,在同一个块上的用户就会有一样的编码。所以,后面搜索附近的人的时候,就可以减少搜索的范围,在自己的小块或者周围的小块进行搜索。
9. 如何去设计一个feed流的系统
feed流系统的基本功能:比如朋友圈,一个用户的feed流,他需要展示所有好友发布的帖子。
大致的方案有3类:
1. 推型:每发一条帖子,需要向自己的所有好友。
优点:对于好友少的用户是可行的,写扩散的范围可控。
缺点:如果一个用户的好友有1万,用户每生成1条朋友圈,就会产生1万条记录
2. 拉型:用户浏览拉取所有好友的朋友圈,不主动推送
优点:比较简单,不会有写扩展
缺点:会产生读扩散,需要拉取所有好友的帖子,一起按时间排序
3. 推拉结合:先采用打标签的方式将用户分为两类:活跃和不活跃。对于活动的用户,采用推送的方式。对于不活跃的,采用拉的方式。
优点:在资源有限的情况下,至少保证核心用户的体验。
缺点:推型和拉型的缺点都是有的。
总结:相比微博大V有近的粉丝的场合,微信1万好友的上线已经是非常小了。所以在写扩散可控的情况下,可采用推型的方案。
而如果是微博这种,使用推拉结合的方式会更好些,毕竟僵尸用户比较多,只推些活跃用户就可以,没必要全量推。
怎么设计feed流的删除/更新场景?
像微信是不支持更新的,删除场景的话,其实删除点原贴就好,feed流中其实存的是帖子的id,如果原贴没有了,根据id找不到记录就是删除后了。所以发贴人将帖子删除,他的好友是立即就看不到了的。
更新的场景:因为帖子的内容只存一份,不存在写扩散,所以也很简单。
10.如何设计一个短链系统
核心功能:
短链生成:生成唯一key(只要唯一就可以,是否依据内容无所谓),将key换成62进制。然后短链为key,长链为value存放在redis和db中。最后将生成的短链返回给客户端。
短链换成长链:从缓存或db中,根据短链获取长链。
11. 超高并发场景下的直播红包发放业务的架构设计
核心问题:单个红包如果抢的人数达到100万,怎么设计这个架构。
思路:redis写场景,单点的qps上限10万。 100万,超过了单点redis的极限。所以这里的数据可能是要拆的。
思路:使用redis多副本节点,节点数据来自db。每个pod,可以按规则指定轮训消费不同副本的数据。如果消费完,需要从db里面再取。db里面没有,再去轮训消费其它副本的数据。
方案1:创建reids数组,数组里是也是数组,内层数的大小比如是10,存放的内容是红包的key。用户获取红包的请求,打到应用,应用访问redis获取可分配的红包数组,并存在本地。拿到可分配的红包key之后,查询redis获取红包。
-- 问题:在负载均衡不那么平衡的情况下,有些应用可能红包消耗的快些。用户端会出现第一次点提示红包抢完,第二次点,出现红包抢成功的情况。但是这种情况也是少量,问题不大。
方案2:将红包服务设计成可相互通信的有状态服务,本pod如果红包分配完,可以将请求转给有红包的pod
方案一的补充:如果红包金额不是等额的。创建红包时,可以提前生成每个红包的数值(这种方式,避免了在领取时计算,需要依赖红包余额的情况,避免单点数据依赖瓶颈),数据格式key-value:key是(红包id+自增id),value是对应的红包金额(这块数据可以存在db中,增加领取状态和领取的用户id)。这块数据使用使用时,需要加载到redis中。领取红包请求到pod时,可以直接使用内存的红包映射找到,具体的金额。领取红包请求获取到具体金额后,就可以投递到消息中间件了,然后向客户端返回领取的金额。扣主播红包,记录领取记录等动作可以后面再支持。
-- 存在问题:红包编码和金额映射,会暂用很多的内存空间。按一个key-value=20by计算,100万占用20M。但是,集群模式的redis,数据是分散分布,内存问题也好解决。
总结:100万的热点写并发,确实是个很难得场景,解决起来是很麻烦的。
12. id生成算法有哪些?
UUId:java的uuid使用的是版本4, 通常使用伪随机数生成器(PRNG)或加密安全随机数生成器(CSPRNG)来生成, 但理论上碰撞概率极低(2^122 的可能性),可以认为在实际应用中是唯一的。
自增id:数据库自增id、数据库段号模式(id生成服务使用)
雪花算法:毫秒时间搓 + 机房id+机器id+自增数(0-4096)