当前位置: 首页 > Linux

sonicorch调度系统orchagent的orchagent

时间:2023-04-06 18:51:16 Linux

sonic核心守护线程以orch为单位管理资源,一个orch包含一组相似的资源;orchagent调度系统以Executor为调度单元,调度实体有Consumer、ExecutableTimer等,本文详细分析sonic调度。OrchDaemonorchagent类将OrchDaemon描述为核心类。类OrchDaemon{public:OrchDaemon(DBConnector*,DBConnector*,DBConnector*);?OrchDaemon();boolinit();//初始化进程voidstart();//启动调度系统private://三个数据库相连DBConnector*m_applDb;DBConnector*m_configDb;数据库连接器*m_stateDb;//包含所有orchstd::vectorm_orchList;//创建select多路异步IO控制块Select*m_select;//管道asic_db刷新,不等待。voidflush();};boolOrchDaemon::init()初始化orchagent执行环境。boolOrchDaemon::init(){SWSS_LOG_ENTER();......//连接数据库TableConnectorconfDbAclTable(m_configDb,CFG_ACL_TABLE_NAME);TableConnectorconfDbAclRuleTable(m_configDb,CFG_ACL_RULE_TABLE_NAME);TableConnectorstateDbLagTableset_switch_attribute(gSwitchId,&attr);if(status!=SAI_STATUS_SUCCESS){SWSS_LOG_ERROR("无法刷新redis管道%d",status);退出(退出失败);}}voidOrchDaemon::start()voidOrchDaemon::start(){SWSS_LOG_ENTER();//遍历每个orch,将每个orch中所有关注的事件添加到epoll中,基本上一个Executor就是一个事件for(Orch*o:m_orchList){m_select->addSelectables(o->getSelectables());}//进入死循环while(true){Selectable*s;诠释;//执行epoll阻塞监听ret=m_select->select(&s,SELECT_TIMEOUT);//错误事件,继续监听if(ret==Select::ERROR){SWSS_LOG_NOTICE("Error:%s!\n",strerror(errno));继续;}//超时事件if(ret==Select::TIMEOUT){/*让sairedis将所有SAI函数调用刷新到ASICDB。*通常redis管道会在足够的请求时刷新*累积。仍然有可能存在少量*请求。当守护进程无事时,*是刷新管道的好机会*确保redis-pipeline中的少量请求在10秒后可以得到处理,而不是累积请求*/flush();继续;}//获取触发epoll事件的Executorauto*c=(Executor*)s;//对于Consumer,进行数据库操作,将redis中的notifications转换为m_tosync,在m_tosync中执行如下任务c->execute();/*每次迭代后,定期检查所有m_toSync映射以*执行所有需要重试的剩余任务。*//*TODO:具有特定待办事项列表的抽象Orch类*///执行留在orch中的其他任务for(Orch*o:m_orchList)o->doTask();}}实例分析下面我们分析一下orchagent处理的最多的事件:ConsumerStateTable看一下orchagent调度系统的ConsumerStateTable,就是orchagent订阅的app_db事件。格式如下:"SADD""INTF_TABLE_KEY_SET""PortChannel1:1.1.1.1/8"#在集合中添加一个key"HSET"INTF_TABLE_KEY_SET"INTF_TABLE:PortChannel1:1.1.1.1/8""scope""global""HSET""INTF_TABLE:PortChannel1:1.1.1.1/8""family""IPv4""PUBLISH""INTF_TABLE_CHANNEL""G"当producer发送命令"PUBLISH""INTF_TABLE_CHANNEL""G"时,orchagent从epoll中唤醒,然后从相应的redis客户端句柄调用RedisSelect::readData()来读取数据。这条命令的响应如下:1)“message”2)“INTF_TABLE_CHANNEL”3)每次收到响应都会发送“G”RedisSelect::m_queueLength加1,响应只有一条消息“G”,仅用作通知。所以如果producer同时写入大量的app_db事件,某个epoll被唤醒,RedisSelect::readData()可以读到大量的response,导致m_queueLength大于1。读完数据后,将事件Selectable添加到Select:m_ready。同时通过调用RedisSelect::updateAfterRead(),将RedisSelect::m_queueLength减1,这里只减1,根据实际处理情况不减相应的值。存在多个值相加,一个值相减的情况。.只要m_queueLength不为1,Selectable就不会从Select:m_ready中移除。Select::select函数返回Select:m_ready中的所有Selectable。遍历每一个selectable,在函数Consumer::execute()中调用TableEntryPoppable::pops,使用脚本consumer_state_table_pops.lua处理INTF_TABLE_KEY_SET中的key,每次最多处理128个key。localret={}localkeys=redis.call('SPOP',KEYS[1],ARGV[1])--一次处理128个keylocaln=table.getn(keys)fori=1,ndolocalkey=keys[i]localvalues=redis.call('HGETALL',KEYS[2]..key)table.insert(ret,{key,values})endreturnret脚本返回的内容会是:INTF_TABLE:PortChannel1:1.1.1.1/8:{"scope":"global","family":"IPv4"}pops然后将上面的内容处理成如下格式:std::tuple>返回:"SET","INTF_TABLE:PortChannel1:1.1.1.1/8",<"scope":"global","family":"IPv4">Consumer::execute()会将先前返回的值添加到Consumer::m_toSync中,并在此处合并。最后,OrchDaemon::start()函数将执行每个orch的Consumer::m_toSync中的任务。sonic调度系统的缺陷sonic调度系统过于简单,无法处理大规模和逻辑复杂的业务,效率很低。当超出规范下发配置时,由于资源不足,会导致大量任务驻留在m_toSync中。OrchDaemon::start()每次触发事件,都会遍历orch的m_toSync中的所有任务,导致频繁执行无效任务,导致orchagent抖动。Consumer必须加一些标签,表示当前Consumer处于资源不足的状态,暂时不会执行m_toSync中的任务。当大规模下发配置时,如果本次配置的依赖还没有下发,m_toSync就会因为依赖未满足而失败。驻留大量任务。导致或试剂振动问题。大规模删除配置时,如果没有删除配置引用,会导致大量任务驻留在m_toSync中,因为被引用了,无法删除。导致或试剂振动问题。Orchagent在处理任务时不考虑事件处理的先后顺序。它应该先执行DEL操作,再执行SET操作。对于DEL操作,先删除低优先级的消费者,对于SET操作,先处理高优先级的消费者。两者的顺序是相反的。