看一下下图就知道了吧。
对于用户的一个表比如Blog,可能包括数据多达亿级
该表的数据可以分布在多个HRegion
而每个HRegion保存表的某一段数据
UserTable (1)------HRegion(*)
对于多个的HRegion则有HRegion Server来维护
每个HRegion唯一对应一个HRegion Server
通过HRegion Server才能够访问对应的HRegion
而一个HRegion从物理上分为如下几个部分
HMemCache(内存缓存),HLog(日志),HStore(持久化存储)
三:HBase的数据 *** 作流程
a:读数据
优先从HMemcache中读取,如果没有读到从HStore中读取
当然这里需要关注:读、写同步的问题,HBase如何解决,还有第一个客户端读取数据从HStore读取后,是否会加载到HMemCache中;后续的客户端,读取时直接从HMemCache中读取,以及MemCache中数据的过期化算法
b:写数据
HBase 写入数据会写到HMemcache 和Hlog 中,HMemcache 建立缓存,颤简冲Hlog 同步Hmemcache和Hstore 茄歼的事务日志,发起Flush Cache 时,数据持久化到Hstore 中,并清空HMemecache。
此处需要关注:
HBase写数据,首先写入Memcache,并计入Log中,最后写入HStore中,如果在写入HStore是发生系统异常,就可以从Log中恢复数据,重新写入HStore中。【该机制跟咐凳BigTable中的SSTabl,MemTable和CommitLog的作用一样】
c:客户端 *** 作数据流程
客户端访问这些数据的时候通过Hmaster ,每个Hregion 服务器都会和Hmaster 服务器保持一个长连接,Hmaster 是HBase 分布式系统中的管理者,他的主要任务就是要告诉每个Hregion 服务器它要维护哪些Hregion。用户的这些都数据可以保存在Hadoop 分布式文件系统上
如果一个HMaster挂了,Secondary NameNode会自动替代HMaster
但是对应的失效转发的效率还需要进一步尝试,可能依赖ZooKeeper的相关配置项
在HBase的根目录下面,有两个跟此棚日志相关的目录,.logs和.oldlogs。.logs保存的是所有Regionserver上当前在写入的HLog,可以看到每个RegionServer对应一个文件,所以HLog是对应RegionServer的。 HLog默认情况下每个小时会滚动,这是通过参数hbase.regionserver.logroll.period控制的,这个参数的默认值是1小时。 此外,hbase.regionserver.hlog.blocksize和fs_local.block.size控制当HLog的大小森野则超过32M的时候,会滚动。 Hbase.regionserver.logroll.multiplier,默认值是95%,表示日志达到95%的时候,也会进行滚动。 日志文件的滚动 *** 作,就是检查HFile中的序列号,确认日志中所有的序列号都小于HFile的序列号,确保所有的日志内容都已经固化到HFile中,确认后将当前的日志挪到.oldlog目录下。 这里有个问题还有些疑惑,书里写的是检查写入存储文件中最大的序列号是中国,小于这个序列号的所有修改都已经固化了,只要确保日志中的最大序列号比这个序列号小,就可以确认这个日志已经固化,可以挪到.oldlog下。 但是memstore刷新到HFile是对HStore的,对表的,可能有的表更新比较多,刷新的快,已经固化到HFile,但有的表修改少,脊碰还没有刷新到HFile,这和序列号的顺序应该是没有必然的关系的,后续应该可以做个测试来验证一下。 当前日志的文件,在写满一个块之前,都显示的是0字节,但实际上可能已经有数据,只是显示的问题而已。 现在插入几条记录,做些修改的 *** 作,查看日志的内容: hbase(main):001:0>put't_lisa','lisa5','cf_1:w1','10d2' 0 row(s) in 0.4590 seconds hbase(main):002:0>put't_lisa','lisa6','cf_1:w1','1032' 0 row(s) in 0.0050 seconds hbase(main):003:0>put't_lisa','lisa7','cf_1:w1','10z2' 0 row(s) in 0.0040 seconds hbase(main):004:0>put't_lisa','lisa8','cf_1:w1','10e2' 0 row(s) in 0.0040 seconds hbase(main):002:0>delete 't_lisa','lisa5','cf_1' 0 row(s) in 0.4270 seconds 查看日志文件,虽然大小为0,但是实际上写 *** 作是先写了WAL,才写memstore的,这里只是文件大小显示的问题。 每个regionserver最初都会有一个HLog,不管是不是有更新 *** 作。 [root@a01 hbase]# hadoop fs -ls /hbase_root/.logs 查看日志文件的内容,-p表示查看对应的value: [root@a01 hbase]# bin/hbase hlog /hbase_root/.logs/*,60020,1385442023669/*%2C60020%2C1385442023669.1385449225598 -p Sequence 2316016 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa5 column: cf_1:w1 at time: Tue Nov 26 15:17:04 CST 2013 value: 10d2 Sequence 2316017 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa6 column: cf_1:w1 at time: Tue Nov 26 15:17:04 CST 2013 value: 1032 Sequence 2316018 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa7 column: cf_1:w1 at time: Tue Nov 26 15:17:04 CST 2013 value: 10z2 Sequence 2316019 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa8 column: cf_1:w1 at time: Tue Nov 26 15:17:04 CST 2013 value: 10e2 Sequence 2316020 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa5 column: cf_1: at time: Tue Nov 26 15:31:49 CST 2013 value: 截取其中的一小段进行分析: Sequence 2316016 from region fa8f6eb2a0bcb54e443f9bfc2693768d in table t_lisa Action: row: lisa5 column: cf_1:w1 at time: Tue Nov 26 15:17:04 CST 2013 value: 10d2 Sequence 2316016 :序列号,在恢复的时候,会判断这个id和HFile中序列ID的大小,小于HFile序列ID(MAX_SEQ_ID_KEY)的 *** 作不用再重做,因为已经固化到数据文件中了。 region fa8f6eb2a0bcb54e443f9bfc2693768d:region name中按照前面部分的MD5散列值 table t_lisa: 表名 row: lisa5:行键 column: cf_1:w1:列族和列标识符 value: 10d2:值 Delete 和 insert *** 作的日志并没有明显写明action 查看HFile的信息,这里可以看到HFile中的kv数据、压缩、起始rowkey等非常详细的信息: [root@a01 ~]# cd /home/hbase [root@a01 hbase]# bin/hbase org.apache.hadoop.hbase.io.hfile.HFile -f /hbase_root/t_lisa1/787ce41dabb55075935e7060583ae6af/cf_1/e541b8a04f224e869166ee43783bd8d0 -v -m -p K: lisa1/cf_1:a/1384389531130/Put/vlen=1/ts=0 V: 1 K: lisa1/cf_1:b/1384390435899/Put/vlen=1/ts=0 V: 6 K: lisa1/cf_1:b/1384389531157/Put/vlen=1/ts=0 V: 5 K: lisa1/cf_1:b1/1384390714903/Put/vlen=2/ts=0 V: 61 firstKey=lisa1/cf_1:a/1384389531130/Put, lastKey=lisa1/cf_1:b1/1384390714903/Put, MAX_SEQ_ID_KEY = 230924首先要明确hadoop使用的log机制。hadoop使用了slf4j,log4j,apache的common-logging。slf4j是扒唯好纯的log接口,common-logging和log4j既是接口
也有实现。而common-logging在检查到classpath下有log4j存在时会默认用log4j吐出log,classpath里有
slf4j-log4j12-xxx.jar时slf4j也通过log4j吐出log。这样hadoop的所有log都通过一个
log4j.properties配置即可管理log的吐春铅出。关系图如下:
但。。。我们自己的central logging系统只有logback的appender。因此需要把这些logging的家伙都转到logback里再通过logback里的logAppender存到我们自己的log系统里。
了解了原理,我们看下如何让logback一统天下,把他们全收拾了。
原理:
在classpath中加上log4j-over-slf4j
jar包,这样log4j就会进入slf4j,在classpath中加入jcl-over-slf4j
jar包,common-logging的log就也会进入slf4j。此时只要再加上logback的jar包,slf4j是纯接口,此时只有
logback一条路可以走,这样所有的log就会乖乖的都从logback里吐出来了。下面看下实际配置的步骤:
1.创建需要lib的文件夹:
sudo mkdir /logback
2.放入我们所需的lib:
3.由于我们用的cdh系列,需要让lib目录能够让hdfs用户能访问:
sudo chmod 777 -R /logback
sudo chown -R hdfs:hdfs /logback
4.修改hadoop的启动脚本,添加我们的lib到classpath下:
sudo vim /etc/hadoop/conf/hadoop-env.sh
添加以下内容
[html] view plaincopy
<span style="font-size:18px">修改classpath
LOGBACK_HOME=/logback
for i in "$LOGBACK_HOME"/*.jardo
HADOOP_CLASSPATH="$i":"$HADOOP_CLASSPATH"
done
export HADOOP_CLASSPATH</span>山信
5.添加我们的logback.xml配置文件到hadoop的配置目录下:
sudo mv ~/logback/logback.xml /etc/hadoop/conf/
配置文件内容如下:
[html] view plaincopy
<span style="font-size:18px"><?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_DIR" value="${hadoop.log.dir}"/>
<property name="LOG_FILE_NAME" value="${hadoop.log.file}"/>
<!-- Output to File and Rotate if it's necessary -->
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${LOG_FILE_NAME}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${LOG_DIR}/${LOG_FILE_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %10logger [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<!--Output to central logging-->
<appender name="CentralLogging" class="com.ctrip.freeway.appender.CentralLoggingAppender">
<appId>901240</appId>
<serverIp>192.168.82.58</serverIp>
<serverPort>63100</serverPort>
</appender>
<root level="INFO">
<appender-ref ref="ROLLING"/>
<appender-ref ref="CentralLogging"/>
</root>
</configuration></span>
可以看到我们添加了自己的CentralLogging的Appender。
6.把slf4j-log4j12-1.6.1这个jar包注释掉!因为如果保留,log4j和logback会竞争,而不幸的是logback比log4j晚加载,所以log还会走log4j。。。此坑搞了半天
sudo mv /usr/lib/hadoop/lib/slf4j-log4j12-1.6.1.jar /usr/lib/hadoop/lib/slf4j-log4j12-1.6.1.jar.bak
ok,配置完后,重启hadoop机器,搞定。但我们还是不满足,hbase的log也搞进来多好啊。
1.添加logback配置到hbase配置目录:
类似上面步骤5
2.注释掉thrift的jar包。此步不是必须的!因为我们的central
logging系统会用到thrift的jar包,而hbase也有thrift。hbase的thrift版本比较低,我们的central
logging会报错。因此注释掉hbase的thrift即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)