HBASE修炼之路——00008(HBase之探索优化方案)

1、Hbase_master_heapsize
令许多人惊讶的是,Hbase Master没有做任何繁重的工作,因此常规情况下Hbase_master_heapsize的值不超过4-8 GB。Master通常负责元数据的操作,例如创建/删除表,可以使用zookeeper znodes持续观察 regionserver的健康状况,当regionserver 宕机时会重新分配regions。 请注意,master的调度管理器仅此在内存中追踪region的状态,如果集群有大量的表/regions ,需要为master提供相应数量的堆内存。
2、hbase_regionserver_heapsize
这是regionserver的一个非常关键的参数,因为大多数的数据加载/处理都会在regionserver的堆内存中发生。 堆内存中包含块缓存可以使读取更快,堆内存保存着用户所有写入的 region memstores(直到它们被刷写到磁盘上)。 但是堆内存大小的最佳值是多少? 我们如何计算这个值? 对此并没有直接的公式,如果我们使用CMS GC算法,堆内存硬停止值大约是36-38 GB,否则长时间“stop the world”的GC暂停不仅会使Hbase无法使用而且加大数据储存的复杂性。 根据当前托管的regions 数量,16 GB - 36 GB之间的值都是可以的,而且,需要有一个适当的计划,根据群集的容量以及节点中regions数量的增加,适度调整堆内存的大小。 使用G1 GC算法时,对于堆内存的大小则没有限制。
可以通过Ambari> Hbase> Master UI> Memory选项卡观察堆内存的使用情况,
如果高峰时段堆内存利用率占到60-70%,则可以适度增加堆内存的大小。 (除非发生内存泄漏)。
3、hbase_regionsever_xmn_max
该参数设置regionsever 堆内存中年轻代的大小, 根据经验需设置为堆内存的1/10 - 1/8,永远不要超过4000 Mb。
4、每台regionserver 服务器的region 个数
讨论这个值,是因为可以帮助我们找出regionser的最佳堆内存和最佳memstore的大小,同时向我们解释这些参数都依赖于region的数量,hbase的性能也依赖于这些参数的值。 单台regionserver服务器不建议超过200-400个region。 可以使用下面的公式计算出群集中的现有值是否为最优值:
(regionserver_memory_size)(memstore_fraction)/((memstore_size)(num_column_families))
例如,假设:
 一台有16 Gb 内存(16384 Mb)的regionserver 服务器,Memstore比例为0.4,Memstore大小是128 Mb ,数据表中有1个列族
此配置的公式如下所示:
(16384 Mb * 0.4)/((128 Mb * 1)=约51个区域
5、file.block.cache.size
块缓存是堆内存的一部分,使用块缓存可以使读取更快。 当磁盘的数据被加载到缓存中,下次访问相同的数据时,从缓存中读取的速度更快。 这里需要注意的是,只有在以下情况下才有效:
a.有一个很庞大的读请求。
b.有大量读取请求的情况下,用户会发出读取相同数据的请求。
如果两个条件都不匹配,将浪费大量的堆内存加载不必要的数据块。 在匹配条件下,命中率在20-40%之间是一个很好的结果。同样,需要使用试错法调整到最合适的值。
6、hbase.regionserver.global.memstore.size
这个值是堆内存的一部分,代表打开每个表,每个region的每个列族的memstore内存。 这是写入操作发生编辑和突变的地方。对于大量的写入请求,20-40%之间的占比都是比较合适的。 还要注意,如上面第4点所述,块缓存的总和和全局memstore大小不应该大于堆内存总量的70-75%,这样我们就有足够的堆可用于除了读写缓存之外的常规hbase操作。
7、hbase.hregion.memstore.flush.size
这个值是单个列族打开的每个memstore的大小,在写操作期间,当memstore被占满的时候,会以hfile的形式刷写到磁盘。注意,当某一个region的其中一个memstore满了,这个region的所有memstore都会被刷写到磁盘上。 每次刷写都会创建一个hfile,因此这个数字越小,刷新频率越高,IO开销越多,创建Hfiles的次数越多,Hfiles的数量越多,触发的压缩越快。 压缩会触发额外的一轮写操作,因为它将较小的Hfiles写入更大的Hfile,所以如果非常频繁地触发刷写,对于服务器IO将会是很大的开销。
因此,一个比较大的刷写值会减少Hfiles的数量和压缩的次数,当然需要综合考虑每个regionserver的堆内存大小、region个数、列族的数量。 如果有太多的region和列族,就无法承受在有限的堆内存下配置更大的刷写值。 刷写值的理想范围在128 MB到256 MB之间。
8、hbase.hregion.memstore.block.multiplier
这是一个的调节参数,允许单个memstore在突发的大量写入期间进行拉伸。 拉伸到(flush.size X multiplier)的大小后,在该列族上写入操作将会被停止,直到刷写完成为止。
9、hbase.regionserver.handle.count
此参数定义处理传入请求的RPC侦听器/线程数量。 默认值为30。如果有更多的并发请求访问Hbase,这个值会更高,但是该值应该与每个regionserver上的CPU核数和堆内存大小成比例,因为每个线程都会消耗一部分内存和CPU。
根据经验,每个请求的有效负载较大时,这个值可以设置的小一点,单个请求的有效负载较小时,这个值可以设置的大一点。 可以把初始值设置成该节点上CPU核数的两倍,后续根据需求进行增减。

10、hbase.hstore.blockingStoreFiles
该参数的默认值是10.每个memstore 刷写时会创建一个Hfile(hbase.hregion.memstore.flush.size),参数的目的是沿着写入管道发送一条消息,除非这些Hfiles正在进行minor compaction,就不再刷写。 日志中显示这些消息,例如“ Too many HFiles,delaying flush ”。 然后就会延迟刷新几秒,如果还在持续写入,memstore就会扩展到以下参数的大小:
(hbase.hregion.memstore.flush.size X hbase.hregion.memstore.block.multiplier)
达到这个限制后,在region-server 上的这个region就不再写入了,这时会看到如下消息出现在日志中“ org.apache.hadoop.hbase.RegionTooBusyException:Above memstore limit”
当minor compaction结束后,写入才会恢复。
一直增加此参数可以避免在发生大流量写入时出现任何潜在的问题,并且反过来可以使通道更有效率。
为了进一步提高效率,还可以增加hbase.hstore.compaction.max的值,以便在压缩过程中涵盖更多的Hfiles。

11、hbase.hstore.compaction.max(maximum files for compaction)
默认值为10。在写负载较重的情况下,可以增大该值,使minor compaction覆盖更多Hfiles,并协助恢复写入功能。 请注意,minor compaction本身也有自己的IO开销,在提高该值的时候需要记住这一点。

12、hbase.hregion.max.filesize (50GB)
默认值为10 GB。 可以用来控制Hbase中region的分裂比例。 一旦region内的任何store(列族)达到该大小,region就会被拆分。
禁用虚拟分割(To disable splitting virtually),设置为非常大的数字,如(100 GB)并将拆分策略设置为:
hbase.regionserver.region.split.policy = org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy

会话超时相关参数:

13、zookeeper.session.timeout
默认值为90秒。 regionserver与zookeeper保持一个会话以确定处于活动状态,每个regionserver在zookeeper中都有自己的临时znode。 一旦会话因任何原因断开连接或超时,znode就会被删除,并且regionserver机会宕机。 zookeeper.session.timeout是“部分地”指示在启动regionserver与zookeeper服务器协商会话超时。 为什么是“部分”? 这是因为zookeeper服务器本身具有为其客户端定义的最小和最大会话超时时间,如下面的公式:
最小会话超时时间:2 X tick time
最大会话超时时间:20 x tick time
无论客户端配置中设置了多长时间的会话超时,如果zookeeper服务器超时时间小于该值,zookeeper只认为这两者中的最小值有效。 例如,zookeeper配置中的默认tick time是2s,这意味着最大会话超时不能大于40s,即使Hbase将其超时设置为90s,真正有效的值仅为40s。 想增加hbase中的会话超时,以便regionserver能够容忍更长时间的GC暂停、网络、hbase、zookeeper等任何其他问题引起的波动,可以考虑增加“tick time”。不建议超过4 - 5秒,可能会影响zookeeper quorum(zk 裁判员)的健康状况。

14、hbase.rpc.timeout
默认值为300000ms。 这是客户端向Hbase发出RPC调用请求获取超时的时间。 按比例将其设置为 客户端连接/作业连接/查询连接 需要的值。 但是,不要设置太大,否则客户端会在很长一段时间后才汇报失败。 当我们谈论hbase.rpc.timeout时,我们会讨论另外两个参数。

15、hbase.client.scanner.timeout.period
默认值为300000 ms。任何hbase客户端 scan程序在hbase表上执行scan的时间。 它取代了之前名为“hbase.regionserver.lease.period”的参数。 这里的区别在于,此超时专门用于来自HBase Scanner类的RPC(例如ClientScanner),而hbase.rpc.timeout是任何RPC调用的默认超时。
请注意hbase.regionserver.lease.period参数现在已弃用,此参数将替换它。
一般来说保持hbase.rpc.timeout等于或大于hbase.client.scanner.timeout.period,因为如果 scan程序在运行时,超过hbase.rpc.timeout的阈值,客户端的会话就会超时。可能会导致异常,如“ScannerTimeoutException or UnknownScannerException”。

16、hbase.client.scanner.caching
默认值为100行。 这是客户端scan程序在一轮中(在“scanner.next”可能触发之前)从Hbase中提取的行数,然后传输回客户端。 如果您将此值设置为非常高的数字,则可能会出现多个性能问题(扫描程序超时也会发生),因为scan程序负责获取这些行数据并将它们传输回客户端,现在假设regionserver或底层HDFS或客户端和服务器之间的网络因某些原因都很慢,然后它很可能导致RPC会话过期,最终导致作业失败,当hbase尝试将行数据发回给会话已经过期的客户端时,会看到“ClosedChannel Exception”等错误信息。
保持较小的数量会使集群和scan程序无法使用,而较大的数量会大量消耗regionserver 堆内存和客户端内存等资源。 因此,一个合适的值取决于集群节点上拥有的 磁盘/内存/ CPU等资源以及需要扫描的行数。

17、Locality
本地化指的是响应请求的region的Hfiles与相关的HDFS块在同一台regionserver服务器上。 这里位置很重要,因为Hbase更喜欢绕过HDFS直接从物理磁盘使用短路读取(short circuit reads)。如果某个region的Hfiles不是本地的,通过网络上的节点读取时会导致读取延迟。
在Hbase Master UI监控界面,通过点击表名,可以查看 table/region的本地化比例,“1”表示本地化比例100%。总体Hbase本地化比例在Ambari的HBASE组件界面是可见的(百分比)。
Major compaction 会尝试在单个regionserver上恢复与region相关的所有Hfiles,从而在很大程度上恢复本地化。
由于HDFS balance的目的是平衡各数据节点的磁盘空间,而Hbase balance的目的通过移动region来平衡每台regionserver的region数量,因此本地化通常会出现混乱。
Hbase balance(默认为随机负载均衡器)可以通过调整相关参数的权重【costs】(region负载,table负载,数据本地化比例,MemStore大小,store file大小)进行调整,让其根据我们的需要运行,例如,hbase balance 人为Locality的权重是最高的,可以在hbase配置中添加以下参数并赋予它更高的值。
hbase.master.balancer.stochastic.localityCost (默认值为25)。(添加前需谨慎)
为了克服HDFS balance 对hbase 本地化的影响,除了在运行HDFS balance以后立即进行compaction 之外,没有其他解决方案。

18、Hotspotting
region热点是性能问题上需要调查的一个非常关键的点。 当所有写入流量仅在特定的regionserver上进行时,通常会出现热点问题。 可能是因为行键是按照“自然增长”的顺序设计,并且所有写入都落在了具有该region热点的节点上。
我们可以用三种方式解决这个问题:

  1. 使用随机密钥 - 不是很理想的解决方案,因为它对使用 start key和end key的scan没有帮助
    2.加盐(Salt buckets)- 如果在hbase表的顶部有Phoenix表,请使用此功能。
    3.使用预分割 - 如果知道顺序键的开始和结束键,则可以通过在创建时预先提供分割关键点来预分割table。 这将在节点之间分配空白 region,并且每当写入特定密钥时,它将落在相应节点上,最终在节点之间分配写入流量。

19、HDFS
HDFS层是非常重要的一层,不管Hbase层面如何优化,如果数据节点没有按预期响应,就无法获得预期的性能。 只要发现Hbase / Phoenix查询有延迟,并且在regionserver日志中观察到大量的以下消息:
2018-03-29 13:49:20,903 INFO [regionserver/example.com/10.9.2.35:16020] wal.FSHLog:Slow sync cost:18546 ms,current pepeline:[xyz]
或者 在查询运行时跟踪datanodes日志中的消息:
2018-04-12 08:22:51,910 WARN datanode.DataNode(BlockReceiver.java:receivePacket(571)) - Slow BlockReceiver write packet to mirror took 34548ms(threshold = 300ms)
或者看到
2018-04-12 09:20:57,423 WARN datanode.DataNode(BlockReceiver.java:receivePacket(703)) - Slow BlockReceiver write data to disk cost:3440 ms(threshold = 300ms)
如果在日志中看到这样的消息,是时候调查HDFS层面的内容,比如datanode是否有足够的传输线程,堆内存,文件描述符(file descriptors),进一步检查日志以查看是否有GC或非GC暂停等。一旦确认问题在HDFS层面,还必须考虑底层基础设施的情况(网络,磁盘,操作系统)。 因为这些消息主要表明HDFS难以 从/向 另一个节点 接收/传输 数据块或难以将数据同步到磁盘。

20、BlockCache Utilization 和 hitRatio
在调查读取数据的性能问题时,需要检查Block Cache和Bucket Cache有多大的用处以及它们是否被利用。
2017-06-12 19:01:48,453 INFO [LruBlockCacheStatsExecutor] hfile.LruBlockCache:totalSize = 33.67 MB,freeSize = 31.33 GB,max = 31.36 GB,blockCount = 7,accessses = 4626646,hits = 4626646,hitRatio = 100.00%, ,cachingAccesses = 4625995,cachingHits = 4625995,cachingHitsRatio = 100.00%,evictions = 24749,evicted = 662,evictedPerRun = 0.026748554781079292

2017-06-12 19:02:07,429 INFO [BucketCacheStatsExecutor] bucket.BucketCache:failedBlockAdditions = 0,totalSize = 46.00 GB,freeSize = 45.90 GB,usedSize = 106.77 MB,cacheSize = 93.21 MB,accessses = 9018587,hits = 4350242, IOhitsPerSecond = 2,IOTimePerHit = 0.03,hitRatio = 48.24%,cachingAccesses = 4354489,cachingHits = 4350242,cachingHitsRatio = 99.90%,evictions = 0,evicted = 234,evictedPerRun = Infinity

21、Flush Queue / Compaction queue 刷新队列/压缩队列
在面对严重的写入延迟的紧要关头,检查memstore刷新队列和压缩队列是非常重要的。 在这里讨论几个场景和一些可能的补救措施(需要专家咨询)
A.flush队列不减少:有三种可能性:
A.1由于某种原因,flush被暂停了,其中一个原因可能是regionserver日志中某处出现的“ too many store files”(由hbase.hstore.blockingStoreFiles指定 )。 查看第2部分文章,了解更多信息。
简而言之,此参数暂时阻止刷新,直到在现有Hfiles上完成minor compaction。 在写入负载较高时增加这个数字应该有所帮助。
甚至可以通过为其分配更多线程来帮助进行minor compaction,以便更快地完成对这些文件的压缩:
hbase.regionserver.thread.compaction.small (默认值为1,我们可以将其调整为3)
A.2另一种可能性是刷写操作本身很慢并且无法应对写入流量导致刷新速度变慢。 通过使用以下命令分配更多的处理线程来帮助flush:
hbase.hstore.flusher.count (默认值为2,我们可以将其表示为4)
A.3还有另一种可能性,即“flush storm(冲洗风暴)”,当预先写入日志文件的数量达到阈值( hbase.regionserver.maxlogs )并且regionserver被强制触发所有的memstores进行刷写,直到WAL文件存档并创建了足够的空间来恢复写入操作。 会显示以下消息:
2017-09-23 17:43:49,356 INFO [regionserver // 10.22.100.5:16020.logRoller] wal.FSHLog:太多wals:logs = 35,maxlogs = 32; forcing flush of 20 regions(s):d4kjnfnkf34335666d03cb1f
这种情况可以通过提升下面的参数来控制:
hbase.regionserver.maxlogs (默认值为32,如果写入负载很重,该值可以加倍或扩大三倍)
B. 压缩队列增长 :compaction_queue = 0:30 - >(表示队列中有0个major compaction和30个 minor compaction)。 请注意,无论是minor compaction还是major compaction 都是系统上额外的IO开销,所以当试图通过更快地压缩或在一个压缩线程中容纳更多Hfiles来解决性能问题时,必须记住这是一把双刃剑。
尽管如此,可以增加以下参数来提高压缩效率:
minor compaction文件数量的下限
hbase.hstore.compactionThreshold ? Default3)
minor compaction文件数量的上限。
hbase.hstore.compaction.max (Default10)
处理minor compaction的线程数。
hbase.regionserver.thread.compaction.small (Default1)
处理主要压缩的线程数。
hbase.regionserver.thread.compaction.large (默认=> 1)

22、JVM metrics
各种性能问题都要深入研究JVM的问题,特别是与GC STW(stop the world)相关联,GC STW会导致应用程序/regionserver性能下降甚至有时会导致 宕机/崩溃。
长时间的GC暂停有几种可能性,这里无法都涉及。 可以通过许多在线工具对regionserver的gc.log文件进行分析,这些工具可以帮助分析JVM或GC中的报错。如果每个regionserver上有大量的region(500 +),可以考虑使用G1 GC算法,即使Hortonworks没有正式支持它,许多客户已成功实施。
提一下GC最基本规则:
1.使用CMS GC算法时,永远不要将regionserver的堆内存大于36 - 38 GB,如果有更多的需求,请切换到G1 GC。
2.年轻代不应该超过regionserver总堆内存的1/8或1/10。
3.为了减少GC暂停,可以先调整 -XX:ParallelGCThreads,默认情况下为8,可以将它设置为16(需对比CPU的内核数量)
4.查出谁是GC暂停的“user”或“sys”或“real”
a) 2017-10-11T14:06:17.492 + 0530:646872.162:[GC [1 CMS-initial-mark:17454832K(29458432K)] 20202988K(32871808K),74.6880980 secs] [Times:user= 37.61 sys = 1.96,real = 74.67 secs]
'real’时间是GC的总耗时。 基本上是你在时钟中看到的时间。
'user’时间是在用户模式(内核之外)花费的CPU时间。
'Sys’时间是内核中花费的CPU时间。 就是在内核中进行系统调用所花费的CPU时间。
在上面的场景中,“sys”时间非常小但“real”时间非常高,表明GC没有获得足够的CPU周期,CPU端的资源可能发生了严重的堵塞。

经常会看到另一类停顿:
2017-10-20 14:03:42,327 INFO [JvmPauseMonitor] util.JvmPauseMonitor:Detected pause in JVM or host machine(eg GC):pause of approximately 9056ms
No GCs detected
这类停顿表示JVM在没有任何GC事件的情况下被冻结了大约9秒。 这种情况主要表明是因为物理机的(内存、CPU或操作系统)的问题导致整个JVM暂时冻结。

23、DISKS
除了调查HBASE和HDFS层的潜在问题外,也不能忽视操作系统、网络和磁盘的问题。 我们每天都会看到几个案例,当时确定了这一层的严重问题。详细的调查超出了本文的范围,但我们应该知道问题在哪里。 查看系统端的触发因素是诸如在性能问题时在datanode日志中跟随的消息。
WARN datanode.DataNode(BlockReceiver.java:receivePacket(694)) - Slow BlockReceiver write data to disk cost:317ms(threshold= 300ms)

以下是一些确定磁盘性能测试:
运行dd test以检查读写吞吐量和延迟。
用于检查写入吞吐量:
dd bs=1M count=10000 if=/dev/zero of=/data01/test.img conv=fdatasync
用于检查读取吞吐量:
dd if=/data01/test.img of=/dev/null bs=1M count=10000
其中/ data是数据节点的磁盘之一。

为了在读取或写入期间检查延迟,在上述命令之前添加“time”命令,您将知道完成这些操作需要多长时间,以及实际延迟是来自客户端还是服务端。 将这些结果与您与存储供应商/云服务提供商商定的吞吐量进行比较。

另一个重要的工具是Linux“ iostat ”命令,它提供了大量的高级信息来诊断,例如IO调度程序队列中IO的请求时间,磁盘控制器队列,队列中等待的请求数,磁盘完成一次IO操作的时间等
这个命令可以很好地展示服务器的工作负载是否超出磁盘容量,或者磁盘是否在硬件或驱动程序/固件级别出现问题。
其中有些参数需要特别注意:
Await:涵盖通过调度程序,驱动程序,控制器,传输(例如光纤)和完成每个IO所需的存储所花费的时间。 Await是存储完成的I / O请求的平均时间(以毫秒为单位),包括调度程序队列中的请求所花费的时间以及存储服务所花费的时间。
avgqu-sz :IO调度程序队列和存储控制器队列中排队的IO的平均数。
Svctm :实际响应IO请求的服务时间 存储/磁盘 ,排除所有队列延迟。
Util :每个磁盘的利用率百分比。

一般会使用top / vmstat / mpstat等命令查看CPU /内存/交换分区 的情况。
查看在IO层发生的实时流式传输最重要的命令是是“ iotop ”。该命令提供有关哪个命令,进程和用户实际堵塞磁盘的实时详细信息。

一般的调整技巧 :
选择正确的IO调度程序对延迟敏感的工作负载非常重要。 “deadline”调度程序被证明是此类用例的最佳调度程序。用以下命令检查当前处理IO的调度程序:
[[email protected] hbase]# cat /sys/block/sd*/queue/scheduler
noop [deadline] cfq

为数据磁盘选择正确的挂载选项。 诸如“noatime”之类的选项可以在数据磁盘上节省大量IO开销,从而提高性能。

检查CPU内核运行的模式。我们建议它们以性能模式运行。 虚拟机和云实例可能没有此文件。

Echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

已经看到将大量累积的“脏页”刷新到磁盘上会导致系统上的大量IO开销。 请调整以下内核参数来控制此行为。 没有一个适合所有人的数字,试验和错误是这里最好的度假胜地,但是对于具有大量内存的系统,我们可以保持这个比率小于它们的默认值,这样我们就不会累积大量的内存中的脏页最终会突发同步到容量有限的磁盘并降低应用程序性能。
vm.dirty_background_ratio(默认为10)
vm.dirty_ratio(默认为40)

24、网络
跨HDP集群节点的网络带宽在重读/写用例中起着至关重要的作用。 它在分布式计算中变得更加重要,因为任何一个跛行节点都能够降低整个集群性能。 虽然我们已经处于千兆网络的世界中,但一般情况下这方面都很稳定。 但是我们继续看到这方面的问题,在datanode日志中看到的以下消息可能被证明是调查网络方面的触发因素:

  1. WARN datanode.DataNode(BlockReceiver.java:receivePacket(571)) - 慢速BlockReceiver写入数据包镜像耗时319ms(阈值= 300ms)

以下是我们可以用来查明这里是否有问题的一些工具/命令:

  • “ iperf ”测试节点之间的网络带宽。 在这里查看有关iperf的更多详细信息。
  • 使用ping / ifconfig和“ netstat -s ”等Linux命令查明是否存在任何重大数据包丢失/套接字缓冲区溢出,以及此数字是否随时间增加。
  • ethtool ethX命令可以帮助您提供协商的网络带宽。
  • ethtool -S将有助于收集NIC和驱动程序统计信息。
    一些一般的调整技巧:
  • 通常,任何类型的NIC级别接收加速都不能很好地适用于我们的用例,并且在大多数情况下反过来证明是性能瓶颈。 禁用NIC卡上启用的任何加速(当然,在咨询平台团队后):
  • 检查是否启用了接收卸载:
    $ grep’rece-offload’sos_commands / networking / ethtool_-k_eth0 | grep’:on’
    generic-receive-offload:on
    large-receive-offload:on
  • 使用以下命令禁用它们:
    #ethtool -K eth0 gro off
    #ethtool -K eth0 lro off
    Referenece
  • 确保网络中所有节点和交换机的MTU大小均匀。
  • 如上所述,如果您观察到数据包的一致性溢出/剪辑/折叠,则增加套接字缓冲区大小。 请咨询您的网络和平台团队,了解如何调整这些值。
    25、内核/记忆
    调优内核是您期望任何节点处理的工作负载性质的强制要求。 然而,已经看到在设计这种基础结构时经常忽略内核调整。 虽然它是一个非常广泛的主题,并且超出了本文的范围,但我将提到一些与内存管理相关的重要内核参数,这些参数必须在HDP集群节点上进行调整。 这些配置参数保留在/etc/sysctl.conf中
  • vm.min_free_kbytes :内核尝试确保系统上始终可以使用min_free_kbytes内存。 为实现这一目标,内核将回收内存。 保持此参数约为节点总内存的2 - 5%,可确保您的应用程序不会因主要内存碎片而受损。
    内存碎片的第一个症状是在/ var / log / messages或“dmesg”(内核环缓冲区)中出现诸如“ 页面分配失败 ”之类的消息,或者当内核开始通过“ OOM Killer杀死进程来释放内存时”。 ”。
  • vm.swappiness :这是反映系统交换趋势的参数。 默认值为60.我们不希望系统根据其意愿进行交换,因此请将此值保持在0到5左右,以使系统的交换趋势保持最小。
  • 已经看到透明的大页面不能很好地适应我们的工作量。 因此建议在我们的集群节点上禁用THP。
    echo never> / sys / kernel / mm / transparent_hugepage / enabled
    echo never> / sys / kernel / mm / transparent_hugepage / defrag
  • 在现代NUMA(此处关于NUMA )系统上,我们强烈建议禁用区域回收模式。 这是基于这样的理解:由于从区域内回收页面而导致的性能损失远远低于从另一个区域提供请求的页面。 通常强烈依赖于使用缓存的应用程序更喜欢禁用此参数。
    vm.zone_reclaim_mode = 0
    通过编辑/etc/sysctl.conf并运行sysctl -p命令使它们生效,可以在运行的系统上进行所有这些内核级别更改。
    在本系列文章的最后一部分( 第5部分 )中,我将详细讨论Phoenix性能调优。

26、在本系列的最后和第5部分中,对Phoenix性能参数进行讨论。

我正在举例说明一个表现非常慢的查询以及我们如何调查这种情况。 我们将从阅读此查询的解释计划开始。 我不能在这里引用确切的查询(客户的数据),但它是一个带有一些where子句的select查询,最后是按条件排序。 查询的解释计划如下:
.| CLIENT 5853-CHUNK 234762256 ROWS 1671023360974 BYTES PARALLEL 5853-WAY FULL SCAN OVER MESSAGE_LOGS.TEST_MESSAGE | | SERVER FILTER BY ((ROUTING IS NULL OR ROUTING = ‘TEST’) AND TESTNAME = ‘createTest’ AND TESTID = ’TEST’ AND ERRORCODE | | SERVER TOP 20 ROWS SORTED BY [CREATEDTIMESTAMP DESC, TESTID] | | CLIENT MERGE SORT |
首先,让我们学习剖析Phoenix查询的解释计划,以下是我对此计划的观察:

第一个声明

“CLIENT”,表示此声明应在客户端执行。
“5853-CHUNK”,这意味着查询计划在逻辑上将数据划分为大约5853个块。每个块都会使用一个单独的线程。因此,为了将来参考,请记住,一个块==客户端线程池的一个线程。
“234762256 ROWS”,表示此查询将处理这些行。自我解释。
“1671023360974 BYTES”,意味着将处理大约1.6 TB的数据。
“PARALLEL”,因此对这些5853块(5853-WAY)的查询处理将并行完成。
“FULL SCAN OVER MESSAGE_LOGS.TEST_MESSAGE”,这意味着它将扫描整个表,最低效的方式和Hbase / Phoenix用例的反模式。此表需要二级索引才能将此完整扫描转换为范围扫描。
第二个声明

“SERVER”,处理将在区域服务器中发生
“FILTER BY”仅返回与表达式匹配的结果
第三个声明

“SERVER”,在服务器端进行处理,特别是“SORTED BY”
第四声明

“CLIENT MERGE SORT”,意味着服务器端的所有SORTED ROWS将被带回客户端节点并再次合并排序。
进行了哪些调整以使查询运行得更快?

对于查询,5853块特别是对于具有默认值128的线程池而言显得过多,这使得整个查询变得更慢,因为一次只有128个线程可以工作并且所有任务都将在队列中等待。 (phoenix.query.queueSize)
我们决定将线程池(phoenix.query.threadPoolSize)从默认的128提升到大约1000,但客户端没有足够的CPU内核,如果我们超出这个数字,他担心CPU争用,所以我们决定去另一个调整。
我们增加了路标宽度(phoenix.stats.guidepost.width),它们是以块为单位逻辑分布数据的标记。 (从默认的100 MB到500 MB)。这有效地减少了块的数量,从而减少了线程数量。
详细了解所有调整参数,包括上述参数。
为了使此查询更有效,建议客户在此数据表之上创建二级索引,并在其中包含最常用的列。在这里阅读更多关于二级索引
因此,在所有的变化到位之后,早先花费大约5分钟的查询现在花费大约15-20秒。
整体调整建议:

为了提高读取性能,创建全局二级索引,它将具有一些写入惩罚,因为索引的所选列的数据将被复制到另一个表。
为了提高写入性能,如果您知道键范围,则预分割表,还要考虑使用写在同一个表中并作为另一列添加的本地索引。使用HDP 3.0进行大量错误修复时,本地索引会更稳定。
选择最常用的主键列。由于所有这些列都连接在一起形成Hbase的“行键”,因此它们在行键中的出现顺序以及它的长度都很重要。订单很重要,因为如果最常用的列在行键中排在第一位,则范围扫描变得更有效。长度很重要,因为这个行键将是每个单元的一部分,因此会占用一些内存和一些磁盘。
如果您有一个单调递增的行键,请使用Salt Buckets。在这里阅读更多相关信息
请注意,Salting会产生读取惩罚,因为每个桶都会重复扫描。
不要创建太多的盐桶,拇指规则应等于群集中的区域服务器数量。

你可能感兴趣的:(HBASE修炼之路——00008(HBase之探索优化方案))