HBase 性能调优-系统配置

14 May 2013

参照 Apache HBase™ Performance Tuning

zookeeper.session.timeout

预设值 : 3分钟(180000ms)
说明 : RegionServer 与 Zookeeper 间的连接超时时间。当超时时间到后,ReigonServer 会被 Zookeeper 从 RS 集群清单中移除,HMaster 收到移除通知后,会对这台 server 负责的 regions 重新 balance,让其他存活的 RegionServer 接管。
调优 : 这个 timeout 决定了 RegionServer 是否能够及时的 failover。

  • 设置成1分钟或更低,可以减少因等待超时而被延长的 failover 时间。
  • 不过需要注意的是,对于一些 Online 应用,RegionServer 从宕机到恢复时间本身就很短的(网络闪断,crash 等故障,运维可快速介入),如果调低 timeout 时间,反而会得不偿失。因为当 ReigonServer 被正式从 RS 集群中移除时,HMaster 就开始做 balance 了(让其他 RS 根据故障机器记录的 WAL 日志进行恢复)。当故障的 RS 在人工介入恢复后,这个 balance 动作是毫无意义的,反而会使负载不均匀,给 RS 带来更多负担。特别是那些固定分配 regions 的场景。
  • 如果集群正在集中处理一些大数据,为避免响应时间过长(假死)而被 Zookeeper 从 RS 集群中移除,应设置成更高的时间。

hbase.regionserver.handler.count

预设值: 10
说明: RegionServer 的请求处理 IO 线程数。
调优: 这个参数的调优与内存息息相关。

  • 较少的 IO 线程,适用于处理单次请求内存消耗较高的 Big PUT 场景(大容量单次 PUT 或设置了较大 cache 的 scan,均属于 Big PUT)或 ReigonServer 的内存比较紧张的场景。
  • 较多的 IO 线程,适用于单次请求内存消耗低,TPS 要求非常高的场景。设置该值的时候,以监控内存为主要参考。
  • 这里需要注意的是如果 server 的 region 数量很少,大量的请求都落在一个region上,因快速充满 memstore 触发 flush 导致的读写锁会影响全局 TPS,不是 IO 线程数越高越好。
  • 压测时,开启Enabling RPC-level logging,可以同时监控每次请求的内存消耗和 GC 的状况,最后通过多次压测结果来合理调节 IO 线程数。

hbase.hregion.max.filesize

预设值: 256M
说明: 在当前 ReigonServer 上单个 Reigon 的最大存储空间,单个 Region 超过该值时,这个 Region 会被自动 split 成更小的 region。
调优:

  • 小 region 对 split 和 compaction 友好,因为拆分 region 或 compact 小 region 里的 storefile 速度很快,内存占用低。缺点是 split 和 compaction 会很频繁。
    特别是数量较多的小 region 不停地 split, compaction,会导致集群响应时间波动很大,region 数量太多不仅给管理上带来麻烦,甚至会引发一些 Hbase 的 bug。
    一般512以下的都算小 region!!
  • 大 region,则不太适合经常 split 和 compaction,因为做一次 compact和 split 会产生较长时间的停顿,对应用的读写性能冲击非常大。此外,大 region 意味着较大的 storefile,compaction 时对内存也是一个挑战。
    当然,大 region 也有其用武之地。如果你的应用场景中,某个时间点的访问量较低,那么在此时做 compact 和 split,既能顺利完成 split 和 compaction,又能保证绝大多数时间平稳的读写性能。
  • 既然 split 和 compaction 如此影响性能,有没有办法去掉?

    compaction 是无法避免的,split 倒是可以从自动调整为手动。


    只要通过将这个参数值调大到某个很难达到的值,比如 100G,就可以间接禁用自动 split(RegionServer 不会对未到达 100G 的 region 做 split)。
    再配合 RegionSplitter 这个工具,在需要 split 时,手动 split。
    手动 split 在灵活性和稳定性上比起自动split要高很多,相反,管理成本增加不多,比较推荐 online 实时系统使用。
  • 内存方面,小 region 在设置 memstore 的大小值上比较灵活,大 region 则过大过小都不行,过大会导致 flush 时 app 的 IO wait 增高,过小则因 store file 过多影响读性能。

hbase.regionserver.global.memstore.upperLimit/lowerLimit

预设值: 0.4/0.35
基础: hbase.hregion.memstore.flush.size 这个参数的作用是当单个 Region 内所有的 memstore 大小总和超过指定值时,flush 该 region 的所有 memstore。RegionServer 的 flush 是通过将请求添加一个队列,模拟生产消费模式来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发 OOM。
说明:

  • upperLimit 这个参数的作用是防止内存占用过大,当 ReigonServer 内所有 region 的 memstores 所占用内存总和达到 heap 的40%时,HBase 会强制 block 所有的更新并 flush 这些 region 以释放所有 memstore 占用的内存。
  • lowerLimit 这个参数的作用是在所有 region 的 memstores 所占用内存达到 Heap 的35%时,不 flush 所有的 memstore。它会找一个 memstore 内存占用最大的 region,做个别 flush,此时写更新还是会被 block。lowerLimit 算是一个在所有 region 强制 flush 导致性能降低前的补救措施。在日志中,表现为 “** Flush thread woke up with memory above low water.”

调优: 这是一个 Heap 内存保护参数,默认值已经能适用大多数场景。

  • 参数调整会影响读写,如果写的压力大导致经常超过这个阀值,则调小读缓存 hfile.block.cache.size 增大该阀值,或者 Heap 余量较多时,不修改读缓存大小。
  • 如果在高压情况下,也没超过这个阀值,那么建议你适当调小这个阀值再做压测,确保触发次数不要太多,然后还有较多 Heap 余量的时候,调大 hfile.block.cache.size 提高读性能。
  • 还有一种可能性是 hbase.hregion.memstore.flush.size 保持不变,但 RS 维护了过多的 region,要知道 region 数量直接影响占用内存的大小。

hfile.block.cache.size

预设值: 0.2
说明: storefile 的读缓存占用 Heap 的大小百分比,0.2表示20%。该值直接影响数据读的性能。
调优: 当然是越大越好,如果写比读少很多,开到0.4-0.5也没问题。如果读写较均衡,0.3左右。如果写比读多,果断默认吧。设置这个值的时候,你同时要参考 hbase.regionserver.global.memstore.upperLimit,该值是 memstore 占 heap 的最大百分比,两个参数一个影响读,一个影响写。如果两值加起来超过80-90%,会有 OOM 的风险,谨慎设置。

hbase.hstore.blockingStoreFiles

预设值: 7
说明: 在 flush 时,当一个 region 中的 Store(Coulmn Family)内有超过7个 storefile 时,则 block 所有的写请求进行 compaction,以减少 storefile 数量。
调优: block 写请求会严重影响当前 regionServer 的响应时间,但过多的 storefile 也会影响读性能。从实际应用来看,为了获取较平滑的响应时间,可将值设为无限大。如果能容忍响应时间出现较大的波峰波谷,那么默认或根据自身场景调整即可。

hbase.hregion.memstore.block.multiplier

预设值: 2
说明: 当一个 region 里的 memstore 占用内存大小超过 hbase.hregion.memstore.flush.size 两倍的大小时,block 该 region 的所有请求,进行 flush,释放内存。

虽然我们设置了 region 所占用的 memstores 总内存大小,比如64M,但想象一下,在最后63.9M的时候,我 Put 了一个200M的数据,此时 memstore 的大小会瞬间暴涨到超过预期的 hbase.hregion.memstore.flush.size 的几倍。这个参数的作用是当 memstore 的大小增至超过 hbase.hregion.memstore.flush.size 2倍时,block 所有请求,遏制风险进一步扩大。
调优: 这个参数的默认值还是比较靠谱的。如果你预估你的正常应用场景(不包括异常)不会出现突发写或写的量可控,那么保持默认值即可。如果正常情况下,你的写请求量就会经常暴长到正常的几倍,那么你应该调大这个倍数并调整其他参数值,比如 hfile.block.cache.size 和 hbase.regionserver.global.memstore.upperLimit/lowerLimit,以预留更多内存,防止 HBase server OOM。

hbase.hregion.memstore.mslab.enabled

预设值: true
说明: 减少因内存碎片导致的 Full GC,提高整体性能。
调优: 详见 利用Arena Allocation避免HBase触发Full GC

其他

启用 LZO 压缩

LZO 对比 Hbase 默认的 GZip,前者性能较高,后者压缩比较高,具体参见 Using LZO Compression。对于想提高 HBase 读写性能的开发者,采用 LZO 是比较好的选择。对于非常在乎存储空间的开发者,则建议保持默认。

不要在一张表里定义太多的 Column Family

Hbase 目前不能良好的处理超过包含2-3个 CF 的表。因为某个 CF 在 flush 发生时,它邻近的 CF 也会因关联效应被触发 flush,最终导致系统产生更多 IO。

批量导入

在批量导入数据到 Hbase 前,你可以通过预先创建 regions,来平衡数据的负载。详见 Table Creation: Pre-Creating Regions

避免 CMS concurrent mode failure

HBase 使用 CMS GC。默认触发 GC 的时机是当年老代内存达到90%的时候,这个百分比由 -XX:CMSInitiatingOccupancyFraction=N 这个参数来设置。

concurrent mode failed 发生在这样一个场景:当年老代内存达到90%的时候,CMS 开始进行并发垃圾收集,于此同时,新生代还在迅速不断地晋升对象到年老代。当年老代 CMS 还未完成并发标记时,年老代满了,悲剧就发生了。CMS 因为没内存可用不得不暂停 mark,并触发一次 stop the world(挂起所有 jvm 线程),然后采用单线程拷贝方式清理所有垃圾对象。这个过程会非常漫长。为了避免出现 concurrent mode failed,建议让 GC 在未到90%时就触发。

可以简单的这么计算,如果你的 hfile.block.cache.size 和 hbase.regionserver.global.memstore.upperLimit 加起来有60%(默认),那么你可以设置 70-80,一般高10%左右差不多。

>>HBase性能调优


MySQL 远程登录

13 May 2013

MySQL 在多机上进行操作,必然会涉及到远程登录

使用 root 账户远程登录

在设置 root 账户密码时,可以选择是否允许其从远程访问。默认情况下是不允许的。有两种大同小异的设置方式:

方法一

# 使用通配符,授与 root 用户从任何其它主机发起访问
# mysql -u hadoop -h 192.168.1.1 -p
mysql> GRANT ALL PRIVILEGES ON *.* TO root@"%" IDENTIFIED BY 'xxx' WITH GRANT OPTION;

方法二

1 # 直接修改 mysql 数据库中的 user 表
2 mysql> use mysql;
3 mysql> update user set host='%' where user='root';
4 # 一定要 flush 才能生效
5 mysql> flush privileges;

新建其他账户远程登录

使用 grant 语句,grant 总是创建新用户

# 创建一个 hadoop 账户,只能从 192.168.1.111 主机通过密码 xxx 登录
mysql> GRANT ALL PRIVILEGES ON *.* TO hadoop@192.168.1.111 IDENTIFIED BY 'xxx' WITH GRANT OPTION;

MySQL 大小写区分

13 May 2013

MySQL 在 Linux 和 Windows 下对大小写处理不同

Linux 版

MySQL 在 Linux 下区分表名的大小写,不区分列名的大小写

MySQL 在 Linux 下数据库名、表名、列名、别名大小写规则是这样的:

  • 数据库名与表名是严格区分大小写的
  • 表的别名是严格区分大小写的
  • 列名与列的别名在所有的情况下均是忽略大小写的
  • 变量名也是严格区分大小写的

如果想在查询时不区分字段值的大小写,用 root 帐号登录后,在 /etc/my.cnf 中的 [mysqld] 后添加 lower_case_table_names=1,重启 MySQL 服务

lower_case_table_names = 0: 区分大小写,1: 不区分大小写

Windows 版

MySQL 在 Windows 下都不区分大小写

如果想在查询时区分字段值的大小写,字段值需要设置 BINARY 属性,设置的方法有多种:

  • 创建时设置:
    CREATE TABLE T(
    A VARCHAR BINARY
    );
  • 使用 alter 修改:
    ALTER TABLE ‘tablename’ MODIFY COLUMN ‘cloname’ VARCHAR BINARY;
  • mysql table editor 中直接勾选 BINARY

MySQL 备份与还原

13 May 2013

如果你要简单将一个 MySQL 库从一个节点转移到另一个节点

Step1 备份(node1)

1 # mysqldump -u 用户名 -p 数据库名 > 导出的文件名 
2 $ mysqldump -u root -p test > test.sql

Step2 还原(node2)

方法一

1 $ mysql -u root -p
2 mysql> create database test;
3 mysql> use test;
4 mysql> source test.sql;
5 # 再次出现 mysql> 并且没有提示错误即还原成功 

方法二

1 $ mysql -u root -p test < test.sql

>>【逻辑备份】深入浅出 mysqldump:常用操作、案例分享、意外终止的原因以及解决方法


CentOS+MySQL 相约日记

12 May 2013

MySQL 我的最爱

Step1 安装

1 $ sudo yum install mysql mysql-server

Step2 配置

1 $ sudo vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# 设置编码格式
default-character-set=utf8
# 设置不区分大小写
lower_case_table_names=1 

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

[mysql]
# 设置编码格式
default-character-set=utf8

Step3 启动服务

1 # 设置MySQL服务随系统启动自启动
2 $ sudo chkconfig mysqld on
3 # 确认MySQL自启动,如果2--5为on的状态就OK
4 $ sudo chkconfig --list mysqld
5 mysqld 0:off 1:off 2:on 3:on 4:on 5:on 6:off
6 # 启动MySQL服务
7 $ sudo /etc/rc.d/init.d/mysqld start
8 Initializing MySQL database:			[ OK ]
9 Starting MySQL:				[ OK ]

Step4 环境设定

为 MySQL 的 root 用户设置密码,MySQL 在刚刚被安装的时候,它的 root 用户是没有被设置密码的。

1 $ mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): <-- 输入系统 root 密码
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] <-- ENTER
New password: <-- 你的 MySQL root 密码
Re-enter new password: <-- 你的 MySQL root 密码
Password updated successfully!

Reloading privilege tables..
... Success!

By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

# 删除匿名用户,在MySQL刚刚被安装后,存在用户名、密码为空的用户。这使得数据库
服务器有无需密码被登录的可能性。为消除隐患,将匿名用户删除。
Remove anonymous users? [Y/n] <-- ENTER 
... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] <-- ENTER
... Success!

By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

# 删除人人都能访问的 test 数据库
Remove test database and access to it? [Y/n] <-- ENTER
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] <-- ENTER
... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!

Step5 测试

 1 # 用 root 用户通过密码登录
 2 $ mysql -u root -p
 3 Enter password: <-- 输入密码
 4 Welcome to the MySQL monitor.  Commands end with ; or \g.
 5 Your MySQL connection id is 50
 6 Server version: 5.1.69 Source distribution
 7 
 8 Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 9 
10 Oracle is a registered trademark of Oracle Corporation and/or its
11 affiliates. Other names may be trademarks of their respective
12 owners.
13 
14 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
15 
16 mysql> 

OK~至此安装成功


<< Previous Page Next Page >>
Fork me on GitHub