剧本杀

HBase是开源版的BigTable。
从官网下载HBase:https://hbase.apache.org/
注意兼容性:http://hbase.apache.org/book.html#hadoop
Hadoop安装后只包含HDFS和MapReduce,并不包含HBase,需要在Hadoop之上继续安装HBase。
编辑配置文件conf/hbase-site.xml,可以修改数据写入目录:
1 | <configuration> |
将 DIRECTORY 替换成期望写文件的目录. 默认 hbase.rootdir 是指向 /tmp/hbase-${user.name} ,重启时数据会丢失。
编辑环境变量conf/hbase-env.sh:
1 | # 如果JAVA_HOME已经有了就不用设置了 |
启动hbase:
1 | ./bin/start-hbase.sh |
关闭hbase:
1 | ./bin/stop-hbase.sh |
如果启动失败后者后续的命令执行失败了,可以查看根目录下的日志:
1 | vim logs/hbase-hgc-master-hgc-X555LD.log |
使用shell连接HBase:
1 | ./bin/hbase shell |
1 | # 查看命令列表,要注意的是表名,行和列需要加引号 |
create - 创建表、列族:
1 | # 创建表 |
list - 查询表信息
1 | > list |
put - 向表、行、列指定的单元格添加数据:
1 | # 向表t1中的行row1和列f1:c1所对应的单元格中添加数据value1,时间戳为1421822284898 |
get - 获取单元格数据
1 | # 从表t1获取数据,行row1、列f1,时间范围为TIMERANGE,版本号为1的数据 |

HBase的实现包含3个主要的功能组件:
客户端会访问HBase的服务端接口,并缓存已经访问过的Region位置信息,用来提高后续访问数据的速度。
Region服务器的主要职责:
Region一般采用HDFS作为底层文件存储系统,并依赖HDFS来实现数据复制和维护数据副本的功能。
每个Region都有一个RegionID来标识它的唯一性,要定位一个Region可以使用<表名, 开始主键, RegionID>的三元组。
HBase还会维护一张<Region标识符, Region服务器>的映射表,被称为元数据表,又名 .META.表。
如果一个HBase表中的Region特别多,一个服务器存不下.META.表,则.META.表也会被分区存储到不同的服务器上,并用一张根数据表来维护所有元数据的具体位置,又名 -ROOT-表,-ROOT-表是不能被分割的,永远只会被存储到一个唯一的Region中。

HBase中的行是根据行键的字典序进行维护的,表中包含的行的数量可能非常大,需要通过行键对表中的行进行分区(Region)。
Region包含了位于某个值区间内的所有数据,它是负载均衡和数据分发的基本单位,这些Region会被Master分发到不同的Region服务器上。
每个Region的默认大小是100MB200MB,当一个Region包含的数据达到一个阈值时,会被自动分裂成两个新的Region,通常一个Region服务器上会放置101000个Region。
Region服务器内部维护了一系列Region对象和一个HLog文件
每个Region由多个Store组成,每个Store对应了表中的一个列族的存储。
每个Store又包含一个MemStore和若干StoreFile,前者是内存缓存,后者是磁盘文件,使用B树结构组织,底层实现方式是HDFS的HFile(会对内容进行压缩)。
HLog是磁盘上的记录文件,记录着所有的更新操作。
每个Store对应了表中一个一个列族,包含了一个MemStore和若干个StoreFile;
其中,MemStore是在内存中的缓存,保存最近更新的数据;StoreFile由HDFS的HFile实现,底层是磁盘中的文件,这些文件都是B树结构,方便快速读取,而且HFile的数据块通常采用压缩方式存储,可以大大减少网络和磁盘IO。
HLog是WAL(Write Ahead Log),因此在MemStore之前写入
如果最后一次刷新后没有新数据,说明所有数据已经被永久保存。
如《缓存刷新》流程所述,每次MemStore刷新都会在磁盘上生成一个新的StoreFile,这样系统中每个Store都会有多个StoreFile,要找到Store中某个值就必须查找所有这些StoreFile文件,非常耗时。
因此,为了减少耗时,系统会调用Store.compact()把多个StoreFile合并成一个大文件。
这个合并操作比较耗费资源,因此只会在StoreFile文件的数量达到一个阈值时才会触发合并操作。
如《Region存储结构》所示,Region服务器是HBase的核心模块,而Store是Region服务器的核心,每个Store对应了表中的一个列族的存储,每个Store包含一个MemStore缓存和若干个StoreFile文件。

在分布式环境下,系统出错可能导致数据丢失,比如Region故障导致MemStore缓存中的数据被清空了。HBase采用HLog来保证系统故障时的恢复。
Ingest Node提供了一种类似Logstash的功能:
相对Logstash来说:
| - | Logstash | Ingest Node |
|---|---|---|
| 数据输入与输出 | 支持从不同的数据源读取,并写入不同的数据源 | 支持从ES REST API获取数据,并且写入ES |
| 数据缓冲 | 实现了简单的数据队列,支持重写 | 不支持缓冲 |
| 数据处理 | 支持大量插件、支持定制开发 | 内置插件,支持开发Plugin(但是添加Plugin需要重启) |
| 配置和使用 | 增加了一定的架构复杂度 | 无需额外部署 |

为ES添加一个Pipeline:
1 | PUT _ingest/pipeline/blog_pipeline |
查看Pipeline:
1 | GET _ingest/pipeline/blog_pipeline |
测试Pipeline:
1 | POST _ingest/pipeline/blog_pipeline/_simulate |
使用Pipeline更新文档:
1 | PUT tech_blogs/_doc/2?pipeline=blog_pipeline |
但是使用_update_by_query更新文档时可能会报错:
1 | POST /tech_blogs/_update_by_query?pipeline=blog_pipeline |
是因为对已经拆分过的字段再用split processor拆分,相当于要对数组类型的字段做字符串切分操作。
为了避免这种情况,可以通过加条件来忽略已经处理过的文档:
1 | POST tech_blogs/_update_by_query?pipeline=blog_pipeline |
processor的种类比较多,这里列出一部分。
ES的_ingest命令可以分析pipeline:
1 | POST _ingest/pipeline/_simulate |
1 | POST _ingest/pipeline/_simulate |
内置脚本语言。
关系数据库一般会考虑Normalize数据,而在Elasticsearch中,往往考虑Denormalize。
ES不擅长处理关联关系,一般采用以下4种方法处理关联:
| Nested Object | Parent / Child | |
|---|---|---|
| 优点 | 文档存储在一起,读取性能高 | 父子文档可以独立更新 |
| 缺点 | 更新嵌套的子文档时,需要更新整个文档 | 需要额外的内存维护关系,读取性能相对较差 |
| 适用场景 | 子文档偶尔更新,以查询为主 | 子文档更新频繁 |
1 | # 插入两条数据 |
上面的搜索初看没什么问题,但是实际上查出了我们不需要的数据。
出现这个问题的原因是:
用Nested Data Type可以解决这个问题:
1 | // 先指定user是nested域 |
像这么定义索引的话相同搜索条件就查不出来了,当然查询条件的city改成”hebei”的话就能重新查出来了。
Nested方式关联的局限性:
ES中Parent / Child的关系是类似关系数据库中的Join查询。
创建索引,设置mapping:
1 | PUT my_blogs |
索引父子文档并查询:
1 | #索引父文档 |
根据需要查询:
1 | #根据父文档ID查看 |
查询子文档:
根据子文档查父文档:
过程:
text:
keyword:
设置多字段类型:
结构化数据:
_source设置enabled为false可以节约磁盘空间
但是一般不会把_source关掉,而是优先考虑增加压缩比,因为关掉后无法再看到_source字段,且无法做Reindex和Update
过多字段带来的问题:
默认最大字段数是1000,可以设置index.mapping.total_fields.limit来修改
正则查询存在的问题:
比如下面插入两条文档,一条文档的rating值为null:
1 | PUT ratings/doc/1 |
聚合分析结果中可以看到,total虽然是2,但是avg结果却是5:
1 | POST ratings/_search |
解决办法是给null取默认值:
1 | DELETE ratings |
1 | PUT softwares |
Mapping的设置是一个迭代的过程:
定义索引的最佳实践。