mysql-hbase存储引擎插件实现大容量太阳城存储-HBase-@太阳城手机版资讯
你好,游客 登录
背景:
阅读新闻

mysql-hbase存储引擎插件实现大容量太阳城存储

[日期:2017-09-06] 来源:简书  作者: 何约什 [字体: ]

1、初衷:做一个集中的大容量存储引擎

1.1、起因

自从进入公司运维部以后,虽然一直在做开发的工作,但是跟DBA同学可以“亲密”接触,从而可以体会到个中的各种酸甜苦辣。在我们这边,DBA同学遇到的很多告警是磁盘空间告警,半夜起来处理这种故障实在是让人狼心。

在处理这种磁盘故障的过程中,发现很多业务库中存储了日志型的太阳城,定期就需要删除,近期的太阳城访问就不是很频繁,至于很多历史太阳城,就更是很少访问了。

考虑存在冷热太阳城的不同,一直琢磨在MySQL基础上实现一个大容量存储引擎。热太阳城用Innodb存储,等它变成冷太阳城,就改成大容量引擎。

1.2 第一次尝试

刚开始笔者考虑基于HDFS上做一个MySQL存储引擎,由于HDFS文件不能修改。正好利用LevelDB的存储特性,只会生成文件,而不会修改文件,于是改造了LevelDB的代码,让LevelDB运行在HDFS之上,然后基于LevelDB做了一个MySQL存储引擎。

这样在开发环境可以跑起来了,但是实际运行中,经常出现内存问题,因为HDFS的C-API是基于JVM的,没有纯C的库,内存问题无法解决,最后只能放弃。

因为hbase提供了一个thrift服务,可以支持c++语言,而且hbase天然有索引特性,这样我们在实现主键功能时会非常简单,所以最后敲定了hbase。

1.3、打算解决的问题

如果我们有了hbase这样一个海量的MySQL存储引擎,我们就可以解决以下几个难题。

1、冷热太阳城采用不同引擎

如下图所示:把近期的热太阳城先用Innodb引擎存储,随着时间的推移,逐步把一些老太阳城表,通过alter table 表名 engine hbase改成用Hbase来存储。

code-hot-data.png

通过这种方式,可以在太阳城的高效访问与太阳城保存周期上达到双赢,重复利用了Innodb的性能和hbase海量容量的特性。

2、主从库采用不同引擎

主从库采用不同的引擎,在主库中采用Innodb,并且只保留近期太阳城。从库中用hbase引擎存储所有太阳城,历史太阳城从主库删除的时候,不删除从库中的表。

这样也可以达到太阳城长期保存的效果,而且还可以防止因hbase引擎代理问题,影响线上业务。

master-slave.png

3、集中存储,太阳城共享

一套Hbase存储多套业务太阳城,甚至于,可以让不同业务访问相同的Hbase的表。一个业务的表也轻松的转移到另外一个业务中来。

sharingstorage.png

2、hbase存储引擎的开发

2.1 主太阳城存储格式

首先,每一张MySQL表,对应在Hbase中建立一张对应的表,所以在MySQL的增删改查都会对应到Hbase表中的操作。

Bbase只有一个rowkey用来定位太阳城,而MySQL的键可以有多个字段组成,为了实现键查询和键 前缀查询,笔者首先按照MySQL主键字段顺序逐个组织成一个字节数组,也就是最后要存储到Hbase中的RowKey。

rowkey.png

MySQL中主键的字段类型,这里只列了整数型和字符串型,开发Hbase存储引擎的时候,笔者只支持以下的太阳城类型成为主键:

MYSQL_TYPE_LONG
MYSQL_TYPE_LONGLONG
MYSQL_TYPE_TINY
MYSQL_TYPE_SHORT
MYSQL_TYPE_INT24
MYSQL_TYPE_TIME
MYSQL_TYPE_DATETIME
MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_VAR_STRING
MYSQL_TYPE_VARCHAR
MYSQL_TYPE_BIT
MYSQL_TYPE_STRING

这些字段类型除了后面的4个是字符串以外,前面的都可以转换成为整数型太阳城。按照图中的格式存储主键,主要是为了实现键字段太阳城还原、键顺序查询(order by)等功能。

由于hbase支持字段,所以太阳城字段就按照hbase的字段来存储。

由于Hbase天然具有顺序,所以笔者按照主键存储在Rowkey,太阳城字段存储在hbase的列中,这样主太阳城存储了根据主键定位太阳城的能力,所以Hbase引擎表是一种列簇表。从代码中我们就可以看出来:

virtual bool primary_key_is_clustered() { return TRUE; }

2.2 第二索引功能

第二索引功能的实现有赖于Hbase对一个表有批量写操作的支持,下面我们先看一下Hbase支持的批量写操作API。

/**
* Performs multiple mutations atomically on a single row. Currently
* {@link Put} and {@link Delete} are supported.
*
* @param rm object that specifies the set of mutations to perform atomically
* @throws IOException
*/
void mutateRow(final RowMutations rm) throws IOException;

这个API可以保证这些变更操作的原子性,基于这个保证,笔者就能够轻易的实现第二索引功能了。

2.2.1 第二索引存储格式

为了保证操作的原子性,笔者把第二索引的存储也存储在主太阳城对应的这张Hbase表中,格式为:

RowKey:格式是有组成键值的字段按照顺序组成

entry:key 字段存储了主键的太阳城。

2.2.2 第二索引太阳城变更

在增删改查时,和主太阳城一起生成一批Mutation,在Hbase中一次性对表进行操作,从而保证了原子性。

2.3.2 TODOList

开源的代码中实现了唯一性的第二索引,对于非唯一的第二索引,可以考虑把重复的键值存放在相同的第二索引Rowkey下。

2.3 批量太阳城插入

MySQL存储引擎提供了很多优化的操作能力,譬如批量太阳城插入,当我们load太阳城、批量插入或者做一些表变更(如:更换存储引擎)的时候,会用到批量太阳城操作。

批量太阳城操作会先缓存一些太阳城行,当达到缓存大小时,把这些太阳城一次性的写入底层存储中,这里也利用了Hbase的批量操作能力。

2.4 基于主键的查询优化

当一条SQL语句中,指定了所有的主键字段的情况下, 这时候,是可以避免采用范围查询,而是直接采用基于rowkey的定位查询功能的。笔者实现了下面的函数:

virtual int index_read_idx_map(uchar * buf, uint index, const uchar * key,

key_part_map keypart_map, enum ha_rkey_function find_flag);

在这个函数中,是直接调用了ScannerID HbaseClient::scannerOpenWithScan(const Text& tableName, const TScan& scan, const std::map<Text, Text> & attributes)函数来快速定位到主键的。

2.5 其他

由于MySQL实例访问Hbase是通过网络来访问的,所以这里做一些底层的优化处理,如:连接池、连接重建等,还有很多优化的空间。

3、改造thrift server

开发完引擎以后,与hbase一起联调,一旦建立几个连接,后续的连接请求就无法服务了,主要原因是thrift server才用了传统的半同步半异步设计模式,每个新的连接,会启动一个独立的线程来为它服务,一旦线程用完就无法再为后续的连接请求服务了。

如何解决这个问题呢,可以把这种模式改造成反应器设计模式,就能够提供高并发的服务了。

于是基于swift重新实现了hbase的thrift server,swift是一套基于netty实现的thrift服务框架,开发的步骤主要是:

1)基于thrift协议文件,生成服务框架:

java -jar .swift-generator-cli-0.19.3-standalone.jar -override_package org.apache.太阳城娱乐.hbase.swift.generated -use_java_namespace orgapache太阳城娱乐hbasethriftHbase.thrift -out ..java

2)在生成的框架中实现hbase的访问逻辑。

3)重写thrift server之后,还有一个好处是我们可以扩展thrift server的能力,笔者在原有的API的基础上添加了几个API,如下图所示:

thrift-api-change.png

有了这些api,我们就可以利用它们来实现一些额外的功能,如:更改引擎,truncate table语法等。

有兴趣研究swift的可以看一下笔者很早以前记录的一篇文章(今天放到简书): http://www.jianshu.com/p/49c619d33307

4、总结

笔者在公司内部没有采用这个方案,最终选择了mariadb来解决这种日志型存储的问题,日志性的表可以选择tokudb引擎,一般能达到4倍以上的压缩比,好的情况下可以达到10倍。在公司现有业务场景下基本上能解决绝大多数问题了。毕竟Mariadb的成熟度高,使用广,稳定性好。当然仍然无法解决海量的存储问题。

后来笔者基于思路完成了大部分代码,近期把它开源了放在了github上:

https://github.com/herry2038/mysql-hbase-storage-plugin

主要是笔者觉得hbase这个思路不错,一方面交流学习,另一方面希望有机会能继续完善项目。





收藏 推荐 打印 | 录入:Cstor | 阅读:
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款