Ticket #142 (new 故障) — at Version 3

Opened 13 years ago

Last modified 13 years ago

比价系统定时任务卡死诡异问题

Reported by: huangyucai Owned by:
Priority: major Milestone:
Component: 比价 Version: 比价1.0
Keywords: 定时任务 Cc:
Due Date: 27/09/2013

Description (last modified by huangyucai) (diff)

一、故障

9月16日下午机房停电,之后服务器重启,比价系统全量同步数据的定时任务执行速度慢,直到卡死,最后报错:

第一种:

org.springframework.dao.CannotAcquireLockException: PreparedStatementCallback; SQL [INSERT INTO pp_product_type SET 

product_type_id=?,name=?,type=?,parent_id=?,pub_url=?,order_key=? ON DUPLICATE KEY UPDATE 

name=?,type=?,parent_id=?,pub_url=?,order_key=?]; Lock wait timeout exceeded; try restarting transaction; nested exception is 

java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction

第二种:

org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL [INSERT INTO pp_product SET 

product_id=?,name=?,brand_id=?,type_id=?,price=?,pic_path=?,pub_url=?, 

brand_name=?,model_name=?,series_id=?,variance_id=?,price_config=?,order_key=?,create_date=?,hot_new=?,variance_count=?,artpic_coun

t=?, 

download_count=?,article_count=?,visit_count=?,comment_count=?,comment_commend_count=?,comment_uncommend_count=?,emall_o

wned=?, 

forum_path=?,item_1=?,item_2=?,item_3=?,item_4=?,item_5=?,version=?,review_count=?,last_count_order=?,eyp_price_count=?,kzd_count=?

, price_100=?,change_rate_100=?,price_show=?,short_name=?,warranty=?,compat=?,mid_pic_path=?,video_count=?,vip_flag=?,item_6=?, 

comment_score=?,comment_total_vote=?,index_pic_path=?,index6_pic_path=?,index7_pic_path=?,concept=?,price_str=?,change_rate_str=? 

ON DUPLICATE KEY UPDATE name=?,brand_id=?,type_id=?,price=?,pic_path=?,pub_url=?, 

brand_name=?,model_name=?,series_id=?,variance_id=?,price_config=?,order_key=?,create_date=?,hot_new=?,variance_count=?,artpic_coun

t=?, 

download_count=?,article_count=?,visit_count=?,comment_count=?,comment_commend_count=?,comment_uncommend_count=?,emall_o

wned=?, 

forum_path=?,item_1=?,item_2=?,item_3=?,item_4=?,item_5=?,version=?,review_count=?,last_count_order=?,eyp_price_count=?,kzd_count=?

, price_100=?,change_rate_100=?,price_show=?,short_name=?,warranty=?,compat=?,mid_pic_path=?,video_count=?,vip_flag=?,item_6=?, 

comment_score=?,comment_total_vote=?,index_pic_path=?,index6_pic_path=?,index7_pic_path=?,concept=?,price_str=?,change_rate_str=?]; 

No operations allowed after statement closed.; nested exception is java.sql.BatchUpdateException: No operations allowed after statement 

closed.

但测试环境里跑定时任务并没有发现这类问题

二、分析
1、首先怀疑有执行慢的SQL语句,同步数据的定时任务大部分使用mysql的“insert ... ON DUPLICATE KEY UPDATE...”这样的语句
于是改造,将SQL改成insert 和 update两条语句,在执行前判断存在记录,如果不存在则insert,否则update。但问题并没有解决。定时
任务依旧会卡死

2、从第一种异常看,有锁表的现象,事务重新启动,第二种异常,statement 等待时间长被关闭导批量更新异常。 猜测事务未提交所致
比价系统是使用spring的aop管理事务的,我们试图改用手动管理事务:
a、使用了spring的TransactionTemplate,即在spring配置文件中配置一个TransactionTemplate的bean

<bean id="transactionTemplate"  class="org.springframework.transaction.support.TransactionTemplate">  
		<property name="transactionManager" ref="transactionManager" />
	</bean>
	 <tx:annotation-driven transaction-manager="transactionManager"/>

b、对定时任务的service方法加上去掉事务管理的注解

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=false)

c、通过 transactionTemplate方式手动控制提交事务

 Object object = transactionTemplate.execute(new TransactionCallback() {  
            public Object doInTransaction(TransactionStatus status) {  
                try {  
                    // 数据库操作 
                } catch (Exception e) {  
                    status.setRollbackOnly();  
                    e.printStackTrace();  
                }  
                return null;  
            }  
        });  


测试发现速度依旧很慢,最后抛相同的异常
尝试把控制事务提交的代码改成如下:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
					def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
					def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

					if (isExists > 0) {// 更新
						TransactionStatus status = transactionManager
								.getTransaction(def);
						try {
							simpleJdbcTemplate.update(updSql, getRecordMap(rs));
							transactionManager.commit(status);
						} catch (Exception e) {
							transactionManager.rollback(status);
							e.printStackTrace();
					}

异常依旧在
期间,请DBA检查并没有发现慢的语句,但偶尔发现会锁表

3、估计在执行定时任务时,使用的是spring的SimpleJdbcTemplate,事务可能未提交,于是调整直接用jdbc来执行数据库操作
数据源用配置jndi的数据源,方法代码如下

	Context ctx = new InitialContext();
	ctx = new InitialContext();
	DataSource ds =(DataSource)ctx.lookup("java:comp/env/jdbc/priceparity");
	return  ds.getConnection();

采用jdbc执行一次提交一次事务:
conn.setAutoCommit(false);
执行
conn.commit();
但是执行速度越来越慢,执行时间成2倍数增长,最后达到约120秒每次, 线程卡死,并抛出异常:

 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during commit(). 

Transaction resolution unknown.

4、因为spring配置service包下的类均会开启事务, 写在service包下的类会受到影响,而且数据的链接用的是jndi的配置,配有一定的活动链接数,在执

行时间较长的任务时,Connection可能被重置或关闭。
鉴于此,我们将定时任务的业务类写在另外一个包job下,连接数据库直接用jdbc的方式:

Class.forName("com.mysql.jdbc.Driver").newInstance();
String url="jdbc:mysql://192.168.75.100:3315/priceparity_new?user=priceparity_app&password=priceparity_app";
return DriverManager.getConnection(url);

每次执行insert和update后都提交事务
执行产品信息同步任务,发现不会卡死,每次执行时间为约为0.2秒,速度依旧慢,产品数据总量越有28万,但是能完成执行,不会抛出异常
将同步爬虫数据的定时任务也按照这种方法改造,执行速度可以约5毫秒每条。

问题的根本原因暂时未找到,初步判定原因
1、jndi方式的数据库连接在长时间内会被关闭或者回收
2、spring事务管理的配置引起
3、mysql数据库端的问题。

Change History

comment:1 Changed 13 years ago by huangyucai

  • Type changed from Bug to 故障

comment:2 Changed 13 years ago by huangyucai

  • Keywords 定时任务 added

comment:3 Changed 13 years ago by huangyucai

  • Description modified (diff)
Note: See TracTickets for help on using tickets.