HBase有合适的SQL层吗?
问:单机kv基础上做分布式kv再做SQL计算,为什么不在已有的HBase基础上再做SQL层呢?
无论在单机kv之上,还是在分布式kv,增加SQL层,从目前的涌现出的技术栈来看并不是难事,例如:Hive,Impla,Presto和Spark SQL。
另外你提出:为什么没有基于HBase之上的SQL层?这是错误的观点,上述SQL引擎都可以作为HBase的SQL层。
但是作为关系型数据库,支持多表事务,的确基于HBase没有很好的解决方案。
首先目前HBase的事务是针对单机Region Server的单表行级事务,也就是客户端一次请求,会将多笔记录作为一条日志针对一个Region进行处理,成功则写入MemStore,失败则WAL回滚,所以事务操作并不复杂,但是若要在一次事务中实现多表写入,多机Region一致性协同,这在HBase设计之初并没有考虑。
因此,若按照目前HBase的设计,写入不同HRegionServer,再写入不同Region的MemStore记录,包括各个WAL的记录,必须保证一致性,这就是Region分布式一致性的第一难,必须要有集群一致性机制,例如PaxOS或者Raft,可是HBase没有,只有一个简单的Master解决Region分片后的迁移平衡问题。必须要具备表表之间,列簇之间的ACID特性,HBase并没有设计此处,他的Master和Region Server在这些问题上基本没有任何前期预留的分布式扩展机制。
其次每次事务必然会有多次查询请求,如果用TPS代表事务吞吐,那么QPS就代表了一次TPS内可能涉及数百次的查询,我们可以忍受1秒1个事务操作,但是查询不行,每次查询必须能在毫秒内完成,甚至更短周期,那么这就存在优化问题了,如果查询是热点数据在MemStore或者BlockCache中,这还好说,但是在多个HFile的磁盘中扫描这就慢了,例如:HBase的LSM-Tree的删除和更新都只是一条新记录的标识,这种用空间换取写入性能的设计,另外的副作用就是增加查询量,过期数据在查询中都扫描出来,由扫描器自己去过滤。那么为了解决查询问题,就必须加大内存和使用固态磁盘来解决查询速度,这就是第二难,实际上HBase类LSM树的查询机制复杂度远高于写入,而且提升基础资源成本改善性能并不具有普适性,这就是另一个问题了!
或许LevelDB,Rocksdb,这些轻量级的kv的查询性能比起HBase会更适合事务单元内的高密度kv查询,但HBase还是倾向于大吞吐kv写入和热点数据查询用于支撑实时流处理过程的流库连接。因此我认为HBase要是考虑在未来支持分布式RDBMS,必须得彻底升级Master服务支撑Region Server的分布式一致性,并且实现跨表的ACID特性支持,最后就是Region级别的读优化。
HBase适合大规模数据查询吗?
问:10亿左右的数据量,Mongodb可以胜任吗,还是说需要使用HBase这种数据库,我主要是对查询速度有点要求,大部分查询都是模糊查询,对一个很长的字符串,找到与目标关键词匹配的的一句话,另外我用的语言是node,感觉不知道怎么选?
如果你的主要需求是查询,那么HBase显然不符合你的需求,因为HBase擅长于写多读少的场景,它的Region结构主要是面向列簇在Memstore中也就是内存中缓冲写入的近期数据,然后定期定量刷新到磁盘上,这种机制非常有利于高速写入,在查询上查询近期热点数据的优势很明显,从Memstore中查询近期数据,从专门用于缓存的BlockCache中,查询热点数据,因为它基于LRU机制。
但是作为模糊查询这就有问题了,模糊查询的效率关键在于二级索引,但是HBase的设计主要是通过行键实现列簇下,面向一级索引的LSM-Tree结构,配合布隆过滤器,实现高效的数据扫描匹配。模糊查询往往需要借助Mr或者Spark计算引擎来实现,因此非常不适合模糊查询的需求。
相比较下,MongoDB更适合你的需求,它具有和传统数据库一样的,构建在B树索引之上,具有成熟的字段二级索引,非常适合模糊查找,但是MongoDB对于集合join关联查询并不行,往往需要文档嵌套结构或者多次文档查找来解决,因此关键看你的需求这种文档关联的查询是否多,如果不是很复杂的关联,那么MongoDB的集合分片shard可以更好的对十亿级数据集合进行切分,分布在不同的副本节点上,通过路由器实现多点查询,单点聚合,那么十亿级数据的模糊查找问题不算大。
关键是看MongoDB关联操作的复杂性有多大,是否影响查询效率。要是特别复杂的业务关联查找,最好考虑优化MySQL分区或者PostgreSQL并行这种单机模式是否能快速查询解决,或许查询效果会更好,再或者考虑TiDB这种分布式关系数据库来解决。
HBase是如何保证缓存与文件的写入一致性?
问:高并发场景下,怎么保证缓存和数据库的数据一致性?具体解决方案是什么?有哪些框架?具体怎么实现?
你的问题我认为特别符合HBase的特性。从一致性角度根子上不适合MySQL+Redis的组合模式。
首先我们说数据库针对高并发的场景最有效的手段:有效缓存和并行性,有效缓存就是客户端实时、持续的读写都可以在缓存中完成和命中,那么就不需要依赖磁盘I/O,没有磁盘的约束,就可以提升数据服务的吞吐量,这一点对于数据读写并发非常重要。
其次就是并行性,并行处理我们可以在单台多核完成,也可以在多台分布式完成,当内存有边界的情况下,当然通过分布式形成多个业务表的并行读写,这样针对大量并发产生的内存存量,效果肯定是最好的。
那么我们回到开头看提出的答案HBase。它的内部针对写入数据主要是MemStore来缓存,另外WAL负责顺序记录写入日志,作为写入过程中出现内存数据丢失的数据恢复,由于WAL是顺序写入HDFS,其磁盘I/O性能是远远胜于索引结构的数据表,可以承载更大限度的数据吞吐。
如果是高并发的读写,就近时间形成的热点数据的读写场景会很常见,HBase基本上在一个Region满128M内存存量之前都可以在MemStore缓存中完成最近数据的读写。如果不是最近数据,但仍是频繁访问的热点数据,那么由另外一组缓存BlockCache基于LRU算法专门提供热点数据的查询。因此针对高并发,我认为HBase是满足就近和热点数据实时与高并发的读写。
但是一定注意时间跨度大,又极为随机的查询,并不适应HBase,因为HBase是基于LSM-Tree和SSTable,层层叠加的数据排序文件,并不适合跨大范围的随机扫描查找。
再就是并行性,HBase通过分布式形成HRegionserver集群,数据表被切分成Region,类似于自动对MySQL进行了分库分表,那么对每个范围的Region数据进行读取就能通过HRegionServer来分解单表的压力。若业务表很多,分解在不同的HRegionserver来支持各自表的读写,肯定比放在单机要好的多!
我们再说一致性,只要提到高并发的缓存系统我们往往想到了Redis+MySQL的组合套装来解决,通过Redis来防止MySQL穿透,可是问题在于Redis和MySQL的数据复制,是建立在记录的异步传输过程,如果采用程序打成强制性同步,那么就等于Redis拖着MySQL走,这种情况不如不用Redis,所以理想的一致性是达不到的,但是对于秒杀,抢票这些场景,异步延时这是无法忍受的,会产生严重的业务数据的错乱。
但是HBase就不同了,它的一次写更新事务一定是在一个HRegionserver上的一个Region上的一组行级数据提交,不存在一次写过程的异步传输,也就说如果你能将业务的一次读写控制在行级事务范围,完全可以考虑使用HBase来解决一致性,也就是用简化的业务模型来交换高性能写吞吐兼备数据一致性,等承载完业务的实时部分之后,再异步的将结果从HBase中取出,慢慢形成复杂的关系模型这个思路。
HBase之所以能形成缓存和磁盘I/O的一致性,就是因为面向Region的StoreFile(也就是Hadoop HDFS的HFile)并不直接参与事务,所有事务都是在MemStore和WAL中配合完成,而且memstore与StoreFile的Flush不是针对一条记录的,而是针对一次128m或者定时刷新MemStore数据量,在Flush的过程中,HBase会保证一致性,这时候会存在短暂的刷盘导致的写请求堵塞,但是只有这样,才能从大吞吐的角度照顾到大多数时间的高速写入缓存,以及保证缓存向磁盘持久化过程的一致性!
全局唯一ID在分布式系统中用来做什么用?
问?这个全局唯一ID用到哪些场景中呢? 为什么有些公司 还要单门的 有服务器 提供生成全局ID的服务呢?使用UUID不行吗?想不通为什么要写一个单门的功能。unique id 到底有哪些用途?
我就拿HBase给你举个例子吧。
HBase是分布式数据库,由多台regionserver组成的集群存储许多region,每个region我们可以理解成数据表(列簇)的一个切片。
我们对HBase的数据表(列簇)理解为一张Excel表,Excel表的特点就是列可以非常宽,我们称之为宽表,而且不同行的某些列值可有可无,这就形成了稀疏表。
表行列如Excel般灵活,那么HBase作为数据库是如何做到的呢?它实际上是存储了一个个独立且原子级别的单元格,就是K/V存储单元,不同K/V之间并没有类似关系型数据库的主外键关联,这样就保证了足够的灵活性的基础。
好,现在谈到关键问题,HBase是怎么让K/V形成行列的逻辑上的关联形式呢?答案就在于K/V中的主键,这就是题主所疑惑的分布式系统为什么还要用独立设计的主键而不是UUID,原因就在于独立设计的主键是有语义的!
主键由行键、列簇名、列名、时间戳等组成了分布式数据库的唯一主键,HBase基于自己的region写入机制和分片机制,始终保持了表(列簇)的K/V单元在所有regionserver上按照主键顺序的,有范围的region存放。
这种顺序规则就是对主键逐次排序:行键排序->列簇名排序->列名排序->时间戳排序,大家看到没有,就是这么一个排序策略,就非常容易的让查询按行键(一行)过滤需要的K/V,再按列簇过滤,那么就拿到了一行多列了,而且每一列可能还有多个历史K/V(通过时间戳已经排序)。
看到了吗?优秀的主键设计的威力就是这么强,无论你的数据在哪台服务节点上,主键来解释你的数据属于整体上的哪个位置。
HBase 的原理更像是Mysql 读写分离还是分库分表?
问:此时有10000个客户端在一瞬间同时发起 10000次写 write 请求(共一亿),那这一亿个请求在同一时刻是发给“十个 slave 中的某一个 server” (一个有难,九个围观)还是分给“十个slave server 一起来处理”(有难同当)?
首先要确定这10000客户端是不是朝一个列簇写?若不是一个列簇,那么就相当于给多个列簇下的region写数据。那么就可能涉及多台server参与写数据。
在同一时刻,每个列簇只会有一个region服务于写入。
核心机制是:一个region在写得足够大,超过设定阈值后就会拆分(split),拆分后的region会分配到新的sever,不断拆分,会逐渐将其他9个server都分配到region。
但是拆分的region是按照行键顺序进行排列的,对于region分布满十台server的列簇来讲,在这种情况下,始终会是一个server负责写进region,这十个server会根据自己的行键范围负责读。
因此对于多个列簇,正好不同列簇中负责支撑写入的region分布在不同的server上,那么这就类似于分库分表。
对于一个列簇中多个被拆分的region,分布在不同的server上,那么只有一个region支撑写,所有的region支撑不同行键范围的读,因此就类似于读写分离。