高并发

1 细粒度锁

  • 最小化锁范围: 细粒度锁将锁的作用范围限制在最小的数据单元或操作上,而不是对整个数据结构或资源加锁。
  • 减少锁持有时间: 通过快速完成操作并尽早释放锁,减少每个线程持有锁的时间,从而减少其他线程的等待时间。
  • 锁分离:将不同的操作或数据访问分离到不同的锁上,使得多个操作可以并行执行,而不是所有操作都依赖于同一个锁。
  • 锁分段:将数据结构分割成多个段,每个段有自己的锁,这样可以同时对不同段进行操作而不会相互阻塞。
  • 无锁编程: 利用原子操作和数据结构来避免使用锁,通过CAS(Compare-And-Swap)等机制来保证数据的一致性。
  • 读写锁:允许多个读操作同时进行,但写操作需要独占锁,以此来提高读操作的并发性。
  • 锁粗化: 在某些情况下,如果一个线程需要连续访问多个资源,可以考虑将锁的范围扩大,以减少频繁的锁获取和释放。
  • 锁升级和降级:根据实际情况动态调整锁的粒度,例如从读锁升级到写锁,或者在不同级别的锁之间进行切换。
  • 避免死锁: 设计锁策略时,确保锁的获取和释放顺序一致,避免出现死锁。
  • 性能监控: 监控锁的性能,包括锁的竞争率、等待时间和吞吐量,以便根据实际情况调整锁策略。

1.1 条件变量

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

import java.util.List;

import java.util.ArrayList;


public class TaskScheduler {

private final List<Runnable> tasks = new ArrayList<>();

private final ReentrantLock lock = new ReentrantLock();

private final Condition condition = lock.newCondition();


public void addTask(Runnable task) {

lock.lock();

try {

tasks.add(task);

condition.signalAll();

} finally {

lock.unlock();

}

}


public void executeTasks() {

lock.lock();

try {

while (tasks.isEmpty()) {

condition.await();

}

Runnable task = tasks.remove(0);

task.run();

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

} finally {

lock.unlock();

}

}

}

2 高并发架构

2.1 负载均衡

2.2 分库分表

通过分库分表,可以极大的减少单点数据库的压力,提高查询效率。通过分库分表,主要解决数据量大、并发访问高的问题。通过将同一表的数据分布到多个数据库实例中,从而,提升系统的水平扩展能力。

跨多个数据库实例的事务操作变得复杂,可能需要分布式事务管理

2.3 消息队列

消息队列在系统中引入异步消息处理机制,可以削峰填谷,缓解瞬时高并发压力。

2.4 异步处理

异步处理通过将一些非实时任务放入队列异步执行,减少实时系统的响应时间。

2.5 缓存

分布式缓存,通过将频繁访问的数据,存储在快速访问的介质中,减少数据库、和后端服务的压力。

2.6 服务拆分

将大型单体应用拆分为多个小型服务(微服务架构),各服务可以独立扩展和部署。

  • 按业务功能划分

  • 按边界上下文划分

  • 数据库分离

  • 限流和熔断:限流用于控制系统的流量,使系统不至于被过载流量压垮,保护系统在高并发下的稳定性,防止系统崩溃。熔断器用于在下游服务不稳定时,快速返回错误以保护系统。

3 参考

  1. 高并发设计之细粒度锁 : 5种细粒度锁的设计技巧图解(高并发篇) (qq.com)

  2. 高并发架构方案详解(8主流高并发架构) (qq.com)

  3. 高并发解决方案详解(8大主流架构方案) (qq.com)