处理大数据时如何确保断电不丢数据

今年7、8月份杭州实行拉闸限电时,导致阿里余杭机房的机器意外断电,造成HDFS集群上的部分数据 丢失。

在Hadoop 2.0.2-alpha之前,HDFS在机器断电或意外崩溃的情况下,有可能出现正在写的数据丢失的 问题。而最近刚发布的CDH4中HDFS在Client端提供了hsync()的方法调用(HDFS-744),从而保证在机器崩 溃或意外断电的情况下,数据不会丢失。这篇文件将围绕这个新的接口对其实现细节进行简单的分析,从 而希望找出一种合理使用hsync()的策略,避免重要数据丢失。

HDFS中sync(),hflush()和hsync()的差别

在hsync()之前,HDFS就已经提供了sync()和hflush()的调用,单从方法的名称上看,很难分辨这三个 方法之间的区别。咱们先从这几个方法之间的差别介绍起。

在HDFS中,调用hflush()会将Client端buffer中的存放数据更新到Datanode端,直到收到所有 Datanode的ack响应时结束调用。这样可保证在hflush()调用结束时,所有的Client端都可以读到一致的 数据。HDFS中的sync()本质也是调用hflush()。

hsync()则是除了确保会将Client端buffer中的存放数据更新到Datanode端外,还会确保Datanode端的 数据更新到物理磁盘上,这样在hsync()调用结束后,即使Datanode所在的机器意外断电,数据并不会因 此丢失。而hflush()在机器意外断电的情况下却有可能丢失数据,因为Client端传给Datanode的数据可能 存在于Datanode的cache中,并未持久化到磁盘上。下图描述了从Client发起一次写请求后,在HDFS中的 数据包传递的流程。

hsync()的实现本质

hsync()执行时,实际上会在对应Datanode的机器上产生一个fsync的系统调用,从而将内存中的相关 文件的数据更新到磁盘。

Client端执行hsync时,Datanode端会识别到Client发送过来的数据包中的syncBlock_字段为true,从 而判定需要将内存中的数据更新到磁盘。此时会在BlockReceiver.java的flushOrSync()中执行如下语句 :

((FileOutputStream)cout).getChannel().force(true);

而FileChannel的force(boolean metadata)方法在JDK中,底层为于FileDispatcherImpl.c中调用 fsync或fdatasync。metadata为true时执行fsync,为false时执行fdatasync。

Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, 
jobject fdo, jboolean md)
{
    jint fd = fdval(env, fdo);
    int result = 0;

    if (md == JNI_FALSE) {
        result = fdatasync(fd);
    } else {
        result = fsync(fd);
    }
    return handle(env, result, "Force failed");
}




转载请注明:http://www.xcqg58.com/lsqy/lsqy/7.html