Ceph分布式存储是怎么防止脑裂的?

Ceph分布式存储是怎么防止脑裂的?,第1张

解决脑裂问题,通常采用隔离(Fencing)机制,包括三个方面:

共享存储fencing:确保只有一个Master往共享存储中写数据。

客户端fencing:确保只有一个Master可以响应客户端的请求。

Slave fencing:确保只有一个Master可以向Slave下发命令。

Hadoop公共库中对外提供了两种fenching实现,分别是sshfence和shellfence(缺省实现),其中sshfence是指通过ssh登陆目标Master节点上,使用命令fuser将进程杀死(通过tcp端口号定位进程pid,该方法比jps命令更准确),shellfence是指执行一个用户事先定义的shell命令(脚本)完成隔离。

切换对外透明:为了保证整个切换是对外透明的,Hadoop应保证所有客户端和Slave能自动重定向到新的active master上,这通常是通过若干次尝试连接旧master不成功后,再重新尝试链接新master完成的,整个过程有一定延迟。在新版本的Hadoop RPC中,用户可自行设置RPC客户端尝试机制、尝试次数和尝试超时时间等参数。

在“双机热备”高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障,2个节点上的HA软件像“裂脑人”一样,“本能”地争抢“共享资源”、争起“应用服务”,就会发生严重后果:或者共享资源被瓜分、2边“服务”都起不来了;或者2边“服务”都起来了,但同时读写“共享存储”,导致数据损坏(常见如数据库轮询着的联机日志出错)。

运行于备用主机上的Heartbeat可以通过以太网连接检测主服务器的运行状态,一旦其无法检测到主服务器的“心跳”则自动接管主服务器的资源。通常情况下,主、备服务器间的心跳连接是一个独立的物理连接,这个连接可以是串行线缆、一个由“交叉线”实现的以太网连接。Heartbeat甚至可同时通过多个物理连接检测主服务器的工作状态,而其只要能通过其中一个连接收到主服务器处于活动状态的信息,就会认为主服务器处于正常状态。从实践经验的角度来说,建议为Heartbeat配置多条独立的物理连接,以避免Heartbeat通信线路本身存在单点故障。

1、串行电缆:被认为是比以太网连接安全性稍好些的连接方式,因为hacker无法通过串行连接运行诸如telnet、ssh或rsh类的程序,从而可以降低其通过已劫持的服务器再次侵入备份服务器的几率。但串行线缆受限于可用长度,因此主、备服务器的距离必须非常短。

2、以太网连接:使用此方式可以消除串行线缆的在长度方面限制,并且可以通过此连接在主备服务器间同步文件系统,从而减少了从正常通信连接带宽的占用。

基于冗余的角度考虑,应该在主、备服务器使用两个物理连接传输heartbeat的控制信息;这样可以避免在一个网络或线缆故障时导致两个节点同时认为自已是唯一处于活动状态的服务器从而出现争用资源的情况,这种争用资源的场景即是所谓的“脑裂”(split-brain)或“partitioned cluster”。在两个节点共享同一个物理设备资源的情况下,脑裂会产生相当可怕的后果。

为了避免出现脑裂,可采用下面的预防措施:

添加冗余的心跳线,例如双线条线。尽量减少“裂脑”发生机会。

启用磁盘锁。正在服务一方锁住共享磁盘,“裂脑”发生时,让对方完全“抢不走”共享磁盘资源。但使用锁磁盘也会有一个不小的问题,如果占用共享盘的一方不主动“解锁”,另一方就永远得不到共享磁盘。现实中假如服务节点突然死机或崩溃,就不可能执行解锁命令。后备节点也就接管不了共享资源和应用服务。于是有人在HA中设计了“智能”锁。即,正在服务的一方只在发现心跳线全部断开(察觉不到对端)时才启用磁盘锁。平时就不上锁了。

设置仲裁机制。例如设置参考IP(如网关IP),当心跳线完全断开时,2个节点都各自ping一下 参考IP,不通则表明断点就出在本端,不仅“心跳”、还兼对外“服务”的本端网络链路断了,即使启动(或继续)应用服务也没有用了,那就主动放弃竞争,让能够ping通参考IP的一端去起服务。更保险一些,ping不通参考IP的一方干脆就自我重启,以彻底释放有可能还占用着的那些共享资源。

使用W5200和W5500的TCP通信过程中,有一个非常容易被问到的问题:

(这里以W5200为例)

W5200作为服务器,假如客户端的网线断开 或 瞬间停电,服务器该怎样判断?

那么当客户端由于这些原因忽然断开,该怎样解决?

今天给大家介绍解决以上问题的办法,即如何使用Keepalive。

什么是Keepalive?

Keepalive即心跳检测,以下简称KA,之所以称之为心跳检测是因为它像心跳一样每隔一段时间发一次,以此来告诉对方自己是否存活。心跳检测用于TCP通讯过程中服务器检测客户端是处于长时间空闲(在线)还是已经断开,一般采用客户端定时发送简单的通讯包,一般是很小的包或者空包给服务器(W5200的心跳包为1字节),如果在指定时间内没有收到该心跳包,则服务器会判断客户端已经断开,此时程序中的Socket状态机会转到SOCKET_CLOSED并重新打开Socket去连接服务器/监听客户端。

KeepAlive怎么分类?

KA根据发出方不同可以分为两种,一种是由客户端发给服务器的心跳包,一种是服务器发给客户端的心跳包,选择哪一种方式需要看哪一方实现起来方便合理。需要注意的是,W5200根据合理的设计,其心跳包需要在Socket TCP连接建立之后,服务器和客户端至少进行一次数据交互,且在设定的时间内没有数据交互时发出。

W5200 KA程序说明

下面我以W5200的TCP Server官方例程为例,用PC建立TCP客户端来连接W5200,说明KA的实现方法。

定义和初始化部分:

程序中用到了定时器和中断函数,在w5200_configc中做了定义:

void Timer_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_TimeBaseStructureTIM_Period = 1000;

TIM_TimeBaseStructureTIM_Prescaler = 0;

TIM_TimeBaseStructureTIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructureTIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_PrescalerConfig(TIM2, 71, TIM_PSCReloadMode_Immediate);

TIM_Cmd(TIM2, ENABLE);

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

void Timer2_ISR(void)

{

ms++; // 等待时间自增,单位为ms

if((ms % 1000)==0) // 当等待时间增加到某一秒

{

if(ka_tick_flag==1)ka_no_data_tick++; // 若KA定时器标志位为1,无数据传输时间计时器自增

if(ka_no_data_tick>=NO_DATA_PERIOD)

{

ka_send_tick++; // 当无数据传输时间计时器值大于NO_DATA_PERIOD,KA发送定时器开始自增

if(ka_send_tick>=KA_SEND_PERIOD)

{

ka_sen d_flag=1; // 当KA发送定时器的大于KA_SEND_PERIOD,KA发送标志位置1,发送一个KA包

}

}

printf(""); // 当时间没到整秒,发一个“”

}

}

在主程序中进行初始化:

Timer_Configuration(); // 定时器初始化

NVIC_Configuration(); // 中断函数初始化

程序中定义了ka_tick_flag(KA定时器开始计时标志位)、ka_send_flag(KA发送标志位)、ka_no_data_tick(KA无数据传输时间计时器)以及ka_send_tick(KA发送定时器)。在w5200_configc中对以上定义进行了初始化:

uint32 ka_no_data_tick=0; // 定义无数据传输时间计时器

uint8 ka_tick_flag=0; // 定义KA定时器开始计时标志位

uint32 ka_send_tick=0; // 定义KA发送定时器

uint8 ka_send_flag=0; // 定义KA发送标志位

主循环部分:

当程序烧录后,按Reset键重启W5200后服务器打开一个Socket,此时Socket由SOCK_CLOSED变为SOCK_INIT并处于监听状态。PC建立客户端成功连接W5200后,Socket处于SOCK_ESTABLISHED,下面是程序具体的操作过程:

case SOCK_ESTABLISHED: // Socket处于连接建立状态

if(getSn_IR(0)& Sn_IR_CON)

{

setSn_IR(0, Sn_IR_CON); // Sn_IR的第0位置1

ka_tick_flag=0; // KA定时器开始计时标志位清零

ka_no_data_tick=0; // 无数据传输时间计时器

ka_send_flag=0; // KA发送标志位清零

ka_send_tick=0; // KA发送定时器清零

}

if ((len = getSn_RX_RSR(0)) > 0)

{

len = recv(0, RX_BUF, len); // W5200收到数据并保存到len

send(0,RX_BUF,len,(bool)0); // W5200将收到的数据发回客户端

if(ka_tick_flag==0)

{

ka_tick_flag=1; // W5200同客户端进行了一次通信后,将KA定时器开始计时标志位置1,进入定时器中断函数,只要接下来在NO_DATA_PERIOD内没有数据通信,就开始发KA包

}

ka_no_data_tick=0; // 无数据传输时间计时器清零

ka_send_tick=0; // KA发送定时器清零

}

// KA发送过程

if(ka_send_flag)

{

ka_send_flag=0; // KA发送标志位清零

ka_send_tick=0; // KA发送定时器清零

send_keepalive(0); // W5200发KA包给客户端

printf(""); // KA以””为标志在串口打印出来

}

break;

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » Ceph分布式存储是怎么防止脑裂的?

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情