项目介绍
<p>[TOC]</p>
<p><strong>BEN</strong>(best-effort-notify)是<strong>基于最大努力通知</strong>的分布式事务解决方案。</p>
<hr />
<h3>架构图</h3>
<p><img src="https://www.showdoc.cc/server/api/common/visitfile/sign/56c2a2bf543945d9c26befc242894709?showdoc=.jpg" alt="架构图" /></p>
<h5>节点角色说明</h5>
<table>
<thead>
<tr>
<th>节点</th>
<th>角色说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>消息中间件</td>
<td>提供消息队列功能,ActiveMQ、RocketMQ等</td>
</tr>
<tr>
<td>通知服务子系统</td>
<td>业务服务实现(存储通知记录、存通知日志、更新通知状态查询等)</td>
</tr>
<tr>
<td>通知恢复子系统</td>
<td>BEN系统重启后,恢复未完成的通知记录,继续通知</td>
</tr>
<tr>
<td>通知监控子系统</td>
<td>监控系统内存、堆积消息数,当达到阈值时发送告警邮件</td>
</tr>
<tr>
<td>通知管理子系统</td>
<td>通知可视化管理后台,通知记录查看、重发、删除、通知日志查看等</td>
</tr>
<tr>
<td>DelayQueue</td>
<td>JDK自带延时队列,实现在指定时间触发通知请求</td>
</tr>
</tbody>
</table>
<hr />
<h3>流程说明</h3>
<p>假设两个业务系统的两个业务AB。基于BEN实现分布式事务流程如下:</p>
<ol>
<li>上层业务系统在完成业务处理之后,向<strong>消息中间件</strong>发送通知消息。</li>
<li><strong>BEN系统</strong>监听通知消息队列,监听到通知消息后添加通知记录到数据库。</li>
<li>根据系统配置的通知时间,设置通知任务执行时间,放入<strong>DelayQueue</strong>。</li>
<li>通知任务达到执行时候后,发送<strong>Http请求</strong>给<strong>下层业务系统</strong>。</li>
<li>添加通知日志到数据库。</li>
</ol>
<h4>异常情况处理</h4>
<ul>
<li><strong>Http请求异常</strong>:网络波动或下层业务系统Down机时(Http请求超时或响应码为5xx)。</li>
<li><strong>下层业务处理失败</strong>:下层业务系统未返回处理成功。</li>
</ul>
<pre><code>1. 通知记录会被标记为对应状态,并且添加通知日志。然后通知任务会根据系统配置的通知时间间隔,设定下次通知时间,放入DelayQueue,继续通知。
2. 下层业务系统需事先业务的幂等性
3. 当通知次数超过系统配置的最大次数,通知记录会被标记为通知失败,不再继续通知。可在通知管理子系统人工干预(删除或重新通知)。</code></pre>
<hr />
<h3>通知监控子系统</h3>
<h4>内存监控</h4>
<p>业务主动方(通知消息生产方)产生消息的速率超过业务被动方(通知消息消费方)的消费速率,就会导致消息驻留在内存中,为了防止内存溢出等情况,提前发送告警邮件。</p>
<h5>计算公式</h5>
<p>JVM剩余内存 < JVM最大内存 * 系统配置阈值百分比</p>
<h5>应对策略</h5>
<ol>
<li>发送告警邮件。</li>
<li>通知任务在保存到数据库后,只执行一次通知,无论通知成功或失败,更新通知结果到数据库,并将任务信息从内存中释放,内存监听器将休眠一段时候后重新计算内存情况,直到内存足够后,从数据库中读取休眠期间未通知成功的通知记录,继续通知。</li>
</ol>
<h4>通知监控</h4>
<p>用于监控系统堆积的通知任务数,并发送告警邮件</p>
<pre><code>如果业务被动方(通知消息消费方)停机,而业务主动方(通知消息生产方)依然继续产生通知消息,可能会导致大量通知任务由于通知异常,驻留在内存中,为了防止内存溢出等情况,提前发送告警邮件。</code></pre>
<h5>计算公式</h5>
<ul>
<li>堆积任务数 > 系统配置阈值数量</li>
<li>每分钟新增堆积任务的速率 > 系统配置阈值速率</li>
</ul>