数据库 | 描述 |
---|---|
Greenplum | 开源大规模并行数据分析引擎。借助MPP架构,在大型数据集上执行复杂SQL分析的速度比很多解决方案都要快。应用广泛。 |
Teradata | 大型数据仓库系统,产品成熟,价格昂贵。用于证券系统。 |
Presto | 分布式SQL查询引擎, 专门进行高速、实时的数据分析。本身不存储数据,但是可以接入多种数据源。擅长对海量数据进行复杂的分析。用于大数据量分析。 |
Clickhouse | 用于在线数据分析。支持功能简单。CPU 利用率高,速度极快。用于行为统计分析。 |
master host:负责与客户端对接, 不包含任何用户数据,使用postgres数据库内核,保存有元数据,与segment 由局域网通讯。
segment:存放数据,监听master的连接,用户只能通过master访问,是独立的PostgreSQL数据库。一个节点可运行多个segment实例
Interconnect:协调进程,由局域网互连,支持TCP or UDP
Hadoop | MPP |
---|---|
非结构化数据,半结构化数据 | 关系数据 |
海量数据存储查询、批量数据ETL、日志分析、文本分析 | 多维度数据自助分析、数据集市 |
设立Standby 节点复制master的系统目录表日志( catalog tables )
master坏掉时需由管理员触发激活standby成为新master。
使用基于预读日志(WAL)的流复制来保持primary master和standby master服务器同步。
gather | broadcast | redistribution |
---|---|---|
每个节点数据发至master节点 | 表数据分布在各节点上,需每个节点发数据至每个节点,使每个节点都拥有表的完整数据,适用于小表 | join与group by时,广播代价大时可按键重新将各节点数据打散至各节点再对每个节点操作,适用于大表 |
行存储 | 列存储 | 外部表 |
---|---|---|
多列更新快 | 一次只访问几个字段,压缩比高 | 数据库只保留元数据信息 |
事务型数据库用锁机制控制并发访问,greenplum用多版本控制保证数据一致性。最大的好处是读写不冲突,读的是snapshot。
每个节点物理上是一个SMP处理单元(多CPU计算机),节点硬件包括CPU、内存、磁盘、网卡、BYNET端口
网卡:与IBM MainFrame连接的Channel Adapter;局域网网卡。 一个节点上只会使用一种网卡,但会有多块网卡,分别用于不同的连接和冗余。
CLI( call level interface ):请求响应、创建session、缓冲区分配、信息打包
TDP( teradata director program ): 运行在客户端系统:session初始化终止、登陆、验证、恢复重起、现有人员传递至PE的 session 队列
MTDP( micro TDP ):与TDP的区别是不负责session在PE间分配。
MOSI( micro operating system interface ):实现不同数据库平台上运行的隔离层
session control:主控logon、logoff
**parser:**解析sql,判断语法语义正确性,查询字典确认请求对象是否存在,用户是否有权限
**optimizer:**评估执行计划,转为AMP可执行步骤
**dispatcher:**分配AMP 所选任务,返回用户结果
MPL 层负责 PE 与 AMP之间传送信息、合成的返回结果集传 PE,由 PDE 与 Bynet 软硬件组成
PDE (parallel database extension):
bynet软件、硬件:
AMP(access module process)
ShareNothing架构的核心。
一个AMP最多控制 64个物理磁盘 (对商用OLTP来说,主要由DBA控制记录在磁盘的分布)
hash算法类似矩阵映射,修改AMP数时只需变动hashmap,速度非常快。
每个AMP可并行处理80个任务
AMP功能:
存储数据根据哈希算法被均匀分散存储到磁盘阵列中的不同的磁盘上。RAID0 与 RAID5 为主。因采用混合均匀存储而不存在数据库重组问题。
查询并行:每个AMP作为一个虚拟进程,独立处理一部分数据(如查询一个表)
步内并行:每个运算步骤都由多个进程并行处理(如借助于pipline的 join操作)
多步并行:优化器分解sql请求原则是尽可能使各步独立(如两个表的查询同时进行)
传统 OLTP 对于提出的新的问题,DBA 会建立一条新的索引,可能使数据库占用磁盘空间过大。而 teradata 采用将相同执行步骤的执行结果暂存于系统缓冲区的方法, 减少数据库本身的大小。
teradata 提供的并行 OLAP 操作有:排序、累计、移动平均、移动和、移动养分、采样、分位、限定
teradata 在解决 hash 函数范围查询需要访问所有数据的问题时引入用户索引(分区主索引PPI),将数据按索引进行分区
引入角色来分配权限
引入用户参数为用户配置持久空间(分配的最大存储容量)、spool空间(存放中间过程与最后结果 )、临时空间(存放global temporary table被实例化的数据)限制、缺省数据库设定、用户密码设定
AMP分组:对一个操作只使用部分amp单元进行处理,提高数据吞吐量
利用稀疏索引来去除大量空值索引
解析器与分派器合为一
增强插入更新能力
引入合并更新
对于unique key 元组在各磁盘分布
对于none-unique key 元组按key分布
次索引一般没有必要,taradata本身性能很高
排它锁(create table):拒绝任意锁
写锁(update):拒绝read、write、exclusive
读锁(select):拒绝write、exclusive
访问锁:只拒绝排它锁(用于积累大量行数据,但结果可能不是最新结果)
presto是facebook为了改进之前基于map-reduce的hive框架查询数据仓库时间过长而开发的数据分析工具。Presto本身不是数据库,而是分布式查询引擎。Presto可以访问HDFS,及其他数据源,数据库。但不能处理在线事务。
Presto被设计为数据仓库和数据分析产品:数据分析、大规模数据聚集和生成报表。这些工作经常通常被认为是线上分析处理操作 。
采用 master - slave 模型:
**coordinator:**master,负责meta管理,worker管理,query解析与调度
worker: 计算与读写
discovery server: 通常内嵌于coordinator节点中,也可以单独部署,用于节点心跳。
catalog:一类数据源,如mysql,hive
schema:数据库
table:表
存储单元包括 page,block:
page:多行数据集合,包含多列,但只提供逻辑行,实际以列存储
block:一列数据
array类型 int 、long、double
可变宽 string
固定宽string
字典(distinct值较少)
**sql 查询:**http POST 请求
**抽象语法树:**以 query 为单位,分层表示子查询
**逻辑计划:**将抽象语法树转为最简单操作
优化器:
**调度器:**以exchange节点划分的段为单位进行调度
物理执行计划:
source类型的operator ,每一次调用都会获取一份新的数据;对于Aggregate的operator,只有之前所有的operator都finish之后,才能获取输出结果。
聚合计算有两类
聚合计算均提供四个接口用于在map-reduce之间加一层计算,接受中间结果输入输出。
接受原始数据的输入
接受中间结果的输入
输出中间结果
输出最终结果。
函数分两类:
Scaler函数:数据的转换处理,不保存状态,一个输入产生一个输出。
Aggregate函数:数据的聚合处理,利用已有状态+输入,产生新的状态。
内存池:
为了防止大任务分配到每台机器后一部分(在该机器是最大内存的任务)在reserve pool执行完成,另一部分(在该机器不是最大内存任务)在general pool等待执行,造成死锁,presto将最大query分配给reserve pool的任务交给coordinator去做(虽然这会造成一部分不执行这个query的机器reserve pool 浪费),而不是让每台机器把最大query任务在reserve pool执行。
cordinator计算query的每个task的内存大小,同时有一个线程定期轮训每台机器内存状态,汇总query内存与机器内存后, coordinator会挑选出一个内存使用最大的query,分配给Reserved Pool。
传统 sql 优化
完全基于内存的并行计算
流水线
本地化计算
动态编译执行计划(如循环展开优化): 使用Google Guava提供的LoadingCache缓存生成的Byte Code。
小心使用内存和数据结构
使用Slice进行内存操作,Slice使用Unsafe#copyMemory实现了高效的内存拷贝,
类BlinkDB的近似查询
为了加快avg、count distinct、percentile等聚合函数的查询速度, 引入了一些近似查询函数approx_avg、approx_distinct、approx_percentile。approx_distinct使用HyperLogLog Counting算法实现。
GC控制
Presto团队在使用hotspot java7时发现了一个JIT的BUG,当代码缓存快要达到上限时,JIT可能会停止工作,从而无法将使用频率高的代码动态编译为native代码。
Presto团队使用了一个比较Hack的方法去解决这个问题,增加一个线程在代码缓存达到70%以上时进行显式GC,使得已经加载的Class从perm中移除,避免JIT无法正常工作的BUG。
Presto TPCH benchmark测试
扩展性
clickhouse本身不扩展,可借助Distributed引擎(本身不存储数据)
写:
指定哪些数据写入到哪些节点里
通过一个节点写,数据分到不同的节点里,通过指定分片的key来分发数据。
数据写入是异步的,对于插入数据到集群的其他节点,数据先是写入到本地磁盘,然后在后台发送到其他分片服务器,如果想查看数据有没有同步完,可以检查下面的目录:/var/lib/clickhouse/data/database/table
读:
可靠性
依赖于zookeeper,使用物理复制
数据始终以列存储,包括矢量执行过程。
有两种不同的加速查询处理的方法: 矢量化查询执行和运行时代码生成
clickhouse是列存储数据库,使用向量查询技术,select,orderby,limit操作都不改原列向量,而是新建。适合少修改的数据。
clickhouse使用抽象渗漏提高速度,使列的数据与数据类型、数据块处理分离。
查询流水线每一步中间数据都保存,临时数据要适合CPU缓存。
对于分布式数据不完全支持join这样的复杂查询。
ClickHouse 使用稀疏索引,不适合高负载的点状查询。
ClickHouse 不依赖Hadoop 生态
不支持事物,不支持Update/Delete操作
向量化引擎:数据不仅按列存储,而且由矢量 - 列的部分进行处理。这使我们能够实现高CPU性能。
允许在运行时创建表和数据库,加载数据和运行查询,而无需重新配置和重新启动服务器。
它的数据剪枝能力比较强,分区剪枝在执行层,而存储格式用局部数据表示,就可以更细粒度地做一些数据的剪枝。它的引擎在实际使用中应用了一种现在比较流行的 LSM 方式。
它对整个资源的垂直整合能力做得比较好,并发 MPP+ SMP 这种执行方式可以很充分地利用机器的集成资源。它的实现又做了很多性能相关的优化,它的一个简单的汇聚操作有很多不同的版本,会根据不同 Key 的组合方式有不同的实现。对于高级的计算指令,数据解压时,它也有少量使用。
ClickHouse 是一套完全由 C++ 模板 Code 写出来的实现
不支持Transaction
使用了矢量化查询执行
提供了有限的运行时动态代码生成(group by的内部循环第一阶段)。
**联机事务处理( OLTP)**由业务数据库所支持,数据固定,操作负载少,强调数据库一致性与可恢复性。
**在线分析处理(OLAP )**由数据仓库支持,反应历史数据、多来源数据,通常多维建模,典型的OLAP操作有:上钻(聚合)、下钻(展开)、切割(选择和投影)、轴转(多维视图)。
OLAP的查询问题有不确定性。
OLAP数据库最关键的两个因素是:并行处理与可扩展性
ROLAP(关系型OLAP):在标准的或扩展的关系DBMS 上,支持扩展SQL和特殊访问
MOLAP(多维OLAP ):直接把多维数据存储在特定的数据结构
shared everything(SMP):网络与磁盘是瓶颈(SQLServer)
shared disk(NUMA): 存储器接口达到饱和的时候,增加节点并不能获得更高的性能 (Oracle Rac)
shared nothing(MPP): 各自处理自己的数据,可扩展,成本低
● 任务并行执行;
● 数据分布式存储(本地化);
● 分布式计算;
● 私有资源;
● 横向扩展;
● Shared Nothing架构。
(1)无master 高平结构
(2)可处理 PB 级数据,采用 hash 分布、random 策略存储,采用先进压缩算法
(3)高扩展,支持集群扩容缩容
(4)高并发:读写不互斥,可边加载边查询
(5)行列混合存储
数据组织实现:
不同于普通段、簇、页管理,采用HTS(huge tablespace)相当于文件系统。
HTS -> SCH模式目录 -> TAB表目录 -> COL列(.dta文件,默认64M)-> 区(存储行数在一开始就指定,开始位置4k对齐)
辅助表:管理HTS中数据,每条记录对应一个区,查询在辅助表进行
智能索引:
一定程度上可以替代BTree索引,最大最小值可起到过滤作用
自适应压缩:
字典编码
异常值( 少数不同时, 异常值使用<行号+值>的方式存储 )
RLE编码(数据大量相同,每个值个数较均匀)
序列编码(存在代数关系时,可只存与共用基础数值的差值,)
自适应的步骤:
以 RAID1 与 RAID5 最常见
JBOD | 磁盘直接串连 |
---|---|
JBOD | 磁盘直接串连而成的磁盘柜 |
RAID0 | 无冗余分布存储 |
RAID1 | 镜像冗余 |
RAID2 | 海明码校验,4个磁盘存数据分布存储,3个磁盘校验,实际很少用 |
RAID3 | 至少三数据盘分布存储(按位分布或按字节分布),一磁盘校验,适用于大容量分散顺序访问。RAID3在有坏盘时性能下降,常由RAID5代替 |
RAID4 | 同RAID3,但按块分布,读性能好,写性能差,实际少见 |
RAID5 | 同RAID4,校验数据分布在各磁盘,不存在RAID4的写瓶颈,目前最佳方案 |
RAID6 | 上面只保护单个磁盘失效,RAID6为双重校验(可在两个磁盘用两种算法存不同的校验数据),写性能差 |
RAID00 | 双重RAID0 |
RAID01 | 先镜像1再条带化0,保证数据安全性的同时又提高了性能 |
RAID10 | 先条带化0再镜像1,保证数据安全性的同时又提高了性能 |
RAID30/50/60 | 提高性能 |
RAID7 | 一套事件驱动的操作系统,采用非同步访问减轻写瓶颈提高IO,自动读写优化 |
RAID-DP | 采用NVRAM存储写数据,掉电也不丢失,集中写,采用RAID6,性能比RAID4下降小于2%,固件实时更新时也不中断 |
RAID5E | 提供冗余盘,在一块磁盘损坏时自动降级至RAID5,时间较长 |
最大的特点就是写入速度快,主要利用了磁盘的顺序写
LSM-tree 主要针对的场景是写密集、少量查询的场景。 被用于各种键值数据库
lsm-tree 的一种实现 LevelDB:文件分三种,内存中有memtable,immutable,磁盘中有SStable(sorted string table)写会写入memtable,当达到阈值,就把immutable合并入磁盘并把memtable转为immutable。
Topic 和 Partition
在 Kafka 中的每一条消息都有一个 Topic,Kafka 为每个topic维护了分布式的分区(Partition)日志文件, 发布到此 Partition 的消息都会被追加到 Log 文件的尾部,由offset数组记录消息位置。保证partition下消息有序,但topic下消息非有序
消费模型
Kafka 采取拉取模型(Poll),由自己控制消费速度,防止基于推送(push)因消费进程挂掉或网络不好导致的消息丢失
网络模型
多线程的 Selector 模型 : Acceptor 运行在一个单独的线程中, 读取操作会在 Selector 注册 Read 事件。 成功后,将请求放入 Message Queue共享队列中。 写线程池中,取出这个请求,对其进行逻辑处理。
这样,即使某个请求线程阻塞了,还有后续的线程从消息队列中获取请求并进行处理。
在写线程中处理完逻辑处理,由于注册了 OP_WIRTE 事件,所以还需要对其发送响应。
依靠的是副本机制,就算机器宕机也不会数据丢失。
Producer 向 Leader 发送数据时,可以通过 request.required.acks 参数来设置数据可靠性的级别:
• 1:默认选项,producer收到一次确认即完成。
• 0:无需确认
• -1:ISR 中的所有 Follower 都确认接收到数据后才算一次发送完成,可靠性最高。
(ISR = Leader + 较新副本)ISR可用于替代leader
AR(Assigned Replicas) = ISR + 老副本
确认模式 | request .required .acks | 描述 | 特点 |
---|---|---|---|
al-least-once | 1 | Producer 收到来自 Ack 的确认,则表示该消息已经写入到 Kafka 了 | Producer 超时或收到错误,重试发送消息,可能导致消息写入两次 |
at-most-once | 0 | 发送后无需确认 | |
exactly-once | -1 | 保证消息最多一次地传递给 Consumer | kafka实现:每个producer向特定topic的特定partition维护一个序号,每次broker收到消息都要求producer序号比自己的大1 |
Kafka 中事务实现 exactly-once 语义。
每个 Partition 其实都会对应一个日志目录,在目录下面会对应多个日志分段(LogSegment)。
LogSegment 文件由两部分组成,分别为“.index”文件和“.log”文件,分别表示为 Segment 索引文件和数据文件。
由于 Kafka 消息数据太大,如果全部建立索引,既占了空间又增加了耗时,所以 Kafka 选择了稀疏索引的方式,这样索引可以直接进入内存,加快偏查询速度。