HBase存储原理剖析

这边笔记主要作用就是让自己更好的深入理解HBase的运行原理,当遇到问题时能高效快捷的锁定并解决问题。

原理剖析我们有一下几个目标:

1、HBase的存储模式

1.1行式存储与列式存储的介绍


行式存储特点是把每一行的所有列存储完,再存储下一个行的所有列,一行一行横向存储的。列式存储特点是把每一列的数据存储完,再存储下一列的所有数据,直到所有列的数据存储完,是纵向的存储

行式存储与列式存储特点:

行式存储:

行式存储维护大量的索引,存储成本比较高,不能做到线性扩展,对于随机读的效率非常高。最大的特点就是对事务的支持能力非常好。

列式存储:

根据同一列数据的相似性原理,对数据进行压缩,存储成本比较低。列式存储每一列的数据都是分开存储的,我们在查找不同列的数据的时候,可以利用并行查询的原理,高效的查询多列的数据。而行式存储是将不同列的数据存储在同一行上的,所以并行查询是不可能实现的。

行式存储与列式存储的应用环境:

列式存储应用场景:

》对于单列或者相对少的列,获取频率较高,推荐列式存储。因为如果你只要某列的数据,那么只需要找某一列存储位置即可。

》如果是对多列查询,使用并行处理的查询也是效率非常高的,这样的情况也可以使用列式存储。

》特别是对于大数据的环境,利于数据压缩和扩展,这样的存储场景比较多的话,同样第一个应该考虑的是列式存储。

》如果你的事务使用率不高、读取场景的频率不高、数据量非常大这样的场景也需要列式存储。

》如果你随机更新某行频率不高的话,列式存储也是不错的选择。

行式存储应用场景:

行式存储实现了一个关系型数据库的解决方案,如果你的表与表之间有很强的关联性,且数据量不大的话,使用行式存储是一个比较好的选择,可以很容易关联查询数据。

》行式存储最大的优势是联机事务处理能力,如果你要存储消费、转账的记录,你就需要强事务关联性。

》但是由于行式存储线性扩展性不高,需要保证我们的数据量存储不能特别大,如果你的数据只有千万量级的话,考虑使用行式存储。

》简单说,行式存储适合事务型应用场景,列式存储更适合分析型应用场景。

hbase的列族(列簇)式的存储

列族的存储概念:多个数据列的组合,hbase表中的每个列都归属于某个列族。列族是表的schema的一部分,而列不是,我们在创建一张hbase表的时候,必须要给出列族的名称,但不需要给出列的名称。列名一般都以列族名称作为前缀,访问控制、磁盘、内存的使用统计都是在列族层面进行的,hbase准确的说是列族数据库,而不是列数据库。


列数据的属性:

默认情况下,一列数据可以保存三个版本,特别对于聊天这类应用,特别方便。比如标识信息是已读的还是未读的。

hbase存储数据底层是两个SortMap,第一个Map按照字段顺序存放RowKey,第二个map是按照字典顺序存放Colume。每一个Column对应一个List<Value,Timestamp>
这个例子中的row1对应的colume就可以清晰的验证相同列族下面的列式是按照字典顺序排列的,另外所有的row对应的rowkey也是按照字段顺序排列的

2、HBase的数据表解析


对表demo:user对应的各个属性分别是什么意思

Name:是数据表的列族名,在建表的时候必须要提供的,且以后在hbase表的工作过程中,最好不要修改。因为很多属性都是基于列族进行配置的,如果你修改那么的话,会导致表的结构发生变化。

Version:是时间版本的个数,这里的b列族就显式声明了3个时间版本。

Replication_scope:是hbase0.9版本的时候,加入了一个重要机制,要多副本机制,他的数据完整性得到进一步保障。当请求发送给master的时候,log的日志放入hdfs的同时会进入到Replication的队列里面,由Slave通过zookeeper去获取信息写入到slave节点的表中,master和slave是主从集群机制。

Compression:数据压缩格式的配置,其中列族b和o都是把压缩格式设置为了SNAPPY,其实SNAPPY就是一种压缩格式。

压缩特性:就是使用cpu资源换区磁盘资源,对读写性能并不会有太大影响,目前hbase支持三种压缩格式,GZip、LZO、SNAPPY


remaining:压缩率、Encoding编码速率、Decoding解码速率,综合来看Snappy是一种解码和编码速率最快的压缩方式,因此hbase选用Snappy来压缩,是较为合适的。

HBase数据存储目录

我们在搭建HBase时,需要指定其数据存储目录,HBase会在指定的目录中构造需要的目录结构,之后我们创建数据表以及存放数据时,也会存放在对应的目录中,我们下面就介绍下,hbase数据存储目录结构。


hbase的数据存储目录就在hbase-site.xml中的hbase.rootdir配置属性

我这里的目录结构是存放在hdfs上的,如下图,系统级别的目录如下:


他们分别什么作用,我们逐一来讲解

.tmp:当对表做创建或删除操作时,会将表移动到.tmp目录下面,然后再去做处理操作他是一个临时交换的表目录,临时存放一些当前需要修改的数据结构。

WALs:它其实是一个预写日志,它是被HLog实例管理的WAL文件,这里可以简单的理解为hbase数据库系统的操作日志文件。

archive:它存储表的归档和快照,hbase在做分隔或者是合并操作完成之后,会将hfile文件移动到archive目录中,然后将之前的hfile删除掉。这个目录是有master中的定时任务定期去处理。

corrupt:这个目录用于存放损坏的日志文件,他一般是空的,如果他不为空代表我们的系统出现了些问题,有些日志文件可能被损坏了。

data:它是hbase存储数据的核心目录,系统表和用户表数据都存储在这里,他是非常重要的目录

hbase.id:hbase在运行起来之后,就会产生集群中的唯一id,是用来标识hbase进程用的。

hbase.version:它表明了hbase的文件格式、版本信息,其实就是表明了hfile的文件版本信息。

oldWALs:当WALs中的log文件被持久化后,日志就不被需要了,就会被移动到oldWALs目录中等待删除。

用户级别的目录:


HBase的元信息表

Row Key:其实Meta Table也是一个普通的hbase数据表,他的结构跟普通的表结构是差不多的。不过他的Row Key和Value有特殊意义:Row Key它包含三个部分,对三个部分进行组合得到一个Row Key,其中table为region table、region Start key、以及region Time,这里的time为存储数据的最早时间。由于Mata Table中包含Start key,所以它很容易找到对应的region,最后找到对应的数据。

Value:value最终指向的是Region Server,它其实保存的是Region Server的地址。表中最主要的列族是info,列族中包含三个主要的列,都是属于value的,三个属性列中第一个属性列是regioninfo,第二个属性列是server,包含了Region Server的服务器地址和端口,第三个属性列是Start code,它包含了Region Server的start time。

Meta Table表的值,会发生变化吗?

答案是可定的,它的值是会发生变化的,当region进行分割、合并、禁用、启用、删除等会导致region重新分配,或者region server服务节点挂掉,也会导致region重新分配,这时候meta表的数据会及时更新,这个动作是由master发起的,正是由于它能够及时的更新,才能保证客户端根据mate表访问到的数据是存在的。其实理解了meta table就理解了hbase存储数据的机制,其实mate Table就是hbase存取数据的第一级索引,是最重要的系统表。


3、HBase的存储设计(核心)


》什么是LSM树?

他的概念是日志结构合并树,是由两个或两个以上存储数据的结构组成的,每一个数据结构各自对应自己的存储介质。但从概念上不太好理解,我们从LSM树的简易模型来介绍,相对好理解些。

LSM树的简易模型是由两个树状结构组成,这两个树分别是C0和C1。C0比较小,并且全部存储于内存之中,而C1则存储于磁盘之上,一条新的记录先从C0中插入,插入时会判断C0中的内存阀值,如果超出了阀值,C0中的某些数据片段会被迁移并合并到C1的树上。由于合并排序算法是批量的且是顺序存储,所以说速度是非常快的。当然这只是简易模型,在实际应用时,是多余两层树结构的。


》LSM思想在HBase中的实现,C0级用户数据到达了region server为了加速随机写,region server不会将数据直接刷写到硬盘里面,是写入log和memorye,写日志的原因是因为内存中的数据是不稳定的,写入内存中的数据在机器宕机或重启的情况下,就会丢失,所以写入log是保证高可用。


》当C0层数据到达阈值时,会被迁移至C1层数据,并将C0层的多个小文件合并成多个大文件,当C1层的数据达到阀值时,异步线程启动,多路合并多个文件刷到磁盘当中,形成一个最终的大文件。这就是HBase借鉴的LSM存储思想,从而达到了高效的存储性能,后续我们会继续详细介绍每个层的实现模块。

HBase存储设计模块简介

RegionServer的组成部分为:Region + Store + MemStore + StoreFile + HFile + HLog

Region:一个RegionServer能包含很多个Region,Region是存储用户数据的最小单元,每个Region中包含的数据都是互斥的,存储用户各个行的数据。

Stroe:Region里包含了很多Store,Store对应于HBase表的列族,我们定义HBase表时,为表定义了多少个列族,那么每个Region中就包含了多少个Stroe。

HLog:一个RegionServer中包含唯一的一个HLog实例,HLog用于实现预写日志,用户存储的数据最先会保存在这里,目的就是实现整个系统的高可用,在系统宕机或崩溃的时候回放日志,恢复到原始的状态。

MemStore:Store中包含了一个MemStore,它是内存式的数据结构,用户数据进入Region之后,先会刷写到MemStore中,当MemStore的数据装满之后,会把数据刷写到StoreFile中。StoreFile又会封装成HFile,最后再去往HDFS中真正刷写成HFile文件。MemStore其实是一个Store的内存缓冲服务,用户数据在写入到HLog之后第二步会写入到MemStore中。

Hlog和MemStore就构成了LSM的第一级结构Level0


StoreFile:它其实是在MemStore数据装满以后,由MemStore刷写出来的文件,他是HFile的简单封装。

HFile:它是HBase存储数据的一个组织形式,我们所保存的数据,在HBase中的最终存储格式就是HFile。我们可以简单的认为我们的数据都存储在HFile中。

StoreFile和HFile这两个模块构成LSM中的第二级结构Level1,他实现了内存数据的持久化。


HBase Region解析

什么是Region?


1、每一个Region都会存储于一个确定的RegionServer上,不会出现同一个region在两个RegionServer上,他们之间的数据是互斥的关系。HBase表在RowKey的方向上分配了多个Region,他是hbase分布式存储和负载均衡的最小单元。Region按照大小进行切分,每个表一行只有一个Region,所以说一行数据不可能分散在多个Region上面。当不断的插入,导致Region的存储或者是某个列族到达一定预值之后,Region会被水平拆分为两个Region,Region在RegionServer运行过程中,可能会出现移动,这是Master的负载均衡策略。或者某一个RegionServer挂了或宕机了,存储于它之上的所有Region都会把Master安排到其他的RegionServer上面。

2、每个Region都有三个重要的属性信息来标识他们,第一个TableName(表的名称)第二个是Start_RowKey(表示从哪个rowkey开始的),所有的rowkey都是排序的,所以根据rowkey容易检索数据。第三个是CreateTime(表示Region中最早的一条数据插入的时间)。

》Region有哪些特点?

1、Region是HBase中分布式存储和负载均衡的最小单元,不同的Region分布到不同的RegionServer上,但并不是存储的最小单元,存储的最小单元是HFile。

2、Region的数量问题,如果RegionServer中Region的数量过多就会导致性能下降,region的数量太少就会妨碍可扩展性,降低并行能力,导致机器压力不够分散。所以有个设计原则,Region的数量一定不能低于集群中节点的数量。

3、Region的拆分策略,Region的拆分操作是不可见的,因为Master不会参与其中,那么RegionServer拆分Region的步骤是什么呢?其实RegionServer是先将要拆分的Region下线,然后对他进行拆分,然后将子Region加入到Meta Table表的元信息中。之后再将他们加入到原本的RegionServer上面。最后同步到Master上面。

总结:Region实现了HBase的负载均衡,所以我们在对表进行设计,特别是对RowKey的设计上,要花一点功夫,尽量让数据分散到多台RegionServer上,避免某个节点成为热点,这样才能高效的发挥HBase的性能。

HBase HFile 解析

Store:一个Store包含了一个MemStroe和0个或多个StoreFile。其中MemStroe是一个内存数据结构,StoreFile是文件系统级别的数据结构。Store是由Region去管理的,用于维护列族的数据。对于一个HBase的表,设计了几个列族,那么对于任何一个Region而言就会有几个Store。这也是HBase被称为列族式数据库的原因。他会把一起访问的数据放在一个Stroe里面。同时HBase会以Store大小来判断,是否需要去切分Region。

MemStore:它是一个内存数据结构,它保存修改的数据,即用户put、delete等请求,因为将数据存储在内存之中,所以需要有预值控制,到达预值,就刷写到文件系统。默认这个预值是64M,为了保证读写线程不被阻塞到,HBase提供了专门的Flush异步线程,去实现数据的刷写。

StoreFile:它是MemStore中的内存数据刷写到文件之后形成的StoreFile,它底层是以HFile的格式保存的。

HFile:HFile文件他是HBase存储数据文件的最基本的存储形式,他底层是HDFS的二进制格式文件。他是用户数据的实际载体。它存储着Key-Value这样的数据。

Scanned block section:它是在顺序扫描HFile的时候,这个部分的所有数据块将会被读取,用户数据存储于这个部分之中。其实用户数据确切的说就存储在Data Block中

Nonscanned block section:它是在顺序扫描HFile的时候,这些数据块不会被读取到,主要包含一些Meta block(元数据块)它是在访问用户数据的时候不会被扫描到的。

Load-on-open section:这部分数据在HBase Region Server启动的时候,会加载到内存中,主要是HFile元数据相关的信息。

Trailer:这部分记录了HFile的基本信息,各个部分的偏移量,寻址信息,可以简单的理解它也是HFile元数据的一部分。

HBase Data Block

Data block是HBase中数据存储的最基本单元,它实际存储用户的数据结构,他实际上存储着key-value数据,key-value数据结构是HBase中的核心。每个数据都是以key-value格式在HBase中存储的。接下来我们详细的介绍下Data block的key-value结构。如下图:

》上图可知,Data Block每一个数据都是一个key-value,而每一个key-value包含四个部分

Key Length:key的长度,Value Length:value的长度,他们两个主要起到控制偏移的作用。最后再保存key和对应的value。

我们发现key也有多部分组成,分别是:

Row Length:行键的长度、Row:行键、ColumenFamily Length:列族的长度、ColumnFamily:列族、ColumnQualifier Length:列描述符的长度(这些所有以length命名的数据模块其实是起到偏移控制的作用)、ColumnQualifier:列描述符、Timestamp:时间戳即版本、KeyType:墓碑标记,包含put、delete、deleteColumn、deleteFamily。什么意思呢?

》我们之前介绍过,HBase的插入性能非常高,但是从来没有介绍过,HBase删除数据的时候是怎么做的。这里卖个关子,问下:当你执行delete的时候,HBase会将存储的数据立即删除吗?答案:是不会的,这里有个非常重要的细节就是,内存数据一旦刷写成HFile文件之后,数据将不可做修改,也就是说,当用户存储进来的数据被保存成HFile之后都不能被修改。

》那这时候如果我么确实要删除数据怎么办呢?

这时候KeyType就起作用了,用户正常插入数据使用put,用户删除数据使用delete,delete代表删除整行数据,deleteColumn代表删除对应的列数据,deleteFamily代表删除一个列族之下的数据。其实这就是给数据打上一个标记,这里叫做墓碑标记,标识着这个数据被删除掉了。当我们再对HBase这张表进行扫描的时候,这些被标记的列或行就不会被扫描到了。在后续的运行过程中,HBase会在某个时间点,定时清理掉这些被标记的数据,并不是在执行delete语句的时候,就立即删除。

HBase WAL解析

》WAL最重要的功能就是灾难恢复,类似于mysql的binlog,它记录的所有的数据改动,一旦服务器崩溃,通过重放log,可以恢复到崩溃之前的状态。所以当对Region Server写入数据的时候,如果写入WAL失败,整个操作将被认为是失败的。由上图可以看出,所有的用户写入数据都会经过RegionServer的log syncer,然后写入到Hlog之中,然后在写入到Region之中。

》WAL解决了hbase的什么问题?

1、它解决了HBase的高可用(HA)的问题,就是说当系统故障的时候,可以通过日志重放,恢复到故障前的状态。

2、它实现了HBase的replaction,远程备份功能。具体实现是,当客户端触发一个对数据改动的操作,比如put、delete操作,这些修改操作被封装在一个key-value实例里面,然后通过rpc调用发送给RegionServer,RegionServer接收到调用后,先去写log,再去写Region。从而实现这个远程备份的方案。可以简单的理解为,远程备份其实就是讲log同步到备份的目标机器上去。

》HLog的解析

WAL是通过HLog模块实现的,我们需要对HLog的内在原理做个介绍,便于我们理解HBase日志运行原理。

》HLog是什么?

HLog是实现WAL的类,一个Region Server对应唯一一个HLog的实例,当Region初始化的时候,HLog会作为一个参数,传递给HRegion的构造函数,这样HRegion就获取到了HLog的引用,可以实现日志打印。

》HLog的工作步骤

HLog最核心的是调用它的append方法,完成对日志记录的追加写入。出于对性能的考虑,put、delete、increatement有一个开关函数setWriteToWAL(boolean flag),传递的是boolean类型的值,当设置为false时,则会禁用WAL。HLog通过序列化的number去追踪数据的改变。

》HLogKey

HLogKey其实就是保存了Region+TableName+序列化Number+写入时间的唯一标志,用户的书就在KeyValue中

》HLogSyncer

HLogSyncer是日志同步刷写类,数据是以keyvalue的形式到达RegionServer,写入WAL的操作默认是直接写入到文件系统里面的,有些时候为了性能,会暂时将日志保存在内存中,这时候就需要有个专门负责将这部分日志刷写到磁盘的机制,而HLogSyncer就担此重任。刷写日志有两种方式,一种是达到内存预值时去刷写,另一种是定时去刷写。

》HLogRoller

log的滚动间隔时间可以通过配置文件设置,默认是一个小时滚动一个新文件,所以HBase系统运行一段时间之后,会产生一大堆的log文件需要维护,HLogRooller作为后台线程去运行。

它主要实现了两个功能:

第一、特定的时间去滚动日志,形成新的日志文件,避免单个日志文件过大。

第二、根据HLog的序列化number对比已经持久化的HFile的序列号,删除旧的不需要的日志。

HBase日志体系,总体的模块比较多,但并不复杂,而且实现了HBase非常多的重要特性,这在以后我们自己在设计系统的时候也可以好好借鉴一下。不仅仅追求系统的高效,还要保证系统的高可用。

HBase Compaction(合并)解析

什么是Compaction?

Commpaction会从一个Region的Store中,选择一些HFile文件进行合并,合并的原理很简单。先从这些待合并的文件中读出key-value数据,再按照由小到大排列后写入到一个新的HFile文件中去。之后这个新的文件就会取代之前的文件对外提供服务。

》为什么需要Compaction操作?

随着系统不停的刷写,会导致存储目录中保存过多的存储目录文件,文件太多会导致维护困难而且不利于查找,会大大降低数据查询的效率。所以需要有这样一种文件合并机制,将数据文件由多变少。

假如,你有十个数据文件,如果你想从这十个文件中找出一条数据,那么你需要依次对这10个文件进行打开-关闭的操作。每次对文件进行io的时候是效率非常低的,尤其是打开这个动作非常耗费资源。当我们合并成一个文件时,那么我们就可以节省下来其他9次打开的资源浪费以及时间消耗,从而达到高效查找的目的。

》Compaction的分类

第一类:MinorCompaction

这种合并类型是选取一些小的、相邻的StoreFile,将他们合并成多个更大一些的StoreFile。

第二类:MajorCompaction

1、这种合并类型是将所有的StoreFile合并成一个较大的StoreFile,也就是你Store中不论有多少个StoreFile都无所谓,他只将所有的StoreFile合并成一个大的StoreFile。

2、这个过程还会清理三类没有意义的数据,

第一类:是被删除的数据即KeyType类型为delete类型的数据。

第二类:TTL过期的数据,也将会被删除。

第三类:版本号超过设定版本号的数据,也将会被删除。比如说当你的列族设定版本个数是3,那么当你第四次存放数据的时候,也会保存在系统中,但是当大合并到来的时候,你最早存入的那个版本的数据将会被删除。

一般情况下,MajorCompaction的合并操作耗时比较长,会消耗大量的系统资源,对上层业务有比较大的影响。因此线上业务都会讲自动触发的MajorCompaction功能关闭掉,改为手动在业务低峰期的时候触发。同事这也是一个非常大的系统优化点。

Compaction的触发时机

触发compaction的因素很多,最常见的因素有三种:

第一种:MemStore Flush触发

Compaction操作源头就是来自于Flush操作,也就是内存中的数据Flush到硬盘上。MemStore Flush会产生HFile文件,文件越来越多就需要Compaction。因此在每次执行完Flush操作之后,都会对当前Store中的文件进行判断,一旦文件的数量超过预值就会触发一个Compaction。这里需要注意的是,Compaction都是以Store为单位进行的。而在Flush触发条件下,这个Region的所有Store都会执行Compaction,所以会在短时间内执行很多次Compaction。

第二种:Compaction checker(后台线程周期性的检查)触发

它会定期的触发检查,当前store是否需要执行compaction,它和Flush有点不同的是,这个线程会优先检查文件数是否大于预值,一旦大于就会触发compaction。如果不满足他就会接着检查是否满足MajorCompaction大合并的条件。简单来说,如果当前Store中HFile的最早更新时间,早于某个值,这个值就叫Mc-time,到了就会触发大合并。HBase通过Mc-time这种机制来定期删除过期数据,Mc-time是个浮动值默认取值区间是

[7-7*0.2,7+7*0.2],七天时间进行一次大合并。

7对应的配置属性:hbase.hregion.majorcompaction,如果想要禁用大合并,只需要在这里设置为0即可。

0.2对应的配置属性:hbase.hregion.majorcompaction.jitter

第三种:手动触发

1、由于担心某些线上业务,会受到大合并的影响,因此会选择低峰期手动完成触发。

2、由于开发人员改变了数据表结构之后,希望立刻生效,执行下手动触发MajorCompaction,让数据清理合并下,让业务重新生效。

3、HBase管理员发现硬盘容量不够的前提下,会手动触发MajorCompaction,这样会删除大量的过期数据。

4、HBase的数据存取解析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • 一、存储模式 1.1 行式存储&列式存储 定义 以行为存储基准的存储方式称为行式存储,一行的数据聚合存储在一块; ...
    要记录的Ivan阅读 3,330评论 0 1
  • 一、简介 Hbase:全名Hadoop DataBase,是一种开源的,可伸缩的,严格一致性(并非最终一致性)的分...
    菜鸟小玄阅读 2,382评论 0 12
  • 万法皆生心 迷则诸法不现 悟则法通明 十万八千 法之渐顿 美丑无别 贫富无别唯别根性 近佛法观自心 顿渐亦如饮水 ...
    星星需点灯阅读 128评论 0 0
  • ——龍•茶馆 那是孤山微凉的夏夜 象牙塔灯冷 三不猴萌态可掬 他忍不住 偷看了一眼 海风徐来的裙摆 便迷上...
    龍茶館阅读 91评论 0 2
  • 假期第一天,小宝还是准时六点就醒了,大宝昨晚玩累了,七点才起床,吃饱饭,孩子说去学习,刚写了一张试卷,爸爸说...
    杨锐y阅读 230评论 0 0