1,麒麟采用预计算的方式,将想要的结果每天预先计算好,放到hbase里存储,这种方式 比较适合 我确切知道明天将会查询什么,知道哪些指标是明天需要的 。很多时候,我们并不知道,明天要看什么,只有事情真发的发生了我才要知道看什么,而且我们也没办法预先将每种结果的组合都预先计算好, 而ydb并不是采用预计算的方式,ydb里面存户的数据都是数据明细,想要查询什么,想要查询那个维度,都是现算的(adhoc),这样比较灵活,适合探索性的分析
2.由于麒麟是预计算模型,通常来说也是离线的,而YDB数据从产生,到最终可见是几秒到2分钟之间,时效性会好点。
二、与druid的区别
本质上druid的宣传文档,确实,稍微改个名字,就可以作为延云YDB的宣传文档来使用。但是两者技术的实现有非常大的差异
1.druid本身也是预计算,数据需要按照固定的粒度预先计算好,查询的时候无法实现 访问原始数据,只能看预先计算好的,而且同麒麟一样查询的灵活性有限制,无法做任意维度的组合查询。YDB则可以。
2,druid在启动的时候会将数据从hdfs上下载到本地硬盘,这个过程需要较长的数据下载时间,每次集群扩容,或机器硬件损坏后的恢复,都需要重新下载相应的数据,几亿数据还好,可能1~2个小时就下载完了,如果数据量很大,如一台机器要下载几十个T的话时间会很恐怖的,但是druid有冗余的机制,宕了一台机器,冗余可以补上,但也意味着双倍的机器。 ydb的数据只存储在hdfs上,不会下载到本地,不存在这个问题。 3,Each Historical node has a startup time to memory map all the segments it was serving before the update. The startup time typically takes a few seconds to a few minutes, depending on the hardware of the node.
ydb则采用按需读取的方式,启动很快,用到哪些数据就读哪些数据,不用则不读,也不加载。 YDB可以用10台机器 跑1100亿的索引.
三、与Pinot的区别
四、与Hive, SparkSQL, Flink的区别
社区里大量涌现的SQL on Hadoop方案,以Hive, SparkSQL, Flink为代表,这类系统的特点是计算和存储相分离,针对存储在HDFS上的文件提供标准SQL功能,他们在部署性和易用性上可以满足企业客户需求,业务场景上也能覆盖扫描,汇聚,详单等各类场景,可见可以将他们视为一类通用的解决方案。为了提高性能,Spark,Flink等开源项目通过不断优化自身架构提升计算性能,但提升重点都放在计算引擎和SQL优化器的增强上,在存储和数据组织上改进并不是重点。所以这类系统大部分的都是通过纯粹的暴力扫描+分布式计算来提升批处理能力,比较适合低时延查询要求,对即席查询并不适合。
三.ya100这个格式压缩效率如何
根据数据的重复程度的不同,压缩比也不同,通常来说是原始文本文件的0.8倍 。
四,是否支持多表JOIN
本身YDB与ya100自身没有JOIN功能,但是由于与spark做了结合,JOIN功能是采用SPARK的join来实现的,join性能取决于有多少数据最终抛出交给了spark。数据量越大,计算量以及数据迁移成本都很大,也意味着性能越低。所以在使用join前,能通过ydb过滤掉的尽量先过滤掉。
五, spark升级迭代对ydb的影响
ydb与ya100没有更改过一行的spark的源码,只要spark的升级向下兼容,ydb依赖的spark就可以升级,而且即将发布的spark2.0我也会跟踪与测试。
六,本身ydb也使用了lucene作为索引,相对于solr与es在使用上有什么区别或优势?
谈到YDB的索引技术,相信很多同学都会想到Solr、ElasticSearch。Solr、ElasticSearch在真可谓是大名鼎鼎,是两个顶级项目,最近有些同学经常问我,“开源世界有Solr、ElasticSearch为什么还要使用YDB?”
在回答这个问题之前,大家可以思考一个问题,既然已经有了Oracle、Mysql等数据库为什么大家还要使用ES下的Hive、Spark? Oracle和Mysql也有集群版,也可以分布式,那ES与Hive的出现是不是多余的?
YDB的出现,并不是为了替代Solr、ES的,就像ES的出现并不是为了干掉Oracle和Mysql一样。而是为了满足不同层面的需求。
一、YDB与Solr,ES定位不同
Solr\ES :偏重于为小规模的数据提供全文检索服务;YDB:则更倾向于为大规模的数据仓库提供索引支持,为大规模数据仓库提供即席分析的解决方案,并降低数据仓库的成本,YDB数据量更“大”。
Solr、ES的使用特点如下:
1. 源自搜索引擎,侧重搜索与全文检索。
2. 数据规模从几百万到千万不等,数据量过亿的集群特别少。
Ps:有可能存在个别系统数据量过亿,但这并不是普遍现象(就像Oracle的表里的数据规模有可能超过Hive里一样,但需要小型机)。
YDB:的使用特点如下:
1. 一个基于大索引技术的海量数据实时检索分析平台。侧重数据分析。
2. 数据规模从几亿到万亿不等。最小的表也是千万级别。
二、YDB与Solr,ES在技术实现上的不同
1,数据存储位置
solr与ES 索引存储在本地硬盘,恢复难
硬盘容易坏,恢复麻烦,每次数据都的从备份恢复么?20T数据的恢复要多久-7个小时够么?
对于运维人员,数据存储在本地是个噩梦,经常半夜因为硬盘故障报警,去手工恢复数据,而且每次恢复都要恢复7~8个小时,一不留心搞错目录,数据还丢了。
YDB的索引是存储在HDFS之上的
理论上只要HDFS有空间,就可以不断的添加索引,索引规模不在严重受机器的物理内存和物理磁盘的限制。容灾和数据迁移容易得多,硬件损坏不在中断服务。
2.进程宕掉的恢复
solr的shard 如果挂掉,整个进群不可服务,需要运维人员去干预
YDB如果是worker进程挂掉,由YARN自动感知,自动重启,如果机器宕机,服务会自动迁移到其他机器上
3.部署与运维
solr的需要一起操作很多台机器,要保证多台机器之间的配置一致性,扩容什么的,新的机器需要重新安装与部署
YDB只需要部署在接口机,进程的启动与停止由YARN统一分配与管理,也可以与hadoop生态圈里的其他资源共存
4.对资源的消耗不同
solr与ES
1)常驻内存问题。
fdx,tvx,fnm,si,tip等文件是常驻内存的,
这种方式需要消耗很多内存不说,首次打开索引的加载速度会特别慢.
在Solr\ES中的索引是一直处于打开状态的,不会频繁的打开与关闭;
这种模式会制约一台机器的索引数量与索引规模,通常一台机器固定负责某个业务的索引。
2)不断的进行全局的内存关系映射
查询或者添加文档的时候,要将每个索引分片在做一次全局的内存映射,即使一次查询只会用到其中的一条记录或者只添加一条记录,也会将整列的全部值都Load到内存里,太浪费资源,这也是为什么,数据量达到一定规模后,CPU,内存,硬盘经常被爆掉的直接原因,数据规模受物理内存限制很大,索引规模上千万后OOM是常事。。
YDB在索引上的改进:
1). 索引按需加载
大部分的索引处于关闭状态,只有真正用到索引才会去打开;一级跳跃表采用按需Load,并不会Load整个跳跃表,用来节省内存和提高打开索引的速度。Hermes经常会根据业务的不同动态的打开不同的索引,关闭那些不经常使用的索引,这样同样一台机器,可以被多种不同的业务所使用,机器利用率高。
2.) 排序和统计按需加载,无须全局映射
排序和统计并不会使用数据的真实值,而是通过标签技术将大数据转换成占用内存很小的数据标签,占用内存是原先的几十分之一。
另外YDB不会像SOLR那样做全局映射,适合大数据量的导入,不会再大数据规模导入时,因为全局映射导致OOM,而且导入性能也是SOLR的5~6倍。
去掉了DOCVALUES的三到四次重复IO,略加改动在索引合并是就可以节省2~3倍的IO。
HASHSET操作太影响性能,要去掉换成数组。
4. 节点和数据规模受限
Merger Server只能是一个,制约了查询的节点数量;数据不能进行动态分区,数据规模上来后单个索引太大。
而YDB则采用 多个merger server。
4,GC问题
创建Field的时候,有对象可以复用,否则GC问题严重。
(在solr里每个field要创建60多个对象,每行要创建600多个对象。)
5,数据倾斜问题
如 性别=男 and 手机号=1234567890。多个条件查询的时候要充分利用跳跃表。
七,谓词下推功能与parquet或rcfile相比有什么不同?
实现原理有区别,spark的parquet的pushdown 是个是粗粒度的索引 ,只是根据一个块内 的数据情况(如最大值,最小值)判断,这个块是否需要计算,或者上次是否已经计算过了,如果有很多复杂的条件组合,或者全文检索(模糊匹配),粗粒度的索引或预计算往往发挥不了作用。
YDB是一个细粒度的索引,精确粒度的索引,就像传统数据库那样,一旦对一个列创建完毕索引后,再次查询,就不是全表扫描Scan了,而是根据索引直接定位到相关数据了,YDB的索引支持中文分词,能够进行全文检索,模糊匹配,这个要比数据库或spark的like实现的性能高很多,也支持任意条件嵌套组合过滤。
八,为什么Yarn中看到的内存使用量(内存计费),比我在ya100_env.sh中配置的多?
1,关于计费
yarn的内存“计费”是按照 yarn.scheduler.minimum-allocation-mb的整数倍进行计费,默认是1G
spark.yarn.executor.memoryOverhead 会在申请的内存的基础上,额外申请384m内存
如果我们对 spark.executor.memory配置了1g内存,外加额外分配的384m,yarn的取整原则,最终是按照2g的内存使用量进行的“计费”
为了计费的相对准确,大家尽量 要凑成 yarn.scheduler.minimum-allocation-mb的整数倍,或者将 yarn.scheduler.minimum-allocation-mb的值调小,让计费更准确
2,关于堆外内存
spark在执行的过程中,会使用堆外内存,如果大家运行的一个job很大(比如说要导入的数据量很大)
请将spark.yarn.executor.memoryOverhead 给予一个较大的内存,或者直接将yarn.nodemanager.pmem-check-enabled与yarn.nodemanager.vmem-check-enabled参数设置为false,以免在导出数据过程进程被kill导致导入数据失败。
3、相关参数解释,备忘
spark.yarn.executor.memoryOverhead :值为 executorMemory * 0.07, with minimum of 384
spark.yarn.driver.memoryOverhead :值为 driverMemory * 0.07, with minimum of 384
spark.yarn.am.memoryOverhead :值为 AM memory * 0.07, with minimum of 384
九,实时生成索引的话 每秒可以达到多少条记录
取决于具体的记录的大小与数据类型,通常来说1kb大小的记录
1.在一台64G内存、CPU16线程、一块1T的SSD磁盘,可以达到13万每秒。
2.在一台128G内存、CPU8线程、8块300G的Sas磁盘,可以达到6万每秒。
3.在9台256G内存、CPU 64线程的IBMopenpower、12块1T的sas盘,24小时可以导入1100亿,约130万每秒(每台13万每秒)
十,如果用SAS盘从实时建完索引 到能检索查询话 这之间延迟 大概几秒
默认配置 1分钟左右,如果数据量不大 可以缩减到10秒左右
十一、YDB隐藏配置
1.分区
随着时间的日积月累,单个索引会越来越大,从而导致系统瓶颈。YDB不会将全部的数据都完整的创建在一个索引中,YDB会对数据进行分区,分区的方式由用户来定义,可以按照日期分区,也可以按照某些固定的HASH方式来分区。
一条数据的分区,在导入的时候直接指定,如下图红色部分所示。
如果按照日期进行分区,每天就会生成一个分区,如需查询哪天的数据,就去对应的分区中检索,其他的分区则闲置。
YDB 的SQL需要通过ydbpartion来指定分区; SQL查询必须要设置分区,而且要写在SQL的最外层。
设置分区例子如下:
ydbpartion ='20140928'
ydbpartion in ('20140928','20140927')
2.ydb_site.yaml配置
配置项 | 建议值 |
ydb.directory.blockbuffer.percent: 32 | 如果您内存富余较多,可以使用更多的内存作为hdfs的buffer |
ydb.realtime.binlog.usebinlog: "true" ydb.realtime.binlog.usehsync: "true" ydb.realtime.binlog.roll.timelen.ms: 120000 ydb.realtime.binlog.sync.intervel: 1 | 如果您的业务不担心数据丢失,可以关闭binlog(预写日志WAL)功能。 :如果设置成true,则binlog的flush会使用hfds的hsync方法,否则使用hflush刷新数据 日志进行切割的时间,20分钟切割一次 每间隔几条记录,调用一次flush,如果在flush调用前进程意外终止,未flush的数据有可能丢失,但是频繁的调用hflush()方法会导致系统变慢建议调大此值。 |
ydb.reader.rawdata.start.delay.secs: 600 | 集群启动后延迟600秒开始消费数据创建索引 |
ydb.reader.speed.limit.kb: 512000 ydb.reader.speed.limit.file: "/hdfs/xxx" | 流量限速50M 如果觉得这个值要动态改变,可以采用此参数指向hdfs中的一个文件,系统会每间隔20分钟读一次配置 |
ydb.realtime.binlog.sync.intervel: 1024 | 建议调整为1024,每间隔1024条同步一次binlog到hdfs,但是意味着如果在同步前进程异常中断,1024条数据丢失 |
ydb.realtime.doclist.buffsize: 1024 ydb.realtime.doclist.flush.secs: 30 ydb.realtime.doclist.flush.thread.check.secs: 300 ydb.realtime.doclist.flush.process.threads: 8 | 积累1024条数据,doclist区域会刷新到buffer区 积累30秒,doclist区域会刷新到buffer区 如果一直没有数据进来,间隔300秒启动线程检查一次,是否应该刷新到buffer区域 采用8个线程来刷新 |
####【buffer区域的索引控制】#### ydb.realtime.buffer.ram.writepartion.each.percent: 1 ydb.realtime.buffer.flush.secs: 60 ydb.realtime.buffer.flush.thread.check.secs: 300 ydb.realtime.buffer.maxcount: 64 ydb.realtime.buffer.merger.factor: 16 | 每个写入的partion分片会使用1%的内存进行buffer,如果并发写入的分区特别多,内存有可能不够 积累60秒,buffer区域的索引会刷新到ram区域 如果一直没有数据进来,间隔300秒启动线程检查一次,是否应该刷新到ram区域 Buffer区域最多积累64个索引 Buffer区域每次合并索引的时候一次最多合并16个索引 |
####【内存区域的索引控制】#### ydb.realtime.ram.ram.writepartion.each.percent: 3 ydb.realtime.ram.localflush.secs: 600 ydb.realtime.ram.ram.maxcount: 64 ydb.realtime.ram.merger.factor: 16 | 每个写入的partion分片会使用3%的内存进行Ram 在合并过程中如果ydb.index.ram2disk.premerger.isuse配置为true 有可能占用2个6%的内存如果并发写入的分区特别多,内存有可能不够 积累600秒,Ram区域的索引会刷新到hdfs上 Ram区域最多积累64个索引 Ram区域每次合并索引的时候一次最多合并16个索引 |
####【hdfs上的索引合并因子的控制】#### ydb.realtime.index.disk.maxcount: 64 ydb.realtime.index.disk.merger.factor: 16 ydb.index.ram2disk.premerger.isuse: "true" |
Hdfs区域最多积累64个索引 Hdfs区域每次合并索引的时候一次最多合并16个索引 在将ram区域的索引合并到磁盘上前,是否先进行预合并(当内存富余的时候推荐使用,可以节省磁盘IO) |
ydb.realtime.index.maxfilesize: 536870912 | 单个索引的最大大小为512m |
3.数据导入注意事项
在导入数据的时候,请注意:
第一:导入数据要均匀的分配给每个分片(Task),防止出现数据倾斜的问题。
第二:同时导入的分区数量不要超过32个(非分片个数),如果同时导入的分区太多,打开的写索引的writer也太多,会导致性能不好,因为每个writer都会占用一定的内存buffer,也容易导致内存用满。
目前允许同时处于写的状态的write数量为512(配置项为ydb.index.max.writer)个,但是实际情况下,同时产生512个writer内存是不够的,所以要严格控制写入的分区数量。如果同时写入的分区数量超过ydb.index.max.writer配置的值,就会有不经常使用的writer被关闭,下次有数据写入的时候会重新打开,这样就会造成索引频繁的被打开关闭,严重影响性能。
数据延迟
如果配置项ydb.reader.rawdata.hdfs.path指定的hdfs中的目录,有较多的文件堆积,说明数据消费有延迟,如果CPU负载不高,可以通过修改ydb.reader.speed.limit.kb: 1024与ydb.reader.speed.limit.file:"/hdfs/xxx"这两个配置来提高消费的速度,但是如果机器负载本身很高,只能通过优化其他配置参数或者扩容的方式解决。
索引的管理方式与性能的关系因为资源的限制,如果一个集群中的索引数量太多(比如保存了1年的索引),集群现有资源不能满足打开全部的索引,YDB采用LRU的方式管理索引,对于那些经常使用的索引,在内存中是一直打开的,不经常使用的索引则是处于关闭状态,存放在HDFS中,不占用任何的内存资源。
如果要查询一个不经常使用的分区,索引需要重新打开,故查询会比较慢。
某些场景,循环扫描不同的分区索引,会导致每个分区都没有热点,会造成性能严重下降。
如何让YDB性能提升10倍(千亿规模集群DBA必读)
Ydb工作的时候会将SQL分成几个部分 “where后的条件过滤”、“分组与统计”、“排序”。
系统最先执行的是“where后的条件过滤",先检索到与where条件匹配的记录。比如说全表有10亿条记录,经过与where条件匹配后,可能还剩下500万条记录,然后对剩下的500万条进行“分组与统计”、“排序”。
由于YDB采用大索引技术,索引的匹配速度比较快,故后续的“分组与统计”、“排序”是决定计算性能的关键。
默认情况是将“where过滤后”,满足条件的全部匹配的数据都取出来,再进行“分组与统计”、“排序”。如果满足条件的数据仅仅是原始数据的一小部分,不会影响性能,也能满足大部分的场景需求,但是如果有“严重的数据倾斜”,或者直接对全表数据进行“分组与统计”、“排序”会严重的消耗系统的资源,这会导致系统变慢。
如果业务模式每次检索的数据 都是原始数据很小的一部分,那么可以将这个 “where过滤”改进一下,不像之前那样每次都取出全部匹配的数据,而是每次仅取其中的一小部分,比如经过“where过滤”后依然有几千万的数据,但我们只取其中的1万条,然后在这1万条的基础上在进一步的“分组与统计”、“排序”。这样除了极大的提高性能,也防止因为用户的误操作(写错了SQL),导致系统崩溃。
要做这样的配置,需要在ydb_site.yaml中配置限制的值,如下面的例子,我们限制每个SQL最多匹配10000条数据参与计算。
ydb.fq.max.return.docset.size: 10000
注:这里的10000针对一个索引片段。一个分区下会有 ydb.topoplgy.task.count 个task,每个task下hdfs目录里最多会有ydb.realtime.index.disk.maxcount个索引片段,内存区域最多会有ydb.realtime.ram.ram.maxcount个索引片段,所以一次查询最多参与计算的记录数是索引片段的个数乘以10000。
如果个别的业务要求突破这个限制(比如说仅仅count计算,对系统性能没什么大的影响),只要SQL再加上如下条件即可突破。
放到SQL里的例子如下
select count(label),count(*) from ydbexample where ydbpartion='20151011' and ydbkv='max.return.docset.size:100000000'
limit 0,100
系统启动阶段会碰到的问题
系统刚启动的时候,历史索引还存放在hdfs中,并没有打开,首次打开索引需要加载很多资源。故系统刚启动的瞬间,查询会比较慢。
如上次系统是因意外终止(硬件损坏,机器重启等),内存中的数据还没有来得及同步到HDFS中,所以在首次启动的时候需要用binlog(WAL write ahead log)恢复数据,这个恢复时间取决于恢复数据的量,所以首次查询的时候,有可能出现卡顿的现象或者出现数据变少的现象,出现这种现象说明系统正在恢复数据,等数据恢复完毕后这种现象会自行消失,所以建议系统启动后等待一段时间(10-15分钟)后再开始查询。
心跳的延迟
页面的心跳信息也不是实时采集的,而是在系统启动后,采用异步的方式,进行异步的抓取。故在启动的开始阶段,有些表的心跳看不到是正常的。
因为心跳是异步采集,所以当新创建一个表或者增加一个新区时,表或分区的心跳并不能实时看到。
同样因为心跳是异步采集,实时导入数据时,数据的条数、占用空间大小、碎片个数的显示都有较大的延迟。
之所以采用异步采集,是因为我们不想因为心跳本身占用系统太多的资源。
心跳频率可控的参数是ydb.hb.task.intervel.secs,他只能加快心跳的频率,但是对新建表以及新增分区无效。
1、ydb大数据查询,不带条件过滤,也就是用不上索引,查询结果需要group by聚合或多表关联,类似这种场景ydb和原生态的spark sql进行pk有什么优势?
这种查询不能使用索引,但是ydb依然会比原生spark快很多
在真实的数据中,数据肯定是有重复的,比如说类目,性别,年龄,成交金额等信息,传统的分析工具存储的是原始的值,比如说我们有1千亿条数据,那么就要存储一千亿条记录,那么进行统计的时候,一条一条的读出这些类目肯定要慢的不得了。
还记得机器人总动员中的伊娃么?当数据规模达到一定程度以后,如果还是直接对原始值进行读取,对大数据的搬运工作将会特别的消耗体力,而且工作效率很低。
hermes对原始数据做了一些处理,基本思路是:虽然你有1千亿的数据,但是你的类目不会那么多,典型的系统一般是几万个类目,2~3个性别值,故hermes在存储的时候虽然有1千亿条记录,但是只会存储几万个类目,2个性别,这根原始的千亿条记录在数据规模上可是相差千万倍,那么在之后的统计(count,sum,avg等)势必会比传统的分析工具快上千倍万倍。
hermes的这种方式我们称为标签技术,就是将数据的真实值用一个数值标签来替换数据本身,原始数据每个值我们只存储一份,这样当有大量重复值的数据,可以节省很多IO,即使数据重复值很少,我们也可以一个数字来代表原始值,因为原始值有可能比较大,但数值确可以很好的压缩。
采用列式存储
hermes在列的处理上也采用了列存储的技术,列和列之间的值是分开的,基于hermes的一个项目(face),是一个几万个列的大宽表,用户分析的时候往往只关心几个列(维度),如果像传统的分析软件那样,将几万个列的值都读出来,然后只取其中几个列的值,那么太浪费了,所以列存储技术hermes这种基于检索的分析系统来说也是必备的。
2、ydb和mpp进行PK优势在哪?(底层技术层面进行阐述)
完成一个计算任务 ,mpp的思路是 找一堆壮汉(硬件特别好的机器)来工作,如果性能慢了,就在找一堆壮汉去干。
ydb的思路是,将东西分们别类(创建索引),而不是非要地毯式的排查,但基于spark也有mpp的优点,在并发性上,性能上均比mpp好很多
3、新版spark支持数据源有parquetFile,jsonFile,外部数据库,hive表,RDD等,为什么ydb不能直接从数据库导入文件呢?
理论上只要spark支持的数据源,ydb都支持,都能导入,但是我没用过嘛,不敢乱说。
4、ydb数据查询结果支持order by吗或分页吗?
一般的大数据系统都不支持翻页,翻页是大数据的难点。一旦翻页到几百万条记录以后,大部分的系统均会OOM
ydb也一样不能直接分页,但是我们在hive的基础上进行了二次开发,可以通过一个接口来实现more翻页,也意味着用户可以一页一页的向下翻页,可以无限的翻页,但是不能跳页
32768的长度,分词的列是不能在YSQL内部进行group by(采用标签字典技术,性能好),但是可以再抛给spark后进行group by
映射表的目的是为了将hive数据导入到ydb中,如果是kafka模式,是kafka直接实时导入到ydb里面,中间不会通过insert overwrite来导入,故不需要创建映射表。
而查询的时候,我们是通过YSQL来查询的,也不需要映射表。