开发了个Event Queue的application,从数据库查询一条语句,然后update这条数据,接着调用rest api,这个简单的服务在load test的时候却出现了很多问题。
有的是Event Queue consumer的配置问题,也有SQL语句的问题。
1.当同时传入多条同样的参数数据时候,update语句出现死锁
解决方法:update语句的条件使用主键
2.偶尔服务会出现time out,其实是有另一个定时的job耗时太久,影响到了这个服务
解决办法:将另一个定时job的sql限定插入数据条数
3.当传入多条数据的时候,application耗尽了服务器的CPU
解决办法:将Queue的Acknowledge Mode从Auto变成Client,Max Sessions默认是1
同时限定JDBC的最大连接数量
4.这样设置了之后,Event不会一下子发送很多数据库连接请求,但同时带来个问题,一次只能处理一条,速度太慢
将Max Sessions改成更大数据后,虽然Queue Receiver变大,但从Queue Comsumers那里可以看出只有一个session在处理数据
解决办法:将Queue的Acknowledge Mode从Client变成TIBCO EMS Explicit Client,然后将App Node的Flow Limit和Thread Count设置成8
这样设置了后,这个application就可以同时处理多条数据了
5.不过速度依旧不能让人满意,于是尝试将App Node的Flow Limit和Thread Count设置成16
当同时丢入大量数据的时候,这个时候出现了不能comfirm这条message的错,由于Queue设置了MaxRedelivery为5,于是queue里多了几倍的message
而且更加严重的是Queue的Receiverm没有了,里面的message没有少,但这个进程产生的线程还在消耗服务器的资源
com.tibco.bw.palette.jms.runtime.fault.JMSEventContextFault: Error occurred when attempting to confirm a JMS message
javax.jms.IllegalStateException: Attempt to acknowledge message(s) not valid for this consumer
解决方法:在consumer的process里,加个try catch
6.其实真正的瓶颈是出现在查询语句上,把App Node的Activity Instance设置为ON后,可以看出查询的JDBC Query的Activity居然耗时700~1500毫秒
这个查询语句是用了GUID字符串的字段来查询,已经创建了index
开始考虑怎样将查询结果存在BW的缓存里面,Java Global Instance的方案或许可行,而Active Space,2.1版本不能用于BW6,这些都有点麻烦
在我用SoapUI运行这条查询语句的时候,发现速度是1毫秒,跟BW的速度简直是天差地别
那为什么这个SQL在BW中会那么慢呢?JDBC Query是pre statement的模式,而SQL Direct应该会更快,但SQL Direct不好用,改起来麻烦
于是用Sql profiler工具,将找到的SQL放在SoapUI里运行,需要上百毫秒,原来JDBC Query产生的语句字符串类型是nvarchar
而数据库字段为varchar,这样运行的时候根本就没hit中index
解决方法:将statement里的?改成convert(varchar(50),?),这样产生的sql就会hit中index