消息覆盖问题排查

来源:互联网 发布:xp如何打开445端口 编辑:程序博客网 时间:2024/06/06 01:28

现象
代码处理的流程:

public class EnsureTradeMsgAction implements Runnable{       private OrderMessage message;       public void run(){           id=message.getId();           model=orderService.getOrder(id);//远程调用           model.setMemberId(message.getMemberId());           model.setName(message.getName());           save(model);//保存数据库       }}

过来两条消息:
{id:1,memberId:"a",name:"a"}{id:2,memberId;"b",name:"bb"}

最后到数据库里面的两条数据是:

id memberId name1  b        bb2  b        bb

推理

通过现象可以看出来,第一条消息的部分数据被第二条消息给覆盖掉了。

分析代码推断出流程是这个样子的:

1. 接收到第一条消息
2. 取出id,执行远程调用(这个时候接收到第二条消息,覆盖了message变量)
3. 取message中的memberId和name(注意:memberId和name已经是第二条消息的值)
4. 存入数据库

原因分析

 查看action构建方式

这样构建出来的action是单例的,而其中message是成员变量,所以不是线程安全的。

<bean id="ensureTradeMsgAction" class="com.alibaba.china.levit.biz.daemon.rialto.action.EnsureTradeMsgAction"/> 注意:没有scope="prototype"

消息接收处理过程中两个采用多线程的地方:


1. 接收消息时,会按照配置的instance个数生成相应个数的session来接收消息,然后多线程调用AsyncWorker的doWork来处理
{code}public interface AsyncWorker {       boolean doWork(Serializable message);}{code}


2. rialto通过pipeline处理消息的时候,会通过线程池来处理(线程池大小由配置中的poolSize来指定)

{code}<pipeline name="bailProccess" poolSize="2" watermark="100" exception="logging">{code}{code}public void submitTask(Runnable task) {ExecutorService service = pool;if (service != null) {service.execute(task);}}{code}

excute方法的注释:Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

所以

问题发生的原因是在多线程处理的时候,message变量被后一个线程覆盖掉,导致数据不一致。

解决方案

1. 加入 scope="prototype",使每次getBean获得不同的实例,也就木有线程安全问题了。缺点:每次都要构造个实例...
2. 其他
原创粉丝点击