🌌 高并发处理原理与流程
1. 分布式锁的使用
- 🔗 用途在任务开始时,通过分布式锁(
RLock
)来确保只有一个实例(或线程)可以执行特定的操作。 - 🔗 实现使用
Redisson
提供的RLock
实现分布式锁。 - 🔗 锁策略只有成功获取锁的实例可以设置
countDownLatch
和数据拉取的截止时间。
2. 信号量控制
- 🔗 用途使用
Semaphore
控制同时访问共享资源(如API调用)的线程数量,防止系统过载。 - 🔗 配置信号量的大小由配置文件中的最大行数参数决定,限制了同时进行的API调用数量。
3. 多线程异步执行
- 🔗 任务执行器使用
Executor
来并行执行任务,提高系统的吞吐量。 - 🔗 任务分配将上报数据任务分配到多个线程中执行,每个线程处理一部分数据。
4. 分批处理数据
- 🔗 分批策略按照配置的最大行数将数据分批,每批数据在一个新的事务中处理。
- 🔗 数据处理每批数据由
ReportProcessReceive
处理,确保数据在独立的事务中被处理。
5. 数据一致性保证
- 🔗 事务管理使用
@Transactional
注解确保数据处理在事务范围内执行,保证数据的一致性。 - 🔗 事务传播行为采用
REQUIRES_NEW
传播行为确保每批处理都在新的事务中。
6. 定时任务调度
- 🔗 任务调度使用
XXL-Job
定时任务调度器来定时触发数据上报任务。 - 🔗 分片执行任务根据分片参数执行,每个分片处理一部分任务,从而分散负载。
7. 协调多实例
- 🔗 协调机制使用
CountDownLatch
协调多实例任务,确保所有实例均完成任务后再进行下一步。 - 🔗 CountDownLatch管理每个数据API枚举有一个对应的
CountDownLatch
来管理同步。
8. XxlJob
分片原理
XxlJob
是一个分布式任务调度平台,它支持分片执行,可以将一个大任务分布在多个执行器或节点上运行,以提高处理效率和缩短任务完成时间。以下是关于XxlJob
分片原理和逻辑的详细解析:
分片原理
-
任务拆分:
XxlJob
允许将一个大任务拆分成多个小任务(分片),并将这些小任务分配给不同的执行器实例(节点)。 -
分片参数:在任务配置时,可以设置分片参数,例如分片总数。这决定了任务将被拆分成多少个子任务。
-
分片标识:每个子任务被分配一个唯一的分片标识(
shardIndex
),它是从0开始的索引,用于标识每个子任务。
逻辑实现
在ReportJob
类中,XxlJob
的分片逻辑如下:
-
获取分片信息:
shardTotal
:获取总的分片数量。shardIndex
:获取当前执行器实例的分片索引。
-
分片数据处理:
- 根据
shardIndex
和shardTotal
,每个执行器实例处理一部分数据。例如,如果有10个分片,则每个分片处理整体任务的1/10。
- 根据
-
并发控制:
- 使用
Redisson
的RLock
和RCountDownLatch
进行并发控制。 RLock
确保设置拉取数据截止时间的操作是原子性的。RCountDownLatch
用于等待所有分片的任务完成。
- 使用
-
任务执行:
- 每个分片执行器独立执行其分配的任务。
- 任务可能包括数据拉取、处理和上报等。
-
任务同步:
- 所有分片完成后,再执行后续操作。这通过
RCountDownLatch
实现,确保所有分片都完成了自己的部分任务。
- 所有分片完成后,再执行后续操作。这通过
使用场景
XxlJob
的分片特性适用于需要大规模并行处理的任务,特别是当单个任务的执行时间较长或处理数据量很大时。通过分片,任务可以在多个节点上并发执行,有效提高了任务的处理速度和系统的吞吐量。
总结
XxlJob
的分片功能为分布式任务处理提供了高效的方法,通过将大任务分散到多个节点上,它可以显著提高处理效率。同时,结合Redisson
的并发控制工具,它能够保证任务的同步和一致性。
🌌 注意事项
- 锁竞争确保对分布式锁的使用正确管理,避免死锁或长时间锁占用。
- 事务边界明确每批数据处理的事务边界,防止事务过大导致的性能问题。
- 资源限制合理配置信号量大小,避免过多并发请求超过系统容量。
- 错误处理异常情况下确保释放分布式锁,避免资源泄露。
1. 分片原理及使用
- 原理分片是将一个大任务拆分成多个小任务,这些小任务可以在不同的节点或线程上并行执行。它通常基于数据的分布或任务的数量来实现。
- 实现在代码中,分片通过
FrameworkJobHelper.shardList(ids)
实现。这个方法可能基于数据的ID或其他属性将总任务分成若干个子任务,每个子任务处理一部分数据。 - 使用每个分片独立处理数据的一个子集,这有助于分散和平衡负载,提高整体处理速度。
2. 分批处理与事务
- 分批处理将大量数据切分成更小的数据块,每个块作为一个单独的处理单元。
- 事务产生每个数据批次的处理被包装在一个新的事务中。这是通过
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
实现的。 - 事务作用确保每批数据的处理具有原子性和一致性。如果处理过程中出现异常,只会影响当前批次的事务,不会影响到其他事务。
3. CountDownLatch 和 Semaphore 的配合
- CountDownLatch
- 职责同步多个执行流程,确保它们在特定点齐头并进。
- 原理等待直到计数器归零,然后所有等待的线程或流程才能继续执行。
- 用途在上报任务中用于确保所有分片的数据处理完成后,才进行下一步操作。
- Semaphore
- 职责限制同时访问共享资源的线程数量。
- 原理基于信号量的值允许或限制访问。当信号量为0时,阻止更多线程的访问。
- 用途在API调用中限制同时进行的调用数量,防止资源过载。
- 相互配合
CountDownLatch
用于同步任务的整体完成,而Semaphore
用于控制并发级别。它们共同确保了任务既能高效执行又不会超出资源限制。
4. 责任链模式在代码中的实现
- 原理责任链模式允许多个对象处理一个请求,形成一条链。请求在链上依次传递,直到被处理。
- 实现在
ReportProcessContext
中,多个处理步骤(IReportProcess
实例)组成了一条处理链。每个处理步骤接收上下文对象,执行特定操作,并可能修改上下文状态。 - 流程在
ReportProcessReceive
中,上报处理任务被传递给责任链的每个节点。每个节点(处理步骤)依次对数据进行处理,可能包括数据转换、验证、发送等。 - 用途责任链模式在此处用于解耦各个处理步骤,使得每个步骤专注于单一职责,提高了代码的可维护性和可扩展性。