如何让你的程序支持HA?

关于HA以及OceanBase中HA的应用请参考前面的两篇博客: HA在OceanBase中的应用, OceanBase中主备Rootserver如何管理切换

实现程序支持HA,要点是能够检测到VIP是否飘到了自己的机器上。如何检测呢?主Server和备Server都需要开一个线程,在这个线程里只做一件事:检查本机IP是否与VIP一致,如果一致则说明VIP飘到了自己的机器上。

这里仔细一想是有问题的:本机IP改了,外面的Server如何得知变成了多少?如何和它保持通信?最简单的情况,一个SSH连接上去,结果它的IP变了,连接岂不是会断开?

怎么办呢?让我们先来补充一点基础知识。

(1) 一台计算机可以有多个网卡,每个网卡可以有一个自己的独立IP,对外呈现为多个IP

(2)可以把多个网卡绑定成一个虚拟网卡(bond),对外只呈现为一个IP

(3)每个网卡(物理网卡或虚拟网卡)都可以有一个或多个虚拟IP(VIP)

(4)每个虚拟IP对应一个虚拟设备,设备命名规则是网卡名+":"+数字编号。例如eth0的VIP设备名称为eth0:0,eth0:1,...bond0的VIP设备名称为bond0:0, bond0:1

为一个设备添加/删除一个虚拟IP的方法如下(以bond0为例):


添加:sudo ifconfig bond0:0 10.32.36.219 netmask 255.255.255.0 up  
删除:sudo ifconfig bond0:0 down 

有了基础知识,再回到原始问题上:

(1)如何实现“VIP漂移”这个动作呢?

其实十分简单,要让VIP漂移到哪台机器上,就在哪台机器上执行下面的语句。VIP为10.32.36.219。


[plain] view plaincopyprint?sudo ifconfig bond0:0 10.32.36.219 netmask 255.255.255.0 up  

sudo ifconfig bond0:0 10.32.36.219 netmask 255.255.255.0 up
“同时”在原来持有VIP的机器上执行


[plain] view plaincopyprint?sudo ifconfig bond0:0 down  

sudo ifconfig bond0:0 down
HA软件很复杂,但其核心就是围绕着上面两个动作展开的,包括执行时机、执行顺序等。

(2)程序如何检测自己持有VIP呢?

同样很简单,在线程里不断执行下面这个函数即可。isLocalAddr函数逐个检查本机所持有的全部IP地址,与vip逐个匹配。


[cpp] view plaincopyprint?bool CNetUtil::isLocalAddr(uint32_t ip, bool loopSkip)  
{  
    int             fd, intrface;  
    struct ifreq    buf[16];  
    struct ifconf   ifc;  
  
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) {  
        return false;  
    }  
  
    ifc.ifc_len = sizeof(buf);  
    ifc.ifc_buf = (caddr_t) buf;  
    if (ioctl(fd, SIOCGIFCONF, (char *) &ifc)) {  
        close(fd);  
        return false;  
    }  
  
    intrface = ifc.ifc_len / sizeof(struct ifreq);  
    while (intrface-- > 0)  
    {  
        if(ioctl(fd,SIOCGIFFLAGS,(char *) &buf[intrface])) {  
            continue;  
        }  
        if(loopSkip && buf[intrface].ifr_flags&IFF_LOOPBACK) continue;  
        if (!(buf[intrface].ifr_flags&IFF_UP)) continue;  
        if (ioctl(fd, SIOCGIFADDR, (char *) &buf[intrface])) {  
            continue;  
        }  
        if (((struct sockaddr_in *) (&buf[intrface].ifr_addr))->sin_addr.s_addr == ip) {  
            close(fd);  
            return true;  
        }  
    }  
    close(fd);  
    return false;  
}  

bool CNetUtil::isLocalAddr(uint32_t ip, bool loopSkip)
{
    int             fd, intrface;
    struct ifreq    buf[16];
    struct ifconf   ifc;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) {
        return false;
    }

    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t) buf;
    if (ioctl(fd, SIOCGIFCONF, (char *) &ifc)) {
        close(fd);
        return false;
    }

    intrface = ifc.ifc_len / sizeof(struct ifreq);
    while (intrface-- > 0)
    {
        if(ioctl(fd,SIOCGIFFLAGS,(char *) &buf[intrface])) {
            continue;
        }
        if(loopSkip && buf[intrface].ifr_flags&IFF_LOOPBACK) continue;
        if (!(buf[intrface].ifr_flags&IFF_UP)) continue;
        if (ioctl(fd, SIOCGIFADDR, (char *) &buf[intrface])) {
            continue;
        }
        if (((struct sockaddr_in *) (&buf[intrface].ifr_addr))->sin_addr.s_addr == ip) {
            close(fd);
            return true;
        }
    }
    close(fd);
    return false;
}

例如我们有一个简单的主备策略:当发生VIP漂移的时候,备会切换成主,老的主则自动退出。 

slave执行的代码:


[cpp] view plaincopyprint?const char *config_vip = "10.32.36.219";  
uint32_t vip = getAddr(config_vip); // 将ip字符串地址转成2进制地址   
while(true)  
{  
   if (isLocalAddr(vip, true))  
   {  
       break; // vip漂移到了本机   
   }  
}  
// 下面是变成master后的代码   
....  

const char *config_vip = "10.32.36.219";
uint32_t vip = getAddr(config_vip); // 将ip字符串地址转成2进制地址
while(true)
{
   if (isLocalAddr(vip, true))
   {
       break; // vip漂移到了本机
   }
}
// 下面是变成master后的代码
....

master执行的代码:


[cpp] view plaincopyprint?const char *config_vip = "10.32.36.219";  
uint32_t vip = getAddr(config_vip); // 将ip字符串地址转成2进制地址   
while(true)  
{  
   if (!isLocalAddr(vip, true))  
   {  
       exit(0); // 自己不再是master,退出   
   }  
}

  • 作者:CSDN.NET
  • 来源网址:http://
  • 免责声明:本文所载资料仅供参考,资料的真实性、准确性由发布者负责,Viv-Media联合大众网对该资料或使用该资料所导致的结果概不承担任何责任。
  • 关于我们|提交网址|提交资讯|提交问答|友情链接|网站地图|广告赞助|帮助中心|举报中心|联系我们|国际站
  • Viv-Media联合大众网法律声明|服务条款|隐私声明|免责声明
  • Copyright 2010-2020 ©viv-media.com Corporation. All rights reserved. 冀ICP备11000884号-1  版权所有 Viv-Media联合大众网  合作伙伴:魅力文学网