热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>编程开发>

Heartbeat 通信层结构分析

来源: 作者: 时间:2007-06-29 Tag: 点击:
前言
  Heartbeat是Linux-HA开源项目发布的用于关键应用环境的HA软件名称。从1999以来到现在, 历经1.2.x, 2.0.x等多个版本,在全球开源HA领域具有举足轻重的知名度, 应用日益广泛, 并且得到了一些主流Linux操作系统厂商的支持。
而通信层实现无疑是集群软件运行的最基本底层支撑。本文对通过分析Heartbeat源码,对其通信层基本结构和机制进行了分析和阐述。给出了基本数据结构和实现流程。
  所有分析基于Heartbeat 2.0.4版本。
相关源码:
http://www.linux-ha.org/download/heartbeat-2.0.4.tar.gz


Heartbeat通信结构概述
  主要分2种:
  1.HBcomm 通信层PLUGIN (节点之间的进程通信)
实现主要是在各个媒介的Plugin里,通过PILS动态连接库加载。比如支持多播,单播,串口等通信方式。所有节点间通信PLUGIN模块放在lib/plugins/hbcomm/路径下。
  2.Unix Domain Socket (节点内的进程通信)
  /include/clplumbing/Ipc.h, IPC抽象层数据结构定义
  /lib/clplumbing/ocf_ipc.c, IPC底层抽象实现
  /lib/clplumbing/ipcsocket.c, IPC的unix域套接字具体实现

交叉点:
  节点间和节点内2种通信方式的交接点在heartbeat.c的read_child(), write_child()等函数中, 在这里实现消息的转发。
Heartbeat API
  是基于ipc抽象层的Unix域实现基础上,用于满足heartbeat和client子模块之间的应用层通信需求。:
  client_lib.c实现了Heartbeat API 客户端部分。
  hb_api.c实现了heartbeat API服务器端部分。




  图1:Heartbeat通信结构概图
上图描述了一个client子模块把消息通过Heartbeat通信机制发送到另一个节点相同模块的过程。
  1. client子模块通过FIFO管道把消息发送到FIFO子进程fifo_child。为什么使用FIFO来进行通信呢,应该是有些进程不能很方便的和 Heartbeat主进程建立Unix域IPC通道的关系,比如执行的脚本和集群管理程序, 集群状态查询程序。
  2. FIFO子进程通过msgfromstream()从fifo管道收到消息后,利用事先建立好的和Heartbeat之间的IPC通道转发给Heartbeat主进程
  3. 主进程判断消息是发给自己的则调用process_msg()进行处理,否则调用send_to_all_media()通过各个媒介的wchan通道发送给write_child子进程。
  4. write_child子进程通过ipcmsgfromIPC()从主进程收到消息,调用各个媒介结构hb_media的write函数把消息发送到集群其他节点。
  5. 其他节点的read_child子进程通过各个媒介结构hb_media的read函数读到消息后,使用事先和Heartbeat主进程建立的IPC通道发送消息到Heartbeat主进程
  6. Heartbeat主进程通过msgfromIPC()收到消息后,调用process_clustermsg()函数进行处理。具体为,如果是主进程处理的消息调用HBDoMsgCallback进行处理,否则通过newstartha_monitor发送到各个client子进程


节点间通信Plugin
  代码在lib/plugins/hbcomm/目录中
  bcast.c /* 广播 */
  mcast.c /* 多播 */
  ucast.c /* 单播 */
  openais.c /* openais */
  serial.c /* 串口 */
  ping.c /* icmp */
  ping_group.c /* ping一组主机 */
  hbaping.c /* 光纤总线适配器ping */

/* 这个结构的每个函数对应Plugin里的具体函数。*/
struct hb_media_fns {
struct hb_media*(*new) (const char * token); /* 建立媒介 */
int (*parse) (const char * options); /* 读取配置文件参数 */
int (*open) (struct hb_media *mp); /* 打开 */
int (*close) (struct hb_media *mp); /* 关闭 */
void* (*read) (struct hb_media *mp, int *len ); /* 读 */
int (*write) (struct hb_media *mp , void *msg, int len); /* 写 */
int (*mtype) (char **buffer); /* 获取媒介类型 */
int (*descr) (char **buffer); /* 获取媒介描述 */
int (*isping) (void); /* 是否ping类型媒介 */
};

hb_media_fns各功能函数调用之处:
new(): config.c的add_option函数
parse(): config.c的parse_config函数
open(): heartbeat.c的initialize_heartbeat函数
close(): heartbeat.c的initialize_heartbeat函数
read(): heartbeat.c的read_child函数
write(): heartbeat.c的write_child函数
mtype(): config.c的parse_config函数
descr(): config.c的parse_config函数
isping(): 在config.c和hb_api.c被调用



节点内IPC通信
IPC通信抽象层(include\clplumbing\ipc.h)
IPC抽象层数据结构概述:
(注:缩进的为该数据结构所属元素)
IPC_AUTH /* 安全认证数据结构 */
IPC_WAIT_CONNECTION /* 等待连接数据结构 */
IPC_WAIT_OPS /* 等待连接函数集 */
IPC_CHANNEL /* 通信管道数据结构 */
IPC_OPS /* 通信管道函数集 */
IPC_QUEUE /* 信息队列 */
ipc_bufpool /* 接收缓冲池,经处理转化为接收队列 */
IPC_MESSAGE /* IPC通信信息数据结构 */
IPC_CHANNEL /* 信息所属通信管道 */
SOCKET_MSG_HEAD /* 信息头数据结构 */


其中2种主要抽象数据结构:
/* server端等待客户端的连接 */
struct IPC_WAIT_CONNECTION{
int ch_status; /* wait conn. status.*/
void * ch_private; /* wait conn. private data. */
IPC_WaitOps *ops; /* wait conn. function table .*/
};


相关文章:
ioctl函数
struts与spring三种整合方法
进程的创建fork
jsp速成
Hibernate单向一对多应注意的问题
Java RMI之HelloWorld篇
常用的Eclipse快捷键
sparc linux 系统调用
一个关于jboss "Halting VM"的情况处理
编写更好的Linux程序3(这次只讲void *)
Tikiwiki 2.2+ Ucenter 1.5(Discuz)整合
玩转ptrace(一)
玩转ptrace(二)
dup2
pipe
Jboss的学习
gcc用法
将UI从代码中解放出来
数据结构与算法(2)
有关于JAVA中的CLASSPATH的作用
const成员函数
虚函数
《c和指针》读书笔记2
初次接触Zend Framework需要掌握的内容
php中require和include的简单区别
正则表达式在PHP中的应用
在PHP中使用与Perl兼容的正则表达式
Zend Studio 生成 wsdl
freebsd7 + php5.2.6 + xdebug2.0.2安装
PHP抓取远程网站数据的代码