- 作者:老汪软件技巧
- 发表时间:2024-12-27 04:04
- 浏览量:
一、实现目的二、基础中间件的并发三、解决1、满足QPS,保证高可用
Nginx 把请求均匀的分摊给应用服务器,这样即使某一个服务器宕机也不会影响请求的处理,或者当应用服务器扛不住了,可以随时进行扩容。Nginx 主要的负载均衡策略(内置的负载均衡)有以下四种:轮询策略(默认负载均衡策略)、最少连接数负载均衡策略、ip-hash 负载均衡策略、权重负载均衡策略
支持的QPS数量 = 应用数量 * Tomcat支持并发数 < nginx并发数
通过在多台服务器上部署 Nacos 实例,并将这些实例配置为集群模式,可以确保当某个节点出现故障时,其他节点仍然能够正常提供服务,从而保证业务的连续性。
在主从模式下,主节点负责处理所有的写操作,并将写操作记录在内存中的缓冲区。从节点从主节点获取这些写操作记录,并在自己的数据库上执行这些操作,从而保持与主节点的数据一致。
在哨兵模式下,哨兵节点会定期检查主节点和从节点的运行状态。如果发现主节点发生故障,哨兵节点会在从节点中选举出一个新的主节点,并通知其他的从节点和哨兵节点。
在集群模式下,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分布式压测(基于阿里云服务器)
springboot 结合mysql、redis+lua 实现库存扣减方案,防止超卖
【系统架构设计】秒杀场景下的用户动态URL生成逻辑
Redis三种高可用模式:主从、哨兵、集群
一篇文章让你搞懂 Nginx 的负载均衡