• 03-QNX高可用框架HAM研究(转)


    1. 背景

    高可用需求,在系统故障时减小故障的影响,尽量保证系统正常运行。在汽车电子尤为重要,核心服务/进程需要实时监听,具备死亡复活机制。

    2. 技术框架-HAM

    HAM(High Availability Manager)是一个“智能看门狗”——一个高弹性的管理进程,它可以在系统服务或进程失败或不再响应时监视您的系统并执行多级恢复。作为一个自我监控的管理者,HAM对内部故障具有弹性。不管出于什么原因,如果HAM本身被异常地停止,它可以通过移交给一个称为“监护人”的镜像进程,立即并完全地重建自己的状态。

    2.1 HAM基本元素

    术语描述
    entry实体,指的是HAM监测的具体实体,可理解为进程
    condition条件,条件与实体相关联,类似进程死亡这种时候
    action动作,动作与条件相关联,一个条件可以关联多个动作,类似重新启动等具体行为

    2.2 功能介绍

    进程自我监控
    进程可以自已选择监测的开始和结束时间,选择相关的触发条件和执行动作,类似“当我挂掉时,做什么事情”。
    例:由于APP不是常驻内存,在执行一些可能CRASH的代码时,可请求HAM,当我出现异常,重启我。

    监控外部应用
    进程可以监控外部进程的状态,类似“当B挂掉了,做什么事情”。
    例:Audio守护进程监控到Audio进程挂掉后,重启Audio。

    监控全局
    系统中一种虚拟进程,可以监控所有被监控的进程,类似“当任意进程挂掉,做什么事情”。
    例:注册行为,在任意进程挂掉后,写日志。

    QNX Neutrino架构的三个关键因素直接促成了内在 HA:

    • 微内核,单个内核逻辑更少,部分重启不太影响全局
    • POSIX 进程模型,单独的内存地址,可创建动态进程
    • 消息传递,标准消息传递,有利于任务解耦、任务简化和服务分发。

    原理: HAM启动时会有一个Guardian进程,并且将状态数据保存在共享内存,若HAM进程挂掉,则Guardian进程会取代HAM进程。

    是谁启动的进程
    QNX启动HAM进程,HAM管理需要监控的进程。
    可以直接执行ham以启动ham进程。
    不需要使用ham时可通过hamctrl -stop 停止ham,也可以调用ham_stop()

    2.3 条件condition

    ConditionDescription
    CONDDEATH进程中止。
    CONDABNORMALDEATH进程异常中止。
    CONDDETACH断开HAM
    CONDATTACH连接上HAM
    CONDHBEATMISSEDHIGH进程失去心跳达最大次数。
    CONDHBEATMISSEDLOW进程失去心跳达最小次数。
    CONDRESTART进程重新启动。
    CONDRAISE
    CONDSTATE进程状态发生变化。
    CONDANY任何condition改变。

     2.4 动作Action

    ActionDescription
    ham_action_restart()重启。
    ham_action_execute()执行一段脚本。
    ham_action_notify_pulse()发送PULSE事件。
    ham_action_notify_signal()发送系统信号事件。
    ham_action_notify_pulse_node()
    ham_action_notify_signal_node()
    ham_action_waitfor()等待。
    ham_action_heartbeat_healthy()
    ham_action_log()输出日志。

     2.5 使用

    1. #include <stdio.h>
    2. #include <string.h>
    3. #include <stdlib.h>
    4. #include <thread>
    5. #include <chrono>
    6. #include <iostream>
    7. #include <process.h>
    8. #ifdef QNX
    9. #include <ha/ham.h>
    10. #endid
    11. int main(int argc, char** argv)
    12. {
    13. #ifdef QNX
    14. printf("HAM Prepar~\n");
    15. int status;
    16. char* inetdpath;
    17. ham_entity_t* ehdl;
    18. ham_condition_t* chdl;
    19. ham_action_t* ahdl;
    20. int inetdpid;
    21. // 新启一个进程
    22. inetdpath = strdup("/usr/bin/picherdemo/helloworld -D");
    23. // 连接HAM
    24. ham_connect(0);
    25. // 将进程交给HAM监控
    26. ehdl = ham_attach("inetd", ND_LOCAL_NODE, inetdpid, inetdpath, 0);
    27. if (ehdl != NULL)
    28. {
    29. //添加条件,当进程“death”时
    30. chdl = ham_condition(ehdl, CONDDEATH, "death", HREARMAFTERRESTART);
    31. if (chdl != NULL) {
    32. //添加动作,重启进程
    33. ahdl = ham_action_restart(chdl, "restart", inetdpath,
    34. HREARMAFTERRESTART);
    35. if (ahdl == NULL)
    36. printf("add action failed\n");
    37. }
    38. else
    39. printf("add condition failed\n");
    40. }
    41. else
    42. printf("add entity failed\n");
    43. //关闭与HAM的连接
    44. ham_disconnect(0);
    45. #endif // QNX
    46. while (true) {
    47. printf("Process id: %d\n ", getpid());
    48. std::cout << "Thread id:\n"<< std::this_thread::get_id();
    49. std::this_thread::sleep_for(std::chrono::seconds(5));
    50. }
    51. return 0;
    52. }

    2.6 案例:

    1. #ifndef HAS_NO_HAM
    2. static void bridgechip_ham_thread(void)
    3. {
    4. ham_entity_t *ehdl = NULL;
    5. ham_condition_t *chdl = NULL;
    6. ham_action_t *ahdl = NULL;
    7. const char *line = BRIDGECHIP_RESMGR_PROCESS_PATH;
    8. bool32 bHAMReady = FALSE;
    9. uint32 uMaxRetries = BRIDGECHIP_RESMGR_HAM_THREAD_MAX_RETRIES;
    10. LOG_TRACE("RM", "ENTER");
    11. /* Check for availability of HAM. If not available within specified number
    12. * of checks, exit the thread.
    13. *
    14. * Note: This approach is preferred over Resource_BlockWait() as it allows us
    15. * to release the thread resource once re-attempts are exhausted.
    16. */
    17. while ((FALSE == bHAMReady) && (0 < uMaxRetries))
    18. {
    19. BridgeChip_OSAL_IsPathExist(BRIDGECHIP_RESMGR_HAM_PATHNAME, &bHAMReady, NULL);
    20. if (FALSE == bHAMReady)
    21. {
    22. BridgeChip_OSAL_SleepMs(BRIDGECHIP_RESMGR_HAM_THREAD_SLEEP_IN_MS);
    23. uMaxRetries--;
    24. }
    25. else
    26. {
    27. LOG_INFO("RM", "HAM is ready");
    28. }
    29. }
    30. if (TRUE == bHAMReady)
    31. {
    32. ham_connect(0);
    33. ehdl = ham_attach(BRIDGECHIP_RESMGR_PROCESS_NAME, 0, getpid(), line, 0);
    34. if (ehdl != NULL)
    35. {
    36. chdl = ham_condition(ehdl,CONDDEATH, "server_death", HREARMAFTERRESTART);
    37. if (chdl != NULL)
    38. {
    39. ahdl = ham_action_restart(chdl, "server_restart", line, HREARMAFTERRESTART);
    40. if (ahdl == NULL)
    41. {
    42. LOG_ERROR("RM", "add action failed strerror(errno=%d)=%s", errno, strerror(errno));
    43. }
    44. }
    45. else
    46. {
    47. LOG_ERROR("RM", "add condition failed strerror(errno=%d)=%s", errno, strerror(errno));
    48. }
    49. }
    50. else
    51. {
    52. /* If this isn't the first instance of bridgechip_server, HAM will already have an entity to track
    53. * the liveness of bridgechip_server. Ignore "entity already exists" error.
    54. */
    55. if (EEXIST != errno)
    56. {
    57. LOG_WARNING("RM", "add entity failed strerror(errno=%d)=%s", errno, strerror(errno));
    58. }
    59. }
    60. }
    61. else
    62. {
    63. LOG_WARNING("RM", "can't find %s", BRIDGECHIP_RESMGR_HAM_PATHNAME);
    64. }
    65. LOG_TRACE("RM", "EXIT");
    66. }
    67. #endif

    3. 小结

    HAM机制是QNX原生机制,通过监控进程状态做到进程的重启。

     

  • 相关阅读:
    IDEA生成Java Doc帮助文档
    BUU [HCTF 2018]Hideandseek
    SQL必需掌握的100个重要知识点:IN 操作符
    从new File("")到jdk源码
    患有癌症的心力衰竭患者LVAD植入前景可期
    Fairlearn 中的 API(二)
    BI业务用户商业分析新时代,如何把数据用透?
    21天学习挑战赛-树形选择排序和堆排序
    uniapp基础篇 - - 页面跳转和传值
    第11章 字符串和字符串函数
  • 原文地址:https://blog.csdn.net/liaochaoyun/article/details/127126798