系统架构面试题(6)高并发设计

系统架构面试题(6)高并发设计

1.如果系统并发增涨100倍,怎样保障可用性?

  • 集群化部署

引入负载均衡层比如Nginx,将请求均匀打到应用层。采用集群化部署多个应用实例,确保可以动态的扩容,扛住初步的并发压力。

  • 数据库分片

单机数据库的并发能力很弱,有必要把一个库拆分为多个库,部署在多个数据库服务上。如果是读多些少的场景,可以进行读写分离,比如1主2从,主库写,从库读。

  • NoSQL数据库

如果MySQL也无法支撑,可以尝试把热门数据放入分布式NoSQL数据库,专门承载当日数据的高并发的读写。每过一段时间做数据归档,把NoSQL里不再频繁使用的冷数据迁移到MySQL里去。

  • 缓存集群

不要盲目进行数据库扩容,数据库服务器成本昂贵。针对写少读多的请求,引入缓存集群Redis,能够极大的缓解数据库的读压力。

  • 消息中间件

采用消息中间件集群,将异步化的请求写入MQ。消息的作用是削峰填谷,消费消息后才把数据落库,大大缓解数据库的写入压力。

  • 数据检索

应对海量数据的检索,可以把索引构建在Elasticsearch里,从NoSQL+MySQL的异构存储来提取明细数据即可。

2.如何解决高并发减库存问题?

关系型数据库如MySQL的单机并发能力很弱,高并发下表字段的加减操作,可能出现幻读。电商的秒杀活动典型的高并发减库存场景,这类问题有三种优化性能的思路:

  1. 异步处理减库存,而不是同步。
  2. 在内存中操作减库存。
  3. 分布式处理,分摊压力。

常见的架构方案是Redis + MQ + MySQL,操作步骤如下:

  1. 采用Redis搭建分布式缓存,在内存中操作库存值。通过数据控制模块提前将库存值放入Redis,将每个秒杀商品在Redis中用一个hash结构表示。

    "goodsId" : {
    "Total": 100
    "Booked": 0
    }

    goodsId表示商品ID,Total表示该商品的库存数量,Booked表示该商品已被订购的数量。
    扣量时,服务器通过请求Redis获取下单资格,通过以下lua脚本实现,由于Redis是单线程模型,lua可以保证多个命令的原子性。

    local vals = redis.call("HMGET", KEYS[1], "Total", "Booked");
    local total = tonumber(vals[1])
    local blocked = tonumber(vals[2])
    if not total or not blocked then
    return 0       
    end   
    if blocked + 1 <= total then
    redis.call("HINCRBY", KEYS[1], "Booked", 1)                                   
    return 1;   
    end                
    return 0

    如果HGET goodsId Booked执行结果为1,表示扣减库存成功,这是可以生成订单了。

  2. 调用接口发送创建订单消息,采用MQ的目的是对下单请求削峰填谷,也将同步下单变为了异步,前端引导用户到等待处理订单的页面。

  3. MySQL:创建订单前,保底检查一次剩余库存量是否大于1;创建订单完成,库存总量减1。

参考(摘抄的文字版权属于原作者)

https://blog.csdn.net/u010006156/article/details/124831431
https://help.aliyun.com/document_detail/63920.html

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注