许多性能研究的一个重要方面是运行期间失败的网络组件的影响。因此,模拟提供了启用和禁用通信节点和链接的功能。本节介绍可用于建模故障和恢复的机制,并介绍这些功能的一些示例应用程序。
每个节点和链接对象具有“条件”属性,该属性指定它是否处于操作状态。当节点或链路从操作状态变为不操作状态时,模拟内核可能会生成故障中断。类似地,当节点或链路从非操作状态变为操作状态时,模拟内核可以生成恢复中断。这些中断将被传递给请求它们的处理器和队列模块。这些中断是强制传递的,这意味着正在更改节点“条件”属性的当前事件被暂停,并且在该事件期间传递每个中断。
当节点发生故障时,不会传递发往该节点内模块的中断。 但是,就在节点发生故障之前,故障中断(如果有的话)是最后一个中断传递给该节点内的模块,直到节点恢复。 在节点恢复之后,传递给该节点内的模块的第一个中断是恢复中断(如果有的话)。 通常情况下不会发生这种情况,但故障中断可能是最后一次中断,而第一个要传递给节点内模块的恢复中断是由同一故障或恢复中的其他中断生成的其他强制事件。
由于节点或链路无法自动失败或恢复,因此必须在模拟期间进行外部操作以更改节点或链路的状态。 通常,使用四种用于生成故障和恢复的方法之一:确定,脚本,随机或交互。 确定方法导致一个节点或链路在模拟期间的特定时间失败并恢复。 脚本方法比确定性方法更通用,并且基于包含显式时间和故障和恢复位置的文件。 随机方法根据指定的时间和位置分布生成故障和恢复。 通过交互式操作,可以通过调试器直接设置故障或恢复。
当对象的“condition”属性更改值时,对象发生故障或恢复。 因此,四种方法中的每一种都提供了一种改变属性值的机制。 但是,它们在选择对象和故障或恢复时间的方式上是不同的。
除了交互操作之外,每个方法都要求进程更改节点或链接的“条件”属性。 通常,一个集中过程或许多分散过程负责生成故障和恢复。 集中式进程通常驻留在仅为此任务预留的节点中,并且本身永远不会失败。 另一方面,每个分散的进程通常驻留在不同的节点内,并负责其父节点的故障和恢复。
如果禁用节点,则不会向节点内的模块传递任何中断。 由于这个事实,节点内的进程不能直接导致节点恢复。 要调用,进程本身需要中断才能更改节点的状态,但由于节点已禁用,因此无法接收任何中断。 因此,如果进程负责使其父节点恢复,则该进程可以调度过程调用中断,该中断将调用导致节点恢复的过程。 虽然过程调用中断在调度它的进程的上下文中调用过程,但是中断不会传递到节点内的对象,因此,模拟内核不会阻止调用过程。
确定方法
本节中介绍的确定过程示例基于特定节点或链路发生故障并在已知模拟时间恢复的概念。该过程有两个属性来指定故障和恢复时间:“失败时间”和“恢复时间”。可选地,该过程可以具有另一个属性,该属性将指定要修改的对象,例如,使用节点或链接的名称。但是,此示例过程只是通过将父节点的“条件”属性设置为“已禁用”然后再“启用”来使其父节点失败然后恢复。由于此过程仅对其父节点负责,因此可以将其视为离散故障/恢复过程的示例。当系统需要简单的故障/恢复建模时,建议使用确定性过程方法。通常只安排一个故障/恢复周期,而不是一系列故障/恢复周期。以下列表包含确定性故障/恢复过程的示例代码片段。
/* Obtain the module's and parent node's object IDs. */
module_id = op_id_self ();
node_id = op_topo_parent (module_id);
/* Obtain the failure and recovery simulation times. */
op_ima_obj_attr_get (module_id, "fail time", &fail_time);
op_ima_obj_attr_get (module_id, "recover time", &recover_time);
/* Schedule the node's failure and recovery via "call" interrupts. */
op_intrpt_schedule_call (fail_time, FAIL_CODE, fail_recov_proc, OPC_NIL);
op_intrpt_schedule_call (recover_time, RECOV_CODE, fail_recov_proc, OPC_NIL);
fail_recov_proc (state_ptr, code)
char* state_ptr;
int code;
{
Objid nd_objid;
/** This procedure causes the parent node of the module that this **/
/** interrupt was scheduled in to either fail or recover, **/
/** depending on the code. **/
FIN (fail_recov_proc (state_ptr, code))
/* Obtain the parent node's object ID. */
nd_objid = op_topo_parent (op_intrpt_source ());
/* Depending on the code, either enable or disable the node. */
if (code == RECOV_CODE)
op_ima_obj_attr_set (nd_objid, "condition", OPC_BOOLINT_ENABLED);
else
op_ima_obj_attr_set (nd_objid, "condition", OPC_BOOLINT_DISABLED);
FOUT
脚本方法
脚本文件是一个文本文件,用于指定故障和恢复时间以及受影响的对象。 基于脚本文件,关联的进程在系统范围内生成节点和链路故障以及恢复。 由于这是导致整个系统出现故障和恢复的唯一过程,因此可以将其视为集中式故障/恢复过程的示例。 当在特定时间的模拟期间发生大量或复杂的一系列故障和恢复时,脚本文件处理方法非常有用。
在此示例中,脚本文件包含每个故障或恢复事件的行。 每行有三个值:事件发生的时间,对象的用户ID以及事件类型(失败或恢复)。 使用对象的用户ID而不是对象ID,因为节点和链接的“用户id”属性值是网络模型的一部分,因此在模拟之前是已知的。 对象ID由Simulation Kernel在运行时分配,只能在模拟期间发现。
可以从若干源之一生成脚本文件。 如果网络模型对应于现有网络,则脚本文件可以基于节点和链路故障和恢复的实际列表。 另一种选择是创建一个代表某些特定系统行为的脚本文件,例如一系列节点失败。 脚本文件也可用于测试“最坏情况”场景,例如,其中一组相互依赖的节点和链接同时失败。
关联进程读取脚本文件并构建节点和链接故障列表以及恢复时间。 构建列表后,进程会在第一次失败或恢复事件时安排自我中断。 发生自我中断时,进程通过调用内核过程op_ima_obj_attr_set()将指定对象的“condition”属性设置为正确的值,并为下一个失败或恢复事件安排另一个自我中断。 下图包含基于脚本的故障/恢复过程的示例代码片段。
# Example script file for node/link failures/recoveries
# Times are expected in order
#
# time user_id event
10.00 12 failure
12.30 12 recovery
14.40 3 failure
14.40 4 failure
14.45 5 failure
14.55 4 recovery
100.00 3 recovery
/* This process just received a self intrpt that signals a failure */
/* or recovery action. Obtain the top instruction from the list. */
inst_ptr = (Script_Inst*) op_prg_list_remove (event_list_ptr, OPC_LISTPOS_HEAD);
/* Convert user ID to object ID. */
object_id = user_id_to_object_id_convert (inst_ptr->user_id);
/* Set the object's "condition" attribute to the specified value. */
if (inst_ptr->type == FAIL_CODE)
op_ima_obj_attr_set (object_id, "condition", OPC_BOOLINT_DISABLED);
else op_ima_obj_attr_set (object_id, "condition", OPC_BOOLINT_ENABLED);
/* Deallocate instruction. */
op_prg_mem_free (inst_ptr);
/* Transition to next state, where next interrupt is scheduled. */
/* Obtain the next instruction from the list. */
inst_ptr = (Script_Inst*) op_prg_list_access (event_list_ptr, OPC_LISTPOS_HEAD);
/* Schedule a self interrupt for the time. */
op_intrpt_schedule_self (inst_ptr->time, 0);
/* Obtain name of script file from the process' attribute. */
op_ima_obj_attr_get (op_id_self (), "script name", script_name);
/* Create and init list to hold failure/recovery instructions. */
event_list_ptr = op_prg_list_create ();
/* Load the file contents into a list. */
line_list_ptr = op_prg_gdf_read (script_name);
/* Loop through the lines of the list and parse each line. */
list_size = op_prg_list_size (line_list_ptr);
for (i = 0; i < list_size; i++)
{
/* Obtain the i_th line in the file. */
string = op_prg_list_access (line_list_ptr, i);
/* Decompose the line in to fields. */
field_list_ptr = op_prg_str_decompose (string, " ,/\t");
/* If the line does not have three fields or starts with '#' */
/* then skip it and try the next. */
if (op_prg_list_size (field_list_ptr) != 3)
goto dealloc;
field0 = op_prg_list_access (field_list_ptr, 0);
if (field0 [0] == '#')
goto dealloc;
/* Allocate a structure to hold the event instruction. */
inst_ptr = (Script_Inst*) op_prg_mem_alloc (sizeof (Script_Inst));
/* Fill in the instruction. */
inst_ptr->time = atof (field0);
inst_ptr->user_id = atoi (op_prg_list_access (field_list_ptr, 1);
field2 = op_prg_list_access (field_list_ptr, 2);
if (strcmp ("failure", field2) == 0)
inst_ptr->type = FAIL_CODE;
else inst_ptr->type = RECOVER_CODE;
/* Place the instruction on the end of the list. */
op_prg_list_insert (event_list_ptr, inst_ptr, OPC_LISTPOS_TAIL);
/* Deallocate the elements in the list and then the list itself. */
dealloc:
op_prg_list_free (field_list_ptr);
op_prg_mem_free (field_list_ptr);
}
/* Deallocate the elements in the list and then the list itself. */
op_prg_list_free (line_list_ptr);
op_prg_mem_free (line_list_ptr);
随机方法
随机故障/恢复过程基于分布生成节点和链路的故障和恢复,以便节点和链路的状态随机变化。 示例过程有四个属性,用于确定故障和恢复事件的频率。 “节点故障均值”和“链路故障均值”属性分别指定节点和链路的平均故障时间。 类似地,“节点恢复平均值”和“链接恢复平均值”属性指定平均恢复时间。 该过程为失效选择特定节点或链接,然后为该节点或链接安排恢复。 通常,指数分布用于模拟故障和恢复时间。 但是,对于特定系统,其他分布可能更准确。
当随机生成的故障和恢复是系统的适当模型时,建议使用随机过程。 当发生大量故障和恢复时,随机过程通常比脚本文件过程更实用。 随机过程具有额外的好处,即动态生成故障和恢复,针对不同大小的网络和模拟持续时间进行调整。 此外,它可以自动使网络进入典型的场景,而无需新的用户输入。
示例过程并行地为节点和链接生成故障。最初,该过程获取平均故障和恢复属性值。基于平均时间计算两个故障时间,并且该过程针对节点故障调用一个自中断,而另一个针对链路故障调用自中断。当故障发生自我中断时,该过程随机选择一个节点或链路,并通过KP op_ima_obj_attr_set()将其“条件”属性设置为“禁用”,从而使其失败。然后,该进程根据指定的平均恢复时间计算节点或链路的恢复时间,并为恢复调度自身中断,并将节点或链路的对象ID作为中断代码。包含对象ID,以便进程可以标识要启用的对象。发生此中断时,对象的“condition”属性将重新设置为“enabled”。除了为恢复安排中断外,该过程还会安排下一次故障自我中断。
/* This process just received an interrupt. Determine what is to */
/* happen. Node and link failures use the codes; recovery intrpts */
/* contain the object ID of the object to recover. */
code = op_intrpt_code ();
if (code == NODE_FAIL_CODE))
{
/* Obtain random node object ID and determine if already disabled. */
object_index = (int) op_dist_uniform (num_nodes);
object_id = op_topo_object (OPC_OBJMTYPE_NODE, object_index);
op_ima_obj_attr_get (object_id, "condition", ¤t_condition)
if (current_condition != OPC_BOOLINT_DISABLED)
{
/* Cause the node to fail. */
op_ima_obj_attr_set (object_id, "condition", OPC_BOOLINT_DISABLED);
/* Schedule recovery interrupt; first generate recovery time. */
intrpt_time = op_sim_time () + op_dist_outcome (node_recov_dist_ptr);
op_intrpt_schedule_self (intrpt_time, object_id);
}
/* Schedule the next fail interrupt; first generate failure time. */
intrpt_time = op_sim_time () + op_dist_outcome (node_fail_dist_ptr);
op_intrpt_schedule_self (intrpt_time, NODE_FAIL_CODE);
}
else if (code == LINK_FAIL_CODE)
{
/* Obtain random link object ID and determine if already disabled. */
object_index = (int) op_dist_uniform (num_links);
object_id = op_topo_object (OPC_OBJMTYPE_LINK, object_index);
op_ima_obj_attr_get (object_id, "condition", ¤t_condition)
if (current_condition != OPC_BOOLINT_DISABLED)
{
/* Cause the link to fail. */
op_ima_obj_attr_set (object_id, "condition", OPC_BOOLINT_DISABLED);
/* Schedule recovery interrupt; first generate recovery time. */
intrpt = op_sim_time () + op_dist_outcome (link_recov_dist_ptr);
op_intrpt_schedule_self (intrpt_time, object_id);
}
/* Schedule the next fail interrupt; first generate failure time. */
intrpt_time = op_sim_time () + op_dist_outcome (link_fail_dist_ptr);
op_intrpt_schedule_self (intrpt_time, LINK_FAIL_CODE);
}
else
{
/* This is a recovery; the code is the object ID of the object */
/* that is recovering. Set the "condition" attribute. */
op_ima_obj_attr_set (code, "condition", OPC_BOOLINT_ENABLED);
交互方法
在Modeler调试器下运行模拟时,可以使用调试器命令attrset直接设置对象的属性。 通过这种机制,节点或链接“条件”属性可以设置为“启用”或“禁用”。 如果值更改,将生成恢复或失败中断,就像某个进程通过调用内核过程op_ima_obj_attr_set()更改了属性的值一样。 交互式操作对于测试系统对“即时”故障和恢复的反应非常有用。