
基于大数据平台的
亿级别非结构化数据的存储实现
尊龙时凯
赵军

1.
项目背景
本次建设基于某政府单位的电子档案系统,,,整体数据存储量为240TB左右,,使用Oracle存储,,,并且按每年30%比例持续增长,,,,随业务发展,,,预计未来5年内将达到1PB左右的数据量。。。。当存储的数据量过大时,,,Oracle数据库将面临需要更大的存储空间,,,,大数据量的导入导出将导致数据库无法高效、、稳定的运行;同时所需要的全备份周期会逐渐延长,,,,会影响到工作时间内业务运行;存储资源需求过大,,,整个灾备系统的存储资源也会投入过大。。。
目前电子档案数据库数据
表1电子档案主要表情况(截止到2021年底)

存储空间严重不足
电子档案数据库总存储量为240TB左右,,,,按照现在的增长速度呈指数级上升,,,,5年内将达到1PB左右的数据量,,Oracle数据库将需要更大的存储空间。。。从资金层面考虑数据库 SAN 上的磁盘存储通常比 Web 服务器场中使用的磁盘上的存储更为昂贵。。。
数据存取方式落伍
原架构对于电子档案数据采用直接通过服务器端程序将需要存储的文件转为二进制文件流直接存在数据库表的BLOB字段中,,,,当需要查询时同样也是服务器端将文件以流的方式查询出来,,,,经过处理后以二进制流的方式发送给客户端显示出来。。。。
此种方法从项目的角度上来说,,,文件存储和数据库存储最好是要分离的,,,二进制的存储方式特别是针对存储文件大而多的情况,,因为性能较差,,,且大量占用数据库内存,,,,已经逐步淘汰。。
计算压力不堪重负
原电子档案数据存储在Oracle数据库中,,,,查询条件单一,,已不能满足电子档案业务的管理需求。。。。随着数据量的上涨,,,服务器计算压力也逐渐不堪重负。。对电子档案库的查询操作在原系统中发生非常频繁,,在工作日繁忙阶段可产生高并发的情况,,,按目前通过文件二进制流的查询方式,,,,查询效率已经不甚乐观,,,,随着数据量的不断加大,,如果继续按目前的查询方式来看查询效率会不断的下降,,,,直接影响到日常业务,,,降低工作效率。。
安全运行无法保障
大数据量的导入导出将导致数据库无法高效、、稳定的运行。。加之数据库单点故障、、、磁盘损坏等情况更会加剧数据库走向奔溃。。。
全量备份周期延长
随着数据量的增长,,所需要的全备份周期会逐渐延长,,会影响到工作时间内业务运行;存储资源需求过大,,,,整个灾备系统的存储资源也会投入过大。。。。
2.
想法与设计
2.1 方案选择
为解决电子档案系统存储空间不足、、、、运行状态不稳定、、、计算负荷过重、、、备份效率低下的问题,,,,我们迫切需要改变现有的电子档案集中式存储架构。。集中式存储服务器使用本地磁盘存放所有数据,,增加磁盘是解决存储空间唯一的办法,,,,计算能力无法提升,,,系统安全性和可靠性也无法得到保证,,,,不能满足大规模存储应用的需求。。而当前的电子档案系统就是采用了这种架构模式。。
表2 集中式存储架构和分布式存储架构特性比较


图1 集中式存储架构和分布式存储架构比较
因此我们将采用分布式存储架构替换原有的集中式存储系统,,分布式存储系统采用可扩展的系统结构,,,,利用多台存储服务器分担存储负荷,,,利用位置服务器定位存储信息,,,它提高了系统的可靠性、、、、可用性和存取效率,,还易于扩展。。分布式存储架构的种种特性,,,,都能够完美的解决我们当下所面临的问题。。。
2.2 问题解决
存储空间严重不足
分布式存储不再需要昂贵的磁盘阵列来解决存储问题,,廉价的商用机器都能扩展器存储能力。。。
分布式存储系统通过对集群服务器规模进行进行扩展,,,从而使系统存储容量、、计算和性能得到提高。。。随着业务量的增大,,对底层分布式存储系统的性能要求也随之增高。。。。衡量可扩展性的要求集群具有线性的可扩展性,,,系统整体性能和服务数量是线性关系。。分布式存储有着合理的分布式架构,,,能够预估并且弹性扩展计算、、存储容量和性能。。
计算压力不堪重负
分布式存储的去中心化思想,,让各个节点都能分担计算压力,,,,计算能力随着节点的扩展而提升。。。。
系统的吞吐量和系统的响应延迟这两项指标,,经常被用来衡量分布式存储系统的性能。。通常高性能的分布式存储,,,能够高效的管理读缓存和写缓存,,,并且能够自动分级存储。。分布式存储是通过把热点区域内数据映射到高速缓存中,,,以此来提高系统响应的速度;如果这些区域不再是热点,,,,那么存储系统就会将它们从高速缓存中剔除。。而写缓存技术则是配合高速存储,,来使得整体存储的性能有显著提高,,,按一定的策略,,,先将数据写入高速存储,,再在适当的时间进行同步落盘。。。
安全运行无法保障
不用再担心单点故障的问题,,,数据多副本分散存储,,即使多个节点宕机,,系统依然能对外提供服务。。。。
使用网络进行松耦合连接,,,分布式存储能够允许高速存储和低速存储分开部署,,,或者以任意比例混布,,,,在业务环境不可预测,,或者用于敏捷的情况下,,,将分层存储的技术优势发挥到最佳。。。而且分布式存储系统不受恶意访问和攻击,,,,能够保护存储数据不被窃取。。。。
全量备份周期延长
系统默认的多副本、、多节点放置策略,,无需再考虑数据备份的问题,,,,从而节省昂贵的异地容灾备份。。
分布式系统数据安全方面的容灾与备份,,数据可靠不丢失。。。。在分布式存储的容灾中,,一个重要的手段就是多时间点快照技术,,这样用户生产系统可以实现在一定时间间隔内对各版本数据的保存。。而且,,,,多时间点快照技术,,能够支持同时提取多个时间点的样本,,,并且同时进行恢复。。。。这一功能对于故障重现也很有帮助,,可帮助进行分析和研究,,,,避免类似灾难的再次发生。。多时间点快照,,,周期增量复制等技术为分布式存储的高可靠性提供了保障。。。。
2.3 产品选型
考虑到实际场景的需要,,,,我们的目标是要建立一套全新的分布式存储系统,,既能满足数据存储的需要,,也能提供快速高效的数据请求服务,,,,并尽可能的避免对现有的业务审查系统造成影响。。。。在我们产品选型方案中,,,FastDFS、、、MinIO、、、HDFS、、、、HBase是我们根据场景需要进行筛选比对之后,,选择最佳的一种。。。。
FastDFS

图2 FastDFS架构图
虽说能能解决海量非结构化数据(PDF)的存储问题,,,但是需要额外的关系型数据来存放PDF的关键信息(文件名称、、大小、、在FastDFS中的位置等),,,也不能很好的使用内存提高读写效率。。
MinIO

图3 MinIO架构图
MinIO对象存储系统是为海量数据存储、、人工智能、、、大数据分析而设计,,,,适合存储海量图片、、、视频、、、日志文件、、备份数据等,,,同样的,,,关键信息也需要额外的关系型数据库控制。。。
HDFS

图4 HDFS架构图
HDFS是指被设计成适合运行在通用硬件上的分布式文件系统,,但其关键信息也需要额外的关系型数据库控制,,,,再者它不适合低延迟的数据访问,,,不支持并发写入和文件随机修改,,,这不是我们想要的。。
HBase

图5 HBase架构图
HBase特别适合于非结构化数据的存储,,,关键信息与PDF一并存储,,不需额外的关系型数据库。。充分使用内存资源,,,从而能够对外提供低延时、、高并发的读写请求服务,,,,这最适合我们的业务需求。。
按照HBase设计特性,,,,有如下优势是我们业务场景迫切需要的:
1) 容量巨大
HBase的单表可以有百亿行、、、百万列,,,,可以在横向和纵向两个维度插入数据,,,,具有很大的弹性。。。
当关系型数据库的单表记录在亿级别时,,,查询和写入的性能都会呈现指数级下降,,这种庞大的数量对传统数据库来说是一种灾难,,,而HBase在限定某个列的情况下对于单表存储百亿甚至更多的数据都没有性能问题。。
HBase采用LSM树作为内部数据存储结构,,,这种结构会周期性的将小文件合并为大文件,,,以减少对磁盘的寻址时间。。。
2) 列存储
与很多面向行存储的关系型数据不同,,HBase是面向列的存储和权限控制的,,它里面的每个列式单独存储额的,,且支持基于列的独立检索。。通过下图的列子来看行存储和列存储的区别:

图6 行存储和列存储区别
从上图可以看到,,,行存储里的一张表的数据都放在一起,,,,但在列存储里是按照列分开保存的。。。。在这种情况下,,,,进行数据的插入和更新,,,行存储会相对容易。。而进行行存储时,,查询操作需要读取所有的数据,,,列存储则只需要读取相关列,,,,可以大幅度降低系统的I/O吞吐量。。。
3) 稀疏性
通常在传统的关系型数据库中,,,,每一列的数据类型是事先定义好的,,会占用固定的内存空间,,,在此情况下,,,,属性值为空(NULL)的列也需要占用存储空间。。
而在HBase中的数据都是以字符串形式存储的,,为空的列并不占用存储空间,,因此HBase的列存储解决了数据稀疏的问题,,在很大程度上节省了存储开销。。所以HBase通常可以设计成稀疏矩阵,,,同时这种方式比较接近实际的应用场景。。。
4) 扩展性强
HBase工作在HDFS之上,,,理所当然也支持分布式表,,,,也继承了HDFS的可扩展性。。。HBase是横向扩展的,,,,横向扩展是指在扩展时不需要提升服务器本身的性能,,,只需要添加服务器到现有的集群即可。。
HBase表根据Region的大小进行分区,,分别存储在集群中不同的节点上,,,当添加新的节点时,,,集群就重新调整,,,在新的节点启动HBase服务器,,动态实现扩展。。这里需要指出的是,,HBase的扩展是热扩展,,即在不停止现有的服务器的前提下,,,,可以随时添加或减少节点。。。
5) 高可靠性
HBase运行在HDFS之上,,HDFS的多副本存储可以让它在出现故障时自动恢复,,,同时HBase内部也提供了WAL(预写日志文件)和Replication机制。。
WAL(Write-Ahead-Log)预写日志是在HBase服务器处理数据插入和删除的过程中用来记录操作内容的日志的,,,保证了数据写入时不会因集群异常而导致写入数据的丢失;而Replicaiton机制是基于日志操作来做数据同步的。。
当集群中的单个节点出现故障时,,,协调服务器组件ZooKeeper通知集群的主节点,,将故障节点的HLog中的日志信息分发到各从节点进行数据恢复。。。。
2.4 设计目标
集群管理
集群管理方面:提供可视化的UI界面,,,实现集群自动化安装、、、中心化管理、、、、集群监控、、、、报警功能为一体的控制平台。。。
平台运行
平台运行方面:保证低故障率、、、出现问题快速修复;可提供全天候24小时不间断服务。。
读写请求
读写请求方面:即使在数据量急速上涨的情况下依然能够提供低延迟、、高并发的读写请求。。
数据迁移
数据迁移方面:保证由Oracle到HBase之间的数据迁移不影响当前业务系统使用,,,,数据迁移准确无遗。。。。
3.
实践与落地
3.1 集群管理
根据我们的业务场景需求,,,,我们希望能够避免使用原生的Apache Hadoop来部署HBase,,而是使用企业版大数据平台来实现,,,,即CDH(Cloudera Distributed Hadoop)。。。因为原生的Apache Hadoop和HBase都有很多未修复的Bug存在,,,而且实际过程中往往需要频繁的操作命令行,,不是一两个人所能完成;而CDH解决了原生Hadoop的很多未修复问题,,,,升级和各个生态圈技术的兼容性,,,也提供了可视化UI界面来供运维人员部署其余组件,,,大大减少了集群的部署时间。。。。总的来说,,,CDH提供开箱即用的企业使用所需的一切,,换位满足企业需求而构建,,CDH将Hadoop与十几个其他关键的开源项目集成。。。。
使用CM(Cloudera Manager),,我们可将集群自动化安装、、、、中心化管理、、集群监控、、、报警处理等功能融为一体。。。。集群的安装可以从几天的时间缩短为几个小时,,,,运维人员也会从数十人降低到几个人,,这更适合我们的工作所需,,将繁重的运维管理工作剥离出来,,,,将工作重心集中的业务开发中。。。。

图7 CM管理控制台
CM集群管理的四大核心功能:
管理:对集群进行管理,,,,如添加、、删除节点等操作。。
1) 批量自动化部署节点:CM为我们提供了强大的集群管理能力,,能够批量自动化部署节点。。。安装一个Hadoop集群只需要添加安装的节点,,安装需要的组件和角色这三大步,,,,大大缩短了Hadoop的安装时间,,也简化了Hadoop的安装过程。。
2) 可视化的参数配置功能:Hadoop包含许多组件,,,,不同组件都包含各种各样的XML配置文件,,,,使用CM,,,我们就可以在GUI界面可视化配置参数。。
3) 智能参数验证及优化:当我们的配置部分参数值有问题时,,,CM会给出智能提示信息,,帮助我们更合理的修改配置参数。。。
4) 高可用配置:使用CM,,我们可以对关键组件进行HA部署,,,如CM的Web管理控制台可以对HDFS NameNode启用HA功能。。。
5) 权限管理:根据CM的权限控制级别,,我们可以配置不同的用户,,,如有的用户只有访问CM的权限,,,,但无对服务启停操作的权限。。。。
监控:监控集群的健康情况,,,对设置的各种指标和系统运行情况进行全面监控。。。
1) 服务监控:查看服务和实例级别健康检查的结果,,,,对设置的各种指标和系统运行情况进行全面监控。。如果任何运行情况测试是不良(Bad),,,则服务或者角色的状态就是不良(Bad)。。如果运行状态存在隐患(Concering,,没有任意一项目是不良),,,则服务或角色的状况就是隐患(Concerning)。。而且系统会对管理员应该采取的行动提出建议。。
2) 主机监控:监控集群内所有主机的有关信息,,,,包括主机目前消耗到内存,,主机上运行的角色分配等,,,,不但显示所有集群主机的汇总视图,,而且能够进一步显示单个主机关键指标详细视图。。。。
3) 行为监控:根据CM提供的列表或图表来看查看集群上进行的活动,,不仅显示当前正在执行的任务行为,,还可以通过仪表盘查看历史活动。。。。
4) 事件活动:根据CM监控界面,,,,我们可以查看事件,,,,可以通过时间范围、、、、服务、、主机、、、、关键字等信息过滤事件。。
5) 报警:通过配置CM可以对指定的时间产生警报,,,并通过电子邮件或者SNMP的事件得到制定的警报通知。。。
6) 日志和报告:轻松点击一个链接查看相关的特定服务的日志条目,,,,并且CM为我们生成了收集的历史日志监控数据统计报表。。。。
诊断:对集群出现的问题进行诊断,,,,对出现的问题给出建议方案。。。。
1) 周期性服务诊断:CM会对集群中运行的所有服务进行周期性的运行状况测试,,,,以检测这些服务的状态知否正常。。如果有异常,,就会进行告警,,,有利于更早的让我们感知集群服务存在的问题。。。
2) 日志采集及检索:对于一个大规模的集群,,,,CM为我们提供了日志收集功能,,,,能够通过统一的界面查看集群中每台及其各项服务的日志,,,并且能够根据日志级别等不同的条件进行检索。。。
3) 系统性能使用报告:根据CM,,,,我们能够查看系统性能使用报告,,,,包括集群的CPU使用率,,单节点的CPU使用率,,,,单个进程的CPU使用率等各项性能,,,,这对于我们调试Hadoop集群的性能是很重要的。。。
集成:对Hadoop的多组件进行整合。。。。
1) 生态圈各组件集成:企业级大数据平台就是有这样的好处,,,,其集成了整个Hadoop生态圈的各项组件。。。根据CM控制台,,,我们可以轻松的部署各项服务,,,,各项服务都默认了最优的配置,,,我们只需根据情况适当调整即可。。包括ZooKeeper、、HDFS、、、YARN、、、SQOOP、、、、Flume、、、、Kafka、、、Hive、、、HBase、、、、Impla、、Oozie、、、Hue、、Spark等都可以实现可视化安装,,无需配置。。
2) 安全配置:为了方便Hadoop大数据平台与原有的身份认证系统如AD、、、、LDAP等的集成,,,,CM只需在界面上配置即可。。。。
3) Cloudera Manager API:通过Cloudera Manager API,,能够方便的将CM集成到企业原有管理系统中。。
3.2 平台运行
存储扩展
对于传统的关系型数据库来说,,,当存储空间不足时,,最好的办法就是增加磁盘,,,随着数据量不断增长,,,不可避免的会遇到性能瓶颈,,因为庞大的数据量导致每次查询寻址时间过长,,,,造成业务系统请求阻塞,,,严重制约了关系型数据库的使用范围。。这种只增加存储不增加计算能力的办法只可解决当下的问题,,,却无法面对长远的隐患问题。。。。
对于CDH来说,,,,存储扩展将变得非常容易。。当存储不够或者计算压力过重时,,我们可以适当的增加机器来提升系统性能,,,,只要配置正确,,,新节点能非常兼容的加入集群中。。。。这种即增加存储也提升计算能力的办法无论面对多大的数据量都不会是问题。。。

图8 CDH集群扩容
CDH的集群扩容非常简单,,,在CDH中,,我们只在待添加的节点中做好基础配置(网络、、域名、、、Selinux、、、文件打开的最大数量、、、数据盘挂载)即可,,,添加节点的操作均在CM控制台操作。。。添加节点时,,,输入IP或者域名搜索,,然后选定在新添加的节点中要配置的服务和角色即可,,,其余的均有CM自动执行。。。
添加服务
CM是控制台,,,其集成的各项服务才是CDH的核心。。。。在原生的Hadoop中,,,,添加服务是一件非常繁琐的事情。。。。首先在管理节点中将要添加的服务配置好(XML);然后分发到所有的节点中;最后在各个节点中分别启动;以上所有的服务均是在命令行操作。。。而在CDH中,,,CM的Web页面提供了一键添加服务甚至批量添加服务功能,,,,所有的服务均由CM做了默认的配置(XML),,,只需根据自身情况做调整即可。。。。

图9 CDH添加服务
高可用性
为保证系统24小时不间断提供服务,,,,我们需要针对关键角色做故障自动转移配置,,,,即HA配置。。。。比如HDFS NameNode、、、、YARN ResourceManager、、HBase Master等关键的性的角色为了避免点单故障,,,,需要对这些角色额外单独(不同节点上)配置一个同样的服务(备用),,,,当发生故障时,,,备用服务自动启动,,,,做到无缝切换。。

图10 HDFS NameNode高可用配置
在原生的Hadoop中,,,,如果要做HA配置,,,,我们要做大量的手动操作:选择节点、、、同步配置文件、、启用HA、、同步元数据、、、、共享元数据、、、、全部重启服务等。。。。而在CDH中,,,我们只需在控制台中点击“启用High Availability”,,选中HA节点,,,剩余的都交由CM去执行。。。。
负荷分担
面对过于沉重的荷载,,,对于Oracle来说,,,我们惯用的方法是分库分表分区等;对于Hive表来说,,,,也存在着分区分桶等方法来避免全表扫描。。。对于HBase来说,,,,为了更好的提升性能,,,用拆分Region的方式来提升查询速度。。。

图11 HBase的拆分Region
HBase拆分Region有别于其他数据库,,HBase表的所有数据都按照RowKey排序,,并且按照RowKey拆分Region,,,每个Region中包含一定范围的数据(Start Key – End Key),,每个Region中的数据又按照RowKey排序。。
高可靠性
为保证系统的可靠性,,我们配置冗余的数据备份,,不同备份将不同磁盘、、不同节点、、、、不同机架分别存放。。。。这样部分节点宕机,,,,或者某个磁盘损坏,,甚至某台节点宕机导致部分备份丢失,,,,我们都不必当心数据安全问题。。。。此外,,,,按照HDFS的Heart Beat机制,,系统还会监控数据备份,,一旦有备份丢失,,,,系统将会自动复制新的一份到其余节点中。。。。

图12 HDFS的数据备份策略
在CDH中,,数据备份策略在CM控制台中即可配置,,无需在命令行去操作。。
低故障率
对于Hadoop来说,,,硬件故障是常态,,为了避免硬件故障导致系统出现奔溃的情况,,,我们需要在内存、、、、磁盘等方面做一些调整:
内存:在Hadoop中有些角色是需要内存资源用来存储关键信息的,,,,如HDFS NameNode元数据、、HBase BlockCache等;因此给这些角色适当增加内存是有助于提升系统性能的。。。。
磁盘:系统盘和数据盘独立创建,,系统盘做冗余磁盘阵列RAID1。。。
3.3 读写请求
根据业务场景,,,,我们所有的业务数据(结构化和非结构化)都存储在HBase中,,,因此对CDH的读写请求更主要针对HBase的读写请求。。提升HBase的读写请求效率是电子档案系统最核心的需求,,因此HBase的优化工作是我们工作的重中之重。。。适当调高HBase内存、、调整垃圾回收策略、、、更改默认的Region大小、、、、选择合适的小文件合并时机和拆分Region时机、、启用Snappy压缩、、预创建Region、、、避免Region热点等等都可以提高HBase的存取速度。。。
调整HBase内存
这里首先涉及HBase服务的堆内存设置。。。。一般刚部署的HBase集群,,,默认配置只给Master和RegionServer分配了1G的内存,,RegionServer中MemStore默认占40%即400M左右的空间,,而一个MemStore刷写阈值默认为128M,,,所以一个RegionServer也就能正常管理3个Region,,,,多了就可能产生小文件了,,,,另外也容易发生Full GC。。。因此建议合理调整Master和RegionServer的内存,,比如:

其次要考虑开启BlockCache,,,,首先,,,,BlockCache是RegionServer级别的,,一个RegionServer只有一个BlockCache。。。BlockCache的工作原理是读请求会首先检查Block是否存在于BlockCache,,,,存在就直接返回,,如果不存在再去HFile和MemStore中获取,,,,返回数据时把Block缓存到BlockCache中,,,后续同一请求或临近查询可以直接从BlockCache中读取,,,避免过多昂贵的IO操作。。。
调整垃圾回收策略
1) G1收集器VS CMS收集器
CMS收集器在物理上区分年轻代和年老代空间。。。G1收集器会将heap分成很多region,,,,然后在逻辑区分年轻代和年老代空间。。。G1收集器主要用于控制垃圾回收的时间。。。。对于HBase使用场景,,,大部分年老代的对象是memsotre或者blockcache。。。。对比测试发现,,CMS收集器有更好的表现。。。
2) CMS配置调优
设置较大的heap size。。使用CMSInitiatingOccupancyFraction=70,,,值为70为JVM的使用百分比,,,,当达到这个阈值后将启动回收任务,,,这个值比较适合的值是要略大约memstore 40%+blockcache 20%。。。如果CMSInitiatingOccupancyFraction这个值小于60会导致GC报警。。。
3) 新生代收集器UseParNewGC
使用UseParNewGC收集器,,,,并加大新生代空间大小占heap size 25%,,,因为memstore(40%)+blockcache(20%)占总heap(60%),,,,这两部分空间会被存放在年老年空间。。。。所以新生代空间不应该大小1-60%,,,让更多的GC发生在新生代,,UseParNewGC可以并行收集,,,,收集成本低。。。
4) TargetSurvivorRatio设置
TargetSurvivorRatio=90设置Survivor区的可使用率。。这里设置为90%,,则允许90%的Survivor空间被使用。。默认值为50%,,故该值设置提高了Survivor区的使用率。。但存放的对象超过这个百分比,,,,则对象会向年老代压缩。。。。因此,,,这个选项更有助于将对象留在年老代。。
选择合适的Region数量
通常较少的region数量可使群集运行的更加平稳,,官方指出每个RegionServer大约100个regions的时候效果最好,,,理由如下:
1) HBase的一个特性MSLAB,,,,它有助于防止堆内存的碎片化,,减轻垃圾回收Full GC的问题,,默认是开启的。。。。但是每个MemStore需要2MB(一个列簇对应一个写缓存memstore)。。。所以如果每个region有2个family列簇,,,总有1000个region,,,,就算不存储数据也要3.95G内存空间。。。。
2) 如果很多region,,,它们中Memstore也过多,,,内存大小触发Region Server级别限制导致flush,,,就会对用户请求产生较大的影响,,,,可能阻塞该Region Server上的更新操作。。
3) HMaster要花大量的时间来分配和移动Region,,且过多Region会增加ZooKeeper的负担。。。
4) 从HBase读入数据进行处理的mapreduce程序,,,,过多Region会产生太多Map任务数量,,,默认情况下由涉及的region数量决定。。。。
所以,,,,如果一个HRegion中Memstore过多,,而且大部分都频繁写入数据,,每次flush的开销必然会很大,,,,因此我们也建议在进行表设计的时候尽量减少ColumnFamily的个数。。每个region都有自己的MemStore,,,当大小达到了上限(hbase.hregion.memstore.flush.size,,默认128MB),,会触发Memstore刷新。。
计算集群region数量的公式:((RS Xmx) * hbase.regionserver.global.memstore.size) / (hbase.hregion.memstore.flush.size * (# column families))
假设一个RS有16GB内存,,,那么16384*0.4/128m 等于51个活跃的region。。
如果写很重的场景下,,,可以适当调高hbase.regionserver.global.memstore.size,,这样可以容纳更多的region数量。。
建议分配合理的region数量,,,根据写请求量的情况,,一般20-200个之间,,,,可以提高集群稳定性,,排除很多不确定的因素,,,提升读写性能。。。。监控Region Server中所有Memstore的大小总和是否达到了上限(hbase.regionserver.global.memstore.upperLimit * hbase_heapsize,,,,默认 40%的JVM内存使用量),,超过可能会导致不良后果,,如服务器反应迟钝或compact风暴。。。
更改默认的Region大小
HBase中数据一开始会写入memstore,,,,满128MB(看配置)以后,,会flush到disk上而成为storefile。。。当storefile数量超过触发因子时(可配置),,,会启动compaction过程将它们合并为一个storefile。。对集群的性能有一定影响。。而当合并后的storefile大于max.filesize,,,会触发分割动作,,将它切分成两个region。。
1) 当hbase.hregion.max.filesize比较小时,,,,触发split的机率更大,,,,系统的整体访问服务会出现不稳定现象。。
2) 当hbase.hregion.max.filesize比较大时,,由于长期得不到split,,因此同一个region内发生多次compaction的机会增加了。。这样会降低系统的性能、、、稳定性,,,因此平均吞吐量会受到一些影响而下降。。。
3) hbase.hregion.max.filesize不宜过大或过小,,经过实战,,,,生产高并发运行下,,,,最佳大小5-10GB!!!关闭某些重要场景的HBase表的major_compact!!!!在非高峰期的时候再去调用major_compact,,,这样可以减少split的同时,,,,显著提供集群的性能,,,吞吐量、、非常有用。。。
HFile文件是否太多
文件越多,,,检索所需的IO次数必然越多,,,读取延迟也就越高。。文件数量通常取决于Compaction的执行策略,,,一般和两个参数有关:
hbase.hstore.compactionThreshold和hbase.hstore.compaction.max.size,,,,前者表示一个store中的文件数超过多少个就应该合并,,,后者表示参数合并的文件大小最大是多少,,,,超过此大小的文件不能参与合并。。
hbase.hstore.compactionThreshold设置不能太大,,,默认是3个;设置需要根据Region的大小,,,通常可以认为是
hbase.hstore.compaction.max.size=RegionSize/hbase.hstore.compactionThreshold。。
选择合适的小文件合并策略
Compaction是将小文件合并为大文件,,,提高后续业务随机读性能,,但是也会带来IO放大以及带宽消耗问题,,问题主要产生于配置不合理导致Minor Compaction太过频繁,,,,或者Region设置太大情况下发生Major Compaction。。。
观察系统IO资源以及带宽资源使用情况,,再观察Compaction队列长度,,,,确认是否由于Compaction导致系统资源消耗过多。。。。
Minor Compaction设置:hbase.hstore.compactionThreshold设置不能太大,,,,也不能太小,,,因此建议设置为5~6;
hbase.hstore.compaction.max.size=RegionSzie/hbase.hstore.compactionThreshold。。。。
Major Compaction设置:大Region读延迟敏感业务(100G以上)通常不建议开启自动Major Compaction,,,手动低峰触发。。小Region或延迟不敏感业务也可以开启自动Major Compaction,,,但建议限制流量。。
Region拆分策略
Region为什么要拆分????随着数据的增加,,一个Region管理的数据条数越来越多,,,,出现传统SQL数据库的单节点并发问题,,将Region拆分,,,,将Region移动均衡到其他节点。。
Region拆分有三种方式:预拆分、、、自动拆分、、、、手动强制拆分
1) 预拆分:指定每个预拆分的Region的RowKey的开始值
create 'test_table', 'table_spilt_test1', SPLITS=> ['1001', '2001', '3001']
2) 自动拆分
Region的默认大小问10G,,,,超过10G就自动拆分,,Region大小通过下面这个参数控制,,,生产环境如果预分区后,,,,每个Region数据都比较大可改成20G 30G:
hbase.hregion.max.filesize
3) 强制拆分
可在HBase shell根据提示,,对某个Region进行强制拆分:

也可以调用HBase JAVA API来操作。。。。
启用Snappy压缩
启用压缩可以大大提高集群的可用性,,scan性能显著提升。。。目前HBase默认支持的压缩包括GZ、、、LZO以及Snappy,,,测试对比之后选择Snappy压缩算法。。。
表3 不同压缩算法测试性能比较

create ‘test’,{NAME => ‘info’,VERSIONS => 1,COMPRESSION => ‘snappy’}
预创建Region
HBase中的预分区就是在创建表之前,,,指定好RowKey在哪个范围的数据会落到哪个分区中,,,,因为HBase会按照字典顺序把RowKey进行排序。。。预分区的好处是一方面可以提高读写效率,,,二是防止数据倾斜,,,,起到负载均衡的作用。。。
创建表格时指定分区边界:
create ‘staff’,’info’,’partition’,SPLITS = > [‘1000’,’2000’,’3000’,’4000’]
使用16进制算法生成预分区
ceate ‘staff’,’info’,’partiton’,{COLUMNS = > 15,SPLITALGO => ‘’HexStringSplit’}
避免Region热点
检索HBase的记录首先要通过RowKey来定位数据,,,,当大量的Client方位HBase集群的一个或者几个Region,,,,会造成少数RegionServer的读写请求过多、、、、负载过大,,而其他RegionServer负载却很小,,,就造成了“热点”现象。。
常见的避免热点的方法:
1) 加盐:这里的加盐不是密码学中的加盐,,而是在RowKey的前面增加随机数,,,,具体就是给RowKey分配一个随机前缀使得它和之前的RowKey的开头不同。。。。给多少个前缀,,这个数量应该和我们要分散数据到不同的Region数量一致。。。。
2) 哈希:哈希会使同一行永远用一个前缀加盐。。哈希也可以使负载分散到整个集群,,,,但是读却是可以预测的。。。使用确定的哈希可以让客户端重构完整的RowKey,,,,可以使用get操作准确获取某一个行数据。。
3) 反转:反转固定长度或者数字格式的RowKey。。这样可以使得RowKey中经常改变的部分(最没有意义的部分)放在
前面。。。这样可以有效的随机RowKey,,,但是牺牲了RowKey的有序性。。
4) RowKey唯一原则:必须在设计上保证其唯一性,,,,RowKey是按照二进制字节数据排序存储的,,,,因此设计RowKey的时候,,,,要充分利用这个排序的特点,,经常读的数据存储的一起,,将最近可能会被访问的数据放到一块。。
5) RowKey长度原则:RowKey是一个二进制码流,,可以是任意字符串,,,,最大长度64kb,,,实际应用中一般为10-100byte,,以byte[]形式保存,,一般设计成定长度,,,建议越短越好,,,,不要超过16个字节(因为RowKey是要加载到内存中的)。。。。
6) RowKey散列原则:如果RowKey按照时间戳的方式递增,,,不要将时间放到二进制码的前面,,,建议将RowKey高位作为三列字段,,由程序随机生成,,,低位放时间字段,,这样将提高数据均衡分布在每个Region上,,,,以实现负载均衡的几率。。。。
Swap的设置
推荐设置为0,,,,这样只有在物理内存不够的情况下才会使用交换分区。。。。这个参数由于JVM虚拟机如果使用了Swap在GC回收时会花费更多到时间。。。
3.4 数据迁移
SQOOP数据导入
使用SQOOP执行数据迁移的目的是需要将Oracle中的结构化数据(ID)迁移到Hive中,,,然后在Hive中计算要预分Region的RowKey值:

预分Region的RowKey(start key和end key)计算
##创建临时表并分区分桶,,,,目的是为了更快的计算

MR接口编程
Oracle到HBase表之间的数据转移以MapReduce分布式计算框架执行:
1) Mapper:

2) Reduce:

3) 主程序入口:


4.
质变与总结
在数据存储方面:电子档案系统不用再承受Oracle频繁增加磁盘和数据量猛增的情况下带来的痛苦,,,即使再大的数据量,,,对于分布式集群来说,,都是添加节点的事情。。。。即使在廉价的商用机器上,,,,大数据平台都能得到很好的部署,,让数据存储不再是个问题。。。
在读写速度方面:因为HBase的特性,,,返回同样的数据HBase比Oracle有着更低的延迟、、更高的效率。。。。
在运行状态方面:因为分布式集群不存在单点故障问题,,,系统稳定方面有了很大的保证,,可确保24小时不间断提供服务。。。
在用户体验方面:随着请求速度的提升,,,,用户不用再长时间的等待数据库请求结果,,极大的提高了用户工作效率。。。。

