HTAP数据库调研

艾木酱
• 阅读 1805

1. HTAP数据库背景及现状

1.1 起源

  • 大型实时分析应用的逐渐流行(实时库存/定价、欺诈检测,风险分析,物联网等);
  • 这些系统需要一个分布式的数据管理系统,要求能处理高并发的TP请求,同时支持对近期的数据进行分析;
  • 有些应用甚至会在TP请求中进行AP操作;
  • Gartner:即有事务又支持分析的系统叫HTAP;
  • 实时分析:指的是实时交易过程中的分析需求,不是数据时效性上的实时。

1.2 方案1:一套系统同时支持OLTP和OLAP

  • 传统的DBMS可以在一套系统上支持TP和AP,但对这两种业务场景都不高效;
  • 基于内存的行存( VoltDB, Hekaton, MemSQL, Silo)和列存( MonetDB , Vertica , BLU , SAP HANA)系统,这些系统开始只是为一个场景专门设计的,后来为了支持HTAP增量了另一场景的支持。

1.2.1 底层数据分开存储

  • SAP HANA 和 Oracle’s TimesTen 最初是为OLAP专门设计的,同时也支持ACID事务操作;不过事务的数据时以行存方式支持的,而分析操作是通过列存支持的;
  • MemSQL最初是为in-memory OLTP设计的,后来也支持分析。对于TP数据是以行存方式存在内存中的,当数据需要写到磁盘中时,会转换成列存;
  • IBM dashDB也是从传统的行存向HTAP演进的系统。通过行列混合的方式来分别支持TP和AP;
  • HyPer是从一开始就为HTAP设计的,最初使用行存来同时支持TP和AP,不过现在也支持通过列存方式来更好的支持AP场景。

1.2.2 底层用一种方式存储数据

  • H2TAP,学术项目,以行存的方式同时支持TP和AP;
  • Hive,SQL-on-hadoop的解决方案之一,AP系统,在0.13版本开始通过ORCFile支持事务,但主要的应用场景是维度表更新以及实时流数据摄取;
  • Impala + kudu:支持SQL分析及数据的更新和删除。 这类系统跟传统DBMS面临同样的问题,没办法同时为AP和TP进行优化。对于采用列存的系统,需要通过批量的方式来提高事务的吞吐能力;对于采用行存的系统,无法实现最佳的分析效果。

1.3 方案2:两套系统来组合来支持OLTP和OLAP

1.3.1 解耦AP和TP的底层存储

现状

  • 需要用户的应用程序自己来协调AP和TP系统的使用;
  • 数据在两个系统之间是通过ETL方式同步的;
  • 这类方案在目前的大数据系统中非常常见,通常使用kv系统(如cassandra)来承载TP负载,然后将数据转换成 Parquet or ORC 文件存储到HDFS中,再使用SQL-on-hadoop方案进行数据分析。

1.3.2 AP和TP共享底层存储

这类系统通常是使用Spark之类的系统,在原有数据上支持大规模分析的场景。由于数据只有一份,因此AP分析的数据是实时数据。

  • SAP HANA Vora:TP业务负载有vora直接支撑,而分析场景则通过Spark-SQL来支持;
  • SnappyData:使用GemFire来承载TP业务,通过Spark生态来支持AP业务;
  • HBase 和Cassandra等kv系统被广泛应用在需要实时更新的场景,而对这些数据的分析场景在通过组合SQL-on-Hadoop的解决方案来实现。TP和AP系统访问的是同一份数据,这需要开发一些额外的扩展,以使得AP引擎能直接读取TP存储中的数据,比如Spark HBase connector,Spark Cassandra connector等。通过connector来进行AP分析通常非常慢;
  • 另外一些SQL-on-hadoop系统,使用HBase作为支持快速更新的存储引擎,如: HIVE, Impala, IBM Big SQL, and Actian VectorH。数据的处理是通过HBase的处理引擎来实现的;
  • Splice Machine 、 Phoenix则是在HBase之上构建了SQL引擎;
  • 基于HBase的AP系统,在处理AP任务时都比较慢,因为在HBase上执行Scan非常慢。HBase适合快速更新和点查的场景;
  • Wildfire:IBM最近开发的一套HTAP系统,使用列存方式来同时支持AP和TP,使用的是Parquet格式。Wildfire可以立即分析最近提交的更新,同时支持使用Spark生态来执行大规模并行分析任务,提交给SparkSQL的请求会被尽可能的下沉到Wildfire引擎来进行数据处理。

1.4. 现状总结

  • 目前没有一个系统支持true-HTAP;

    • 大多数系统已经分别支持了AP请求和TP请求的处理,但是没有系统支持在TP中执行AP的场景;
    • 要支持真正的HTAP,需要支持在同一个请求中既有TP又有AP的场景。 目前大多数系统需要组合各种解决方案来达到HTAP场景的需求,这对用户部署和维护系统带来挑战;
  • 目前大多数TP系统为了加速TP的更新和点查,将索引全部放在了内存中,但是对于更大规模数据的场景,索引全部在内存中会导致TP系统变慢,应当考虑一种仅保留部分索引在内存中的方案,以提高常用数据的访问性能;

  • 为AP场景设计的存储引擎,通常使用对象存储或者共享文件系统来存储数据。这些存储格式主要是为scan场景进行优化,无法提供高效的点查和更新能力。目前这还是一个未解决的难题。

1.5. 设计HTAP系统要做的一些决策

  • Query processing and ingestion engines(数据分析和数据摄取引擎)
  • Storage options (存储方式:一套存储还是混合存储)
  • Data organization (数据组织格式:行存还是列存)
  • Transactional semantics (事务语义)
  • Recency of data being read by OLAP
  • Indexing support(索引支持)

2. HTAP类数据库分析

2.1 TiDB

2.1.1 TiSpark

所属分类

  • 两套系统来组合来支持OLTP和OLAP(采用Spark生态)
  • AP和TP共享底层存储

TiSpark 是将 Spark SQL 直接运行在 TiDB 存储引擎 TiKV 上的 OLAP 解决方案

  • TiSpark 深度整合了 Spark Catalyst 引擎, 可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查
  • 通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划

2.1.2 TiFlash

所属分类

  • 底层数据分开存储,TP采用行存,AP采用列存
    • AP存储在一定程度上属于TP的一个副本,在比较高的层面上来看,可以认为是一套存储同时支持行列
  • 两套系统来组合来支持OLTP和OLAP,TP通过原生的TiDB来支持SQL和事务;AP则通过TiFlash(基于clickhouse开发的向量化分析引擎)来实现
    • 通过动态的SQL路由,TiDB在更高的层面隐藏了AP和TP引擎

技术实现

  • TiFlash 基于列存和向量化分析引擎(Clickhouse)实现;
  • TiFlash 作为 TiDB 的另外一个存储层,通过raft learner从TiDB 复制数据,并保证数据的事务性;
  • TiFlash目前不支持SQL直接写数据,因此其角色目前不能成为leader或者follower;
  • TiFlash节点如果发生故障,需要从TP集群重新同步数据;
  • TiFlash作为TiDB的扩展,属于TiDB集群的一部分;
  • 通过全局时间戳来保证用户从TiFlash中读到的是最新的数据;
  • 通过LSM-Tree来解决列存的更新带来的写放大问题;同时利用其局部有序性来解决AP场景对scan的需求;
  • 可以通过动态增减不同类型的节点来增减,TP或AP能力;
  • TP节点和AP节点在系统层面有不同的标签,当启发式算法任务用户下发的SQL是一个AP运算时,会将请求路由到AP节点上执行。在一定程度上隐藏了AP和TP的具体角色分配;
  • 一条join语句的两部分数,一份数据需要全表扫描、另一份可以利用索引,则可以分别将这两个子查询调度到不同类型的节点上执行,一部分利用TiFlash的scan能力、一部分利用TiKV的点查能力。

后续计划

  • 支持SQL直接更新TiFlash中的数据
  • TiFlash支持MPP,从而可以将TiDB或TiSpark的一部分计算下推到TiFlash执行
  • 重新设计TiFlash的存储引擎,从而将性能提升2倍(目前TiSpark+TiFlash的性能,与Spark+Parquet的性能差不多)

TiKV 对应yugabyte的TabletServer(即DocDB),定位和实现框架几乎差别不大,都是在实现一个支持事务的分布式kv。TiKV是一个单独的项目,更解耦(意味着性能要差)。

  • 都是提供RPC接口
  • 都是Raft
  • 都是基于rocksdb

2.2 MemSQL

2.2.1技术细节

所属分类

  • 一套系统同时支持OLTP和OLAP
  • 底层数据分开存储

技术实现

  • completely in-memory rowstore(行存,全部在内存中,为TP/HTAP服务,主要针对实时场景)
  • disk-backed columnstore(数据写到磁盘时,改成列存,为AP以及需要查询大量历史数据的HTAP应用服务)
  • 一条查询语句可以同时查询内存和磁盘中的数据
  • 也支持内存无法承载情况下的OLTP任务(使用hash indexes)
  • 主从复制模式,支持同步和异步。同步会导致写延迟变高,异步复制则从节点数据落后一段时间
  • 没看到如何实现列数据的更新的(MemSQL开启了列存的表不适合频繁更新的场景<参考>)
  • MVCC + lock free 充分发挥内存的性能
    • 每当事务修改一行时,MemSQL都会创建一个新版本,该版本位于现有版本之上。该版本仅对进行修改的事务可见。Read查询访问同一行,“查看”该行的旧版本;
    • MemSQL仅在同一行发生写-写冲突的情况下才使用锁;
    • MemSQL为死锁实现了锁等待超时。默认值为60秒;
    • MemSQL将已修改的行排入垃圾收集器。通过避免全表扫描,垃圾收集器可以非常有效地清理旧版本;
    • MemSQL尽可能将单行更新查询优化为简单的原子操作;
  • skip list 代替btree,以提供更好的扩展性(skip list可以实现lock free访问,更适合纯内存场景)
  • code gen,提高SQL查询性能
    • 将SQL编译成C++代码,然后用GCC编译成native code,动态加载到MEMSQL进程。该过程是在SQL首次执行时进行的,并且编译后的代码重启后仍旧有效;
    • 编译后的结果会被存储到hash表中,下次如果有相同模式的sql请求,直接使用编译后的代码执行。
  • CPU效率意味着更高的吞吐量。由于MemSQL每个查询使用较少的指令,因此它们可以实现更高的吞吐量
  • 无锁数据结构扩展性好,同时也减少了数据争用期间导致的CPU浪费。MemSQL引擎的每个组件都建立在无锁的数据结构上:链表,队列,堆栈,跳表和哈希表
  • 内存数据持久化:定时快照+WAL
    • 事务首先提交到内存缓冲区中,然后异步开始写入磁盘。日志刷新器线程每隔几毫秒将事务刷新到磁盘一次,通过批量提交来提高磁盘IO吞吐;
    • 当日志文件达到已经大小时(2G),会压缩成快照。快照更紧凑、恢复更快;
    • MemSQL完全避免了页面交换,并且可以保证在读/写查询上具有一致的高吞吐量SLA。MemSQL中的任何读取查询都不会等待磁盘。此属性对于对数TB的数据进行实时分析扫描极为重要。
  • Aggregator:专门的聚合节点,类似Gateway,负责接收用户的查询请求,将请求调度到leaf节点,对查询结果进行聚合,返回最终结果给客户端。根据系统负载,可以配置任意数量的Aggregator节点
  • 对于开启了列存的表,数据也会先写到内存中的面向行的skip list中,然后批量往列存中刷;只要数据写到内存skip list中,对客户端就是可见的

特性&定位

  • 支持从各种数据源(文件、kafka、数据库、S3、HDFS)load数据
  • 可以在一条语句中对实时数据和历史数据进行操作
  • Full SQL. MemSQL supports full SQL and transactional semantics.
  • 只支持READ COMMITTED隔离级别
  • 支持冗余和持久化
  • 面向高并发、高吞吐、小事务的场景
  • 面向需要使用MEMSQL赚钱的场景:因为纯内存架构比较昂贵
  • 解决实时需求,能回答当前正在发生什么事情的场景
  • 提供实时分析功能,如:min、max、distinct、average
  • 不是和BI场景
  • Write-heavy, read-heavy workloads:Machine data、Traffic spikes、Streaming data

2.3 HyPer

简介

HyPer最开始是一个学术项目,产出了不少最新的研究成果。目前已经被收购。

3. 其他数据库

kudu HTAP: 放弃事务,只保留TP系统的高性能点查、插入特性;列存:提高OLAP的性能

参考资料

Hybrid Transactional and Analytical Processing - A Survey https://blog.csdn.net/tidb_pingcap/article/details/76178413 https://blog.csdn.net/TiDB_PingCAP/article/details/100201889 https://docs.memsql.com http://www.hyper-db.de/

MemFireDB,带你体验不一样的云端飞翔。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这