gyb优化事项(2)
来源:互联网 发布:js中的this详解 编辑:程序博客网 时间:2024/05/16 17:31
1.SEMQ流量控制(已修改trunk 2014-7-22)
DAS测试过程中,5.17下午开始就没有新的单据导入了,tb_0031在此后没有新的记录生成。检查日志:发现没有可用数据库连接。
[2014-05-17 23:59:41:685][线程6152][1][20][0][][33]连接id=33,使用状态=已使用,取用时间=66986(秒),拥有者线程=5384.[2014-05-17 23:59:41:685][线程6152][1][20][0][][34]连接id=34,使用状态=已使用,取用时间=66986(秒),拥有者线程=4028.
检查占用连接的线程(如4028),看为什么没有释放。
int CBBoxPlugin::OnRespInquiry(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) { if (ack==0) result = semq_.Resend(ref_object_id);
4028线程占用了数据库连接.
从日志看,该线程阻塞在semq_.Resend调用上。
////////////////////////////////////////////////////////////////////////////////int CSEMQ::SendRecord(CQQ_OBJECT_ID object_id) { CSendTaskItem *sti = new CSendTaskItem; sti->action_ = 1; sti->type_ = 1; sti->object_id_ = object_id; ACE_Message_Block *mb = 0; ACE_NEW_RETURN(mb,ACE_Message_Block(sizeof(CSendTaskItem*)),-1); memcpy(mb->rd_ptr(),&sti,sizeof(CSendTaskItem*)); pre_send_task_.putq(mb); return 0;} ////////////////////////////////////////////////////////////////////////////////int CSEMQ::Resend(CQQ_OBJECT_ID object_id) { string sql = LogMsg("update %s set f009n_0031=0 where object_id=%I64d",this->GetTableName(),object_id); USEDBC(pdbor,this->dbc_name_.c_str()); int ret = pdbor->Execute(adCmdText,sql.c_str()) ? 0 : -1; if (ret==0) { SendRecord(object_id); } return ret;} ////////////////////////////////////////////////////////////////////////////////int CPreSendTask::handle_message_block(ACE_Message_Block *mb) { CSendTaskItem *sti = 0; memcpy(&sti, mb->rd_ptr(), sizeof(CSendTaskItem*)); mb->rd_ptr(sizeof(CSendTaskItem*)); if (sti->action_==1) { string sql; if (sti->type_==1) {//////< 直接根据object_id发送 sql = LogMsg("select object_id,dest_type,dest_id,f018c_0031,f005n_0031,f019n_0031,f023v_0031 from %s where object_id=%I64d and f009n_0031=0 order by object_id",semq_->GetTableName(),sti->object_id_); } else { sql = sti->sql_; } ///< @note semq_.GetData必须成功. short report_flag = 0; while(semq_->GetData(sql)) { ///< GetData失败只有在数据库故障,或与数据库服务器通信的网络故障时才发生 ///< 此时间检查数据库服务是否有效 short db_svc_flag = 0; ///< 数据库服务是否有效 do { USEDBC(pdbor,semq_->GetDBCName()); db_svc_flag = pdbor->GetDBExt()->CheckDBService(); if (db_svc_flag!=0&&report_flag==0) { ///< @todo 报告给监控者 GetLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_EMERGENCY,"CPreSendTask::handle_message_block检测到%s数据库故障.\n",semq_->GetDBCName()); report_flag = 1; } ACE_OS::sleep(5); ///< 出现一次故障后至少等待5秒 if (db_svc_flag==0) { break; } } while(1); } } delete sti; return 0;}
阻塞在GetData函数上,此函数一直没有结束.
int CSEMQ::GetData(string &sql)
和发送队列有关。
int cnt = send_task_[st_index].putq(mb);
处理很慢,处于堆积状态。但仍在执行。
[2014-05-19 13:44:11:093][线程7000][2][20][0][]CSEMQ::GetData 发送队列序号0, 队列个数32769
为什么send_task_这么慢呢?
int CSEMQ::Send(SHORT_SEMQ_RECORD *ssr)---此函数慢
每次TraceAction要6分钟。流量控制导致的,大量的消息没有返回。
SEMQ的默认水标:300。超时300秒(5分钟)。
测试环境下bbox.conf的配置
<inquiry_timer_interval>60</inquiry_timer_interval><inquiry_interval>1</inquiry_interval>问询间隔为每分种一次。(这是在调试时为了加快速度设置的参数)
3091299 [2014-05-17 23:46:10:901][线程4832][1][20][0][]CSEMQ::TraceAction ok,num of action_trace:1 .
3091310 [2014-05-17 23:46:10:913][线程4832][1][20][0][]CSEMQ::TraceAction acquire 1_1_1_47656...
3092410 [2014-05-17 23:52:10:901][线程7096][1][20][0][]CSEMQ::TraceAction ok,num of action_trace:1 .
3092420 [2014-05-17 23:52:10:902][线程7096][1][20][0][]CSEMQ::TraceAction acquire 2_1_1_49277...
3093482 [2014-05-17 23:58:10:901][线程4832][1][20][0][]CSEMQ::TraceAction ok,num of action_trace:1 .
3093493 [2014-05-17 23:58:10:909][线程4832][1][20][0][]CSEMQ::TraceAction acquire 1_1_1_47657...
可见acquire要执行6分钟。流量控制下没有可用的信号量,只有在超时后才释放。(为什么不是默认的5分钟呢?)
int CSEMQ::TraceAction(char action,MQ_LOC_KEY *lock_key) { char key[128]; sprintf(key,ACTION_KEY_FORMAT,action,lock_key->mq_id_,lock_key->mq_db_id_,lock_key->record_id_); DEBUG_LOG(GetLogger(),(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CSEMQ::TraceAction acquire %s...\n",key)); fc_sema_->acquire(); CActionTraceItem *ati = new CActionTraceItem; ati->ts_ = clock(); action_trace_.bind(key,ati); DEBUG_LOG(GetLogger(),(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CSEMQ::TraceAction ok,num of action_trace:%d .\n",action_trace_.current_size())); return 0;}
修改后的代码:(已修改trunk 2014-7-22)
int CSEMQ::TraceAction(char action,MQ_LOC_KEY *lock_key) { char key[128]; sprintf(key,ACTION_KEY_FORMAT,action,lock_key->mq_id_,lock_key->mq_db_id_,lock_key->record_id_); DEBUG_LOG(GetLogger(),(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CSEMQ::TraceAction acquire %s...\n",key)); fc_sema_->acquire(); CActionTraceItem *ati = new CActionTraceItem; ati->ts_ = clock(); if (action_trace_.bind(key,ati)==1) { ///< 已经存在跟踪项 fc_sema_->release(); } DEBUG_LOG(GetLogger(),(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CSEMQ::TraceAction ok,num of action_trace:%d .\n",action_trace_.current_size())); return 0;}
2.SEMQ 记录状态
故障现象:测试中发现f009n_0031=100的记录,会变成4.与消息的处理顺序有关。
由于测试时问询的频率比较短。发送后,目标接收方返回的810-Indication已经被处理,f009n_0031状态为100.但此时,已经发出了809-Request问询。
在目标方处理809-Request时还没有接收到单据,返回的消息指示“没有收到”。发送方接收到809-Confirmation后,把状态修改为0,重新发送。
***机制不严谨,有可能出现重复发送。(可以在Resend时排除已经是100状态的记录)
流量控制:
控制有多少个等待确认的消息。
int TraceAction(char action,MQ_LOC_KEY *lock_key); ///< 跟踪一个活动
action
含义
TraceAck时机
1
发送数据,跟踪tb_0031
接收到810-Indication
2
问询(809-Request),跟踪tb_0031
接收到809-Confirmation
3
反向确认(808-Indication),跟踪tb_0030
接收到800-Response
action=1:
如果网络原因或者接收方处理失败,没有接收到810-Indiction:超时会删除
如果接收到2个810-Indication(分别来自平台和目标接收方):只能释放一个信号量
action=2
如果问询速度非常快(如压力或破坏性测试时),远大于返回消息的速度。
则同一条记录可能会发送多次,但信号量只能有一个。
如果同一个消息执行多次问询,每次执行fc_sema_->acquire();
但第1个该消息的确认返回时,只执行1次fc_semq_->release();----这会导致可用信号量减少,直到没有信号量可用。只能等待超时,释放信号量后才可继续。
---这和每6分钟执行一次是吻合的。
actino=3,
int CBBoxPlugin::OnRespInquiry(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) { result = semq_.Resend(ref_object_id);
Resend函数增加参数force,表示是否强制发送。force=false,如果消息已经确认则不发送 。
semq.h
int Resend(CQQ_OBJECT_ID object_id,bool force); ///< 重发一条消息
semq.cpp
问询条件表达式(部分条件项)
inquiry_expr_ = "((f016c_0031=3 and f009n_0031=4) or (f017c_0031=1 and f009n_0031=6))"; ///< f017c_0031=1实际上包含了f016c_0031(必须为3) seqctrl_expr_ = "((f016c_0031=3 and f009n_0031 in (4,10,12)) or (f017c_0031=1 and f009n_0031<>100))"; ///< 时序控制时判定是否还有未处理的先前记录的过滤条件(如一张单据的2次改变产生的2条记录,第1条未确认则后面的不发送)--->
inquiry_expr_ = "((f016c_0031=3 and f009n_0031 in (4,5,6)))"; ///< 忽略,废弃f017c_0031 seqctrl_expr_ = "((f016c_0031=3 and f009n_0031 in (4,5,6,10,12)))"; ///< 时序控制时判定是否还有未处理的先前记录的过滤条件(如一张单据的2次改变产生的2条记录,第1条未确认则后面的不发送)
***f017c_0031此字段已不使用.(废弃此字段)
f016c_0031的含义如下:
enum { SF_NONE=1,SF_SAVE_FWD,SF_ACK, RL_DISCARDABLE=1,///< 目标不在线时丢弃 RL_NODISCARDABLE,///< 目标不在线时保存在待发送消息队列中 RL_STRICT,///< 要求确认(已送达)};
UMXT默认RL_NODISCARDABLE.
假设发送给机构A的用户100681004的某个消息,不同消息可靠属性的含义分别如下:
- 对于RL_DISCARDABLE,消息到达机构A时,如果用户在线则发送给用户,如果不在线则丢弃。***发送端并不需要知道用户是否在线,在发送端就决定是否删除.
- 对于RL_NODISCARDABLE,消息到达机构A时,如果用户在线则发送给拥护,否则,保存在机构A的数据库中,等待用户上线后发送。***不能保证消息被送达
- 对于RL_STRICT,必须确保目标接收到.
对于UMXT消息,传输采用TCP。没有属性指示采用TCP或UDP。
CSEMQ::Resend实现:
////////////////////////////////////////////////////////////////////////////////int CSEMQ::Resend(CQQ_OBJECT_ID object_id,bool force) {string sql;if (force)sql = LogMsg("update %s set f009n_0031=0 where object_id=%I64d",this->GetTableName(),object_id);else sql = LogMsg("update %s set f009n_0031=0 where object_id=%I64d and %s",this->GetTableName(),object_id,inquiry_expr_);USEDBC(pdbor,this->dbc_name_.c_str());int ret = pdbor->Execute(adCmdText,sql.c_str()) ? 0 : -1;if (ret==0) {SendRecord(object_id);}return ret;}
要求目标为平台的消息最后的状态应该为100.(已送达),而不能是6。
810-Indication增加flag参数:
int CBBoxPlugin::OnAck(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) ///< 发送给PT_APP的消息,只要已到达平台(写入网关应用队列),就算已经送达// if(src_t == PT_CENTRAL && qe.dest_type_ != PT_CENTRAL && qe.dest_type_!=PT_PAPP){ ///< 如果确认消息来自平台,但是队列记录的目标不是平台,表示可能并没有发送到目标方(非平台) if (handle_flag==1||handle_flag==2) { status = ISEMQ::SS_ACK; ///< @note 不区分平台是转发还是存储了----平台代码目前不支持 } else { status = ISEMQ::SS_ACK2; }
- gyb优化事项(2)
- gyb优化事项(1)
- gyb优化事项(3)
- gyb优化事项(4)
- SEO网站优化事项
- ORACLE SQL优化事项
- gyb todo
- 优化关键词获得好的排名四个事项(2)
- ORACLE性能优化主意事项
- sq语句优化l事项
- 安卓开发优化事项
- Unity游戏开发优化事项
- gyb-e改造说明
- 安卓开发中的优化事项
- MYSQL建表优化考虑事项
- 网站优化应注意的事项
- 事项
- 事项
- 如何在word里输入勾
- Hadoop 新 MapReduce 框架 Yarn 详解
- 蓝桥杯--李白打酒
- FastJson 解析JSON/映射实体
- 并发编程实践六:ReentrantReadWriteLock
- gyb优化事项(2)
- HTML和sql特殊符号编码对照表
- eclipse如何导入android工程
- IMP各参数使用详解 exp
- Linux基础
- Spring MVC 教程,快速入门,深入分析
- 你选择开发工程师做为自已的职业
- Configuration file tmeplate mysql\my-template.ini could not be processed and written to Error code-1
- iframe去边框,无边框,使用大全