• 作者:老汪软件技巧
  • 发表时间:2024-12-27 04:04
  • 浏览量:

一、实现目的二、基础中间件的并发三、解决1、满足QPS,保证高可用

nginx负载均衡图示.png

Nginx 把请求均匀的分摊给应用服务器,这样即使某一个服务器宕机也不会影响请求的处理,或者当应用服务器扛不住了,可以随时进行扩容。Nginx 主要的负载均衡策略(内置的负载均衡)有以下四种:轮询策略(默认负载均衡策略)、最少连接数负载均衡策略、ip-hash 负载均衡策略、权重负载均衡策略

支持的QPS数量 = 应用数量 * Tomcat支持并发数 < nginx并发数

nacos集群部署图示.png

通过在多台服务器上部署 Nacos 实例,并将这些实例配置为集群模式,可以确保当某个节点出现故障时,其他节点仍然能够正常提供服务,从而保证业务的连续性。

redis主从架构图示.png

在主从模式下,主节点负责处理所有的写操作,并将写操作记录在内存中的缓冲区。从节点从主节点获取这些写操作记录,并在自己的数据库上执行这些操作,从而保持与主节点的数据一致。

redis哨兵模式图示.png

在哨兵模式下,哨兵节点会定期检查主节点和从节点的运行状态。如果发现主节点发生故障,哨兵节点会在从节点中选举出一个新的主节点,并通知其他的从节点和哨兵节点。

redis集群模式图示.png

在集群模式下,Redis使用一种叫做哈希槽的技术来实现数据的分片。整个哈希空间被分成16384个哈希槽,每个节点负责一部分哈希槽。当一个键需要被存储时,Redis会根据键的值计算出一个哈希值,然后根据哈希值决定将这个键存储在哪个节点上。这样,读写请求就可以在多个节点上并行处理,提高了系统的性能。

应用场景数据量大,需要高性能和高可用性,可选择集群模式

熔断策略:

慢调用比例:当每秒请求量超过设定的阈值时,开始记录慢调用,当慢调调用比例超过设定的阈值时,开启熔断。>2. 异常比例:当每秒请求量超过设定的阈值时,开始记录异常比例,当异常比例超过设定的阈值时,开启熔断。>3. 异常数:当每秒请求量超过设定的阈值时,异常数超过设定的阈值,开启熔断。2、避免超卖,保证数据一致性

秒杀前将商品的库存信息保存到Redis中,秒杀期间扣减逻辑在Redis中执行,订单产生由消息队列异步写入数据库中,购买成功后返回给客户端状态,客户端进入下一步界面查询订单(订单ID),客户端定时轮询结果

基于Redis Key值的分布式锁

每次只允许一个线程操作,库存减为0时,返回库存不足。

 public int createOrderByRedisLock(Integer productId, Integer count) {
   String key = "stock:" + productId;
   int stock = (int) redisTemplate.opsForValue().get(key);
   if (stock <= 0) {
       throw new StockLackException("库存不足");
   }
   RLock lock = redissonClient.getLock(LOCK_KEY);
   if (lock.tryLock()) {
       try {
           int stock1 = (int) redisTemplate.opsForValue().get(key);
           if (stock1 >= count) {
               Order order = new Order();
               order.setUserId((int) Thread.currentThread().getId());
               order.setProductId(productId);
               order.setCount(count);
               order.setOrderTime(new Date());

秒杀解题技巧_秒杀的实现思路_

baseMapper.insert(order); redisTemplate.opsForValue().decrement(key, count); } else { throw new StockLackException("库存不足"); } } finally { lock.unlock(); } } return 1; }

基于lua 脚本原子操作

原理与分布式锁类似,将库存判断与扣减的过程原子化,省去加锁的过程。返回 -2 时,表示库存未初始化,需要先初始化库存到缓存中,而且只能有一个线程执行初始化的操作,所以这里也需要加锁,初始化之前进行一次非空判断,防止重复初始化;初始化完成后,重新校验一次库存。

local key = KEYS[1]               -- 获取第一个参数作为键名
local incrementBy = tonumber(ARGV[1])  -- 获取第二个参数作为增量值,并将其转换为数字类型
local stock = redis.call("GET", key)  -- 通过GET命令获取键的当前值
if nil == stock or not stock then
   return -2  -- 库存还未初始化
elseif tonumber(stock) >= incrementBy then
   return redis.call('DECRBY', key, incrementBy)  -- 库存充足
else
   return -1  -- 库存不足
end

3、避免脚本,保证数据安全四、测试

Jmeter分布式压测图示.png

参考:

Jmeter分布式压测(基于阿里云服务器)

springboot 结合mysql、redis+lua 实现库存扣减方案,防止超卖

【系统架构设计】秒杀场景下的用户动态URL生成逻辑

Redis三种高可用模式:主从、哨兵、集群

一篇文章让你搞懂 Nginx 的负载均衡


上一条查看详情 +Conda 环境中,更换 R 语言的镜像源
下一条 查看详情 +没有了