HBase丢失数据的故障和原因分析
hbase的稳定性是近期社区的重要关注点,毕竟稳定的系统才能被推广开来,这里有几次稳定性故障和大家分享。
    第一次生产故障的现象及原因
    现象:
- 1 hbase发现无法写入
 - 2 通过hbck检测发现.META.表中出现空洞,具体log是:;Chain of regions in table ... is broken; edges does not contain ...
 - 3 此时读写失败
 
修复方法:直接使用check_meta.rb重新生成.META.表并修补空洞,但是会引起数据丢失。因为引起该空洞的原因是某个region的parent和daughter都被删掉了
    查找故障过程非常复杂,具体就不提了,都是内伤啊...
    故障原因需要从split的原理说起:
    split是一个分布式的事务过程,由于分布式的复杂性,在每一步都有可能发生异常中止,因此每进行一步就要记录一下当前的状态。如果出错了,就根据己经进行的状态来进行对应的回滚操作。这个记录状态的变量在代码里体现为JournalEntry
    于是split的过程是这样的:(见图)

- 1 创建splitDir(region目录下的splits目录)
 - 2 状态机添加CREATE_SPLIT_DIR
 - 3 执行internalFlushcache把内存刷到磁盘
 - 4 close parent并且返回所有storefile
 - 5 状态机添加CLOSED_PARENT_REGION
 - 6 把region从rs的online列表中删除
 - 7 状态机添加OFFLINED_PARENT
 - 8 多线程进行split storefiles,创建子目录并把文件写进去,(原文件不删除,该过程默认超过30s会强行中止并抛出IOE)
 - 9 状态机添加STARTED_REGION_A_CREATION
 - 10 创建第一个daughter region
 - 11 状态机添加STARTED_REGION_B_CREATION
 - 12 创建第二个daughter region
 - 13 在meta表中下线parent
 - 14 原子性往meta表中写以下信息:parent置为offline以及split状态,parent添加两列:splitA和splitB
 - 15 并发open DaughterA和DaughterB(如果线程中断,则通知rs退出进程)
 - 16 在open期间,如果server中止,则先把A和B的信息写入到meta表中再跳过以下过程
 - 17 创建两个新的HRegion,通知rs把子region添加到online列表中
 - 18 把Daughter信息写入meta表
 
当以上过程中任何一步抛出异常时,regionserver会进入回滚逻辑(rollback):
    对状态机中存储己经进行的状态进行检查,并从后往前开始遍历己进行的状态:
- CREATE_SPLIT_DIR:删除子目录
 - CLOSED_PARENT_REGION:重新初始化parent
 - STARTED_REGION_A_CREATION:删除A对应的目录
 - STARTED_REGION_B_CREATION:删除B对应的目录
 - OFFLINED_PARENT:把parent添加到online队列中
 
了解了以上过程,我们来假设以下两种场景:
    场景1 如果split期间如果在第4步(close parent并且返回所有storefile)结束后,或者执行过程中发生异常,那么此时会发生什么呢?
    状态机里的值是CREATE_SPLIT_DIR,因此会删除子目录,但由于parent己经被close或者处于closing状态了,那么就是父子region都没有在线,此时无法读写该region对应的数据
    场景1还比较好解决,比如直接下线该台rs再重启就能解决了。当然对于在线业务来讲,这个还是不能接受的,因为系统不可用时间太长了。于是需要用到HBASE-4563这个patch来解决它
    它的原理很简单:把CLOSED_PARENT_REGION状态放到close parent前面即可
    场景2 如果split期间在第14步期间或以后发生异常。那此时meta表己经将parent下线了,回滚时却没有将parent在meta中的状态改回来,而是删除了子region的目录以及open parent
(注意在open parent的时候并不会修改meta中的offline及split值)。于是该region就不再上线了,形成了空洞。不过这个时候客户端如果cache了该region的地址,那暂时还不会报错,
因为regionserver己经把它重新上线了,数据暂时还能读到。
    但是严重的问题是:master有个垃圾清理线程(CatalogJanitor)会定期对meta表做扫描,默认5min一次。它会扫描meta表中split和offline状态为true的那些region,检查是否有子region指向它,如果没有的话,它会认为这个region是己经split成功的,于是会将它从meta表以及hdfs上删掉。检查子region是否指向它是检查是否有子目录存在并且不为空。在场景2中显然子目录己经不再存在了,因此被认为是split成功的region,于是数据被master删掉...
    这里的根本原因是没有对写meta这个状态进行记录以及回滚,并且master检查子region是否存在的条件太过简单,需要做调整。具体可参见HBASE-3872以及HBASE-4562(3872试图解决这个问题,但是没有解决掉。4562进行了进一步的处理)
    修复的原理就是增加一个状态来记录,而当回滚发现这个问题时,让这台regionserver自己挂掉。这样在master恢复它的时候,会执行fixDaughter的逻辑,这个逻辑会完整地恢复这个region,让split成功,子region上线。而CatalogJanitor的逻辑也进行了调整,对数据进行更加严格的检查和保护,避免随意删除数据。
    场景2是个非常严重的bug,推荐大家都升级一下。因为在复杂的网络环境中这个异常还是比较容易出现的。
    第二次生产故障的现象及原因
    现象:
- 1 用户发现tps有下降,且部分写入不正常。
 - 2 通过hbck检查到集群有"Chain of regions in table …contains less elements than are listed in META; visited=”问题存在,意即META表中某些region出错,此时若用户有新的写入,则新的写入有可能会数据丢失。
 - 3 通过1个多小时的修复,仍然没有将该集群状态无损还原。原因是出现了两个region服务同一段数据
 
修复方法:找到start_key和end_key相同的几个region,把它们的从hdfs上删除掉。然后用add_table重建meta表(会导致丢失数据)
    这个过程也是一个hbase的bug产生的,这个bug来自于重启过程。复现问题也很容易,进行以下几步即可复现:
    1 找到一台正在split的region所在的rs
    2 kill掉该台rs
    3 重启整个集群或master进行切换
    原因分析:
    当hbase的master在主从切换或者重启的时候,有一个步骤是切换之后的master需要对原来所有的挂掉的regionserver上的region进行processDeadRegion,即重新上线。
    该过程在0.90.4之前存在一个bug,即会把meta表中所有处在split期间的region也进行处理,虽然region在meta表中处于split状态并不能证明它己经split结束还是正在split(要对split状态进行标记还是很复杂的,因此目前的代码还没有对split状态进行记录,只能通过一些辅助手段,比如检查子region的状态来说明region是否处于split状态),但是万一它己经split结束的话是绝对不应该上线的。因此有可能一个region己经split结束,但它在这个处理过程中又被新起的master上线了,这就导致父子region同时服务了。而父region上线后又有可能继续split,导致状况更加糟糕,同一段数据被两个region服务,等等。
    正确的处理办法是在重启时检查这些region的子region状态,具体检查方案在hbase-0.90.4中己经给出,可参见HBASE-3946。注意:打上3946的patch以后,还必须要打上3995的patch,否则单元测试无法通过。
HBase丢失数据的故障和原因分析的更多相关文章
- MYSQL数据表损坏的原因分析和修复方法小结
		
MYSQL数据表损坏的原因分析和修复方法小结 1.表损坏的原因分析 以下原因是导致mysql 表毁坏的常见原因: 1. 服务器突然断电导致数据文件损坏. 2. 强制关机,没有先关闭mysql 服务. ...
 - Entity Framework 数据并发访问错误原因分析与系统架构优化
		
博客地址 http://blog.csdn.net/foxdave 本文主要记录近两天针对项目发生的数据访问问题的分析研究过程与系统架构优化,我喜欢说通俗的白话,高手轻拍 1. 发现问题 系统新模块上 ...
 - 记一次OGG数据写入HBase的丢失数据原因分析
		
一.现象二.原因排查2.1 SparkStreaming程序排查2.2 Kafka数据验证2.3 查看OGG源码2.3.1 生成Kafka消息类2.3.2 Kafka配置类2.3.3 Kafka 消息 ...
 - Lily HBase Indexer同步HBase二级索引到Solr丢失数据的问题分析
		
一.问题描述二.分析步骤2.1 查看日志2.2 修改Solr的硬提交2.3 寻求StackOverFlow帮助2.4 修改了read-row="never"后,丢失部分字段2.5 ...
 - Beforeunload打点丢失原因分析及解决方案
		
淘宝的鱼相在 2012 年 8 月份发表了一篇文章,里面讲述了他们通过一个月的数据采集试验,得到的结果是:如果在浏览器的本页面刷新之前发送打点请求,各浏览器都有不同程度的点击丢失情况,具体点击丢失率统 ...
 - SQL Server扩展事件的使用ring_buffer target时“丢失”事件的原因分析以及ring_buffer target潜在的问题
		
事情起因: 排查SQL Server上的死锁问题,一开始想到的就是扩展事件, 第一种方案,开profile守株待兔吧,显得太low了,至于profile的变种trace吧,垂垂老矣,也一直没怎么用过. ...
 - mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310
		
mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310
 - Hbase写数据,存数据,读数据的详细过程
		
Client写入 -> 存入MemStore,一直到MemStore满 -> Flush成一个StoreFile,直至增长到一定阈值 -> 出发Compact合并操作 -> 多 ...
 - Kudu – 在快数据上的进行快分析的存储
		
转自: http://www.tuicool.com/articles/nmYf2uf Cloudera Impala Kudu – 在快数据上的进行快分析的存储 Kudu,对应中文的含义应该 ...
 
随机推荐
- lucene查询索引库、分页、过滤、排序、高亮
			
2.查询索引库 插入测试数据 xx.xx. index. ArticleIndex @Test public void testCreateIndexBatch() throws Exception{ ...
 - GDB调试工具入门
			
从windows转到linux下已经有一段时间了,每次刷算法题碰到问题需要调试的时候,就分分钟想关机,切换到windows上调试.于是,花了一点时间来搜索一下linux下常见的调试工具,这不搜不知道, ...
 - Android 增量更新和升级
			
在年初的时候,尝试了一把热修复技术,当时选择的是阿里的andfix,使用起来也很简单,这里就不在多少,如果你对andfix有兴趣请链接:点击打开链接.虽然网上将热修复的文章很多,不过我还是想说原理,然 ...
 - 仿淘宝购物车demo---增加和减少商品数量
			
在上一篇博客中,小编简单的介绍了如何使用listview来实现购物车,但是仅仅是简单的实现了列表的功能,随之而来一个新的问题,买商品的时候,我们可能不止想买一件商品,想买多个,或许有因为某种原因点错了 ...
 - 06 Activity的启动模式 Intent的七大属性的总结
			
1.Task以及back stack >Task(任务) 为了完成一个功能 多个Activity的集合, 当你的应用程序启动时 系统会自动创建Task用于管理Activity ...
 - scala学习笔记5 (隐式转化/参数/类)
			
隐式转化: 隐式参数: 隐式类:
 - Android初级教程三个Dialog对话框小案例
			
这里把三个对话框形式写在一个项目程序里面,用三个按钮控制显示什么样式的对话框. 先看布局文件代码: <LinearLayout xmlns:android="http://schema ...
 - A*寻路算法入门(四)
			
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
 - 给你的流添加缓冲装置——字节块ByteChunk
			
这是一个很重要的一个字节数组处理缓冲工具,它封装了字节缓冲器及对字节缓冲区的操作,包括对缓冲区的写入.读取.扩展缓冲区大小等等,另外还提供相应字符编码的转码操作.此工具让缓冲操作变得更加方便,除了缓冲 ...
 - (六十五)iOS的socket实现(GCDAsyncSocket)
			
本文介绍使用GCDAsyncSocket来实现iOS端的socket,有关简易服务端的代码已经在上一篇文章中提到,这里不再赘述,将直接介绍如何实现客户端. 首先下载CocoaAsyncSocket框架 ...