Druid 简介,架构,部署,python连接,hue链接druid
架构
什么是Druid
Druid是一个高效的数据查询系统,主要解决的是对于大量的基于时序的数据进行聚合查询。数据可以实时摄入,进入到Druid后立即可查,同时数据是几乎是不可变。通常是基于时序的事实事件,事实发生后进入Druid,外部系统就可以对该事实进行查询。
Druid是一组系统,按照职责分成不同的角色。目前存在五种节点类型:
Historical: 历史节点的职责主要是对历史的数据进行存储和查询,历史节点从Deep Storage下载Segment,然后响应Broker对于Segment的查询将查询结果返回给Broker节点,它们通过Zookeeper来声明自己存储的节点,同时也通过zookeeper来监听加载或删除Segment的信号。
Coordinator:协调节点监测一组历史节点来保证数据的可用和冗余。协调节点读取元数据存储来确定哪些Segment需要load到集群中,通过zk来感知Historical节点的存在,通过在Zookeeper上创建entry来和Historical节点通信来告诉他们加载或者删除Segment
Broker:节点接收外部客户端的查询,并且将查询路由到历史节点和实时节点。当Broker收到返回的结果的时候,它将结果merge起来然后返回给调用者。Broker通过Zook来感知实时节点和历史节点的存在。
Indexing Service: 索引服务是一些worker用来从实时获取数据或者批量插入数据。
Realtime:获取实时数据
除了上述五个节点,Druid还有三个外部依赖:
- Zookeeper集群
- 元数据存储实例:Mysql
- Deep Storage:HDFS/或者分布式文件系统
参考:
https://help.aliyun.com/document_detail/72987.html?spm=a2c4g.11186623.6.675.5ebb7ba7mPowo3
Segments
Druid 把它的索引存储到一个Segment文件中,Segment文件是通过时间来分割的。
Segment数据结构
对于摄入到Druid的数据的列,主要分三种类型,时间列(timestamp)、维度列(dimensions)和指标列(聚合列metrics)。如下图
- 时间列 每一条数据都必须有此列,此列会决定数据所在的Segment(后面会介绍),所有的查询也都需要此列,在上面对应的数据列为timestamp,在系统中会存储的字段名为__time;
- 维度列 Druid会针对这些列建立bitmap的倒排索引,用于筛选数据,结合时间列便能快速找到需要查询的数据。根据假设的分析模型,我们只需要publisher和advertiser,而其他例如gender和country并非我们需要分析的列,便可以在建立模型的时候忽略,需要注意的是Druid只有String型的维度列,如果我们需要对维度列做数字范围的筛选,需要做特殊处理
- 聚合列(metric column) Druid会根据我们定义的时间粒度,再结合维度列在数据接入的时候对数据进行聚合,并根据聚合类型,用不同的数据结构来保存这一列。这一列算是Druid比较复杂的一个概念,与下面介绍的预聚合有很大关系,稍后我会进一步解释。在假设的分析模型中,我们需要对click列求sum。
于是我们可以建立一个简单的分析模型:
"dataSchema": {"dataSource": "wiki","parser": {"type": "string", #说明读取的每一行数据都是都是string类型"parseSpec": {"format": "json", #说明数据的格式需要通过json来解析"timestampSpec": { #指明时间列字段和格式"column": "timestamp","format": "auto"},"dimensionsSpec": { #指明需要索引的维度,只有加到此处的维度才可以查询"dimensions": ["publisher", "advertiser"]}}},"metricsSpec": [{"type" : "count", # 统计行数"name" : "rows"},{"name": "click_sum","fieldName": "click","type": "longSum" #整数求和}],"granularitySpec" : { #预聚合相关的配置"segmentGranularity" : "HOUR","queryGranularity" : "HOUR"}}
上面的分析模型是一个简单的使用,Druid本身的配置性非常强,我会在后续章节介绍这些配置的实现原理。
预聚合
上面的样例数据我们可以称之为原始数据,为我们直接采集到的数据,每天这样的数据有千亿甚至万亿。基于这些原始数据,如果我们需要分析点击量,成本是非常高的,因为我们尽管我们可以通过维度筛选出一部分数据,但是数据量还是很巨大,需要扫描这些数据来聚合,如此便会直接导致查询时长加长。为了避免这种情况,Druid采用了预聚合的设计,在数据接入的时候,就开始根据定义的维度,对数据进行聚合。Druid的预聚合分为两个级别,第一级是时间粒度,第二级是维度。
时间粒度
例子中模型的配置有segmentGranularity 和queryGranularity两个关键的参数,可以理解为一个是段的粒度,一个是查询的最小粒度。首先,Druid会根据timestamp和segmentGranularity来决定数据所属的段;然后,再根据timestamp和queryGranularity来决定存储在Druid的__time。
维度
Druid的预聚合过程也是其索引的过程,通常Druid会在内存中使用ConcurrentSkipListMap存储数据,以TimeAndDims(时间和维度值信息)作为key,根据配置的metricsSpec对数据进行聚合,聚合的结果作为value。为了避免OOM,最后会以bitmapIndex的数据格式周期性的落地到磁盘存储。
于是,样例数据最后存储的格式大概为:
Segment sampleData_2011-01-01T01:00:00:00Z_2011-01-01T02:00:00:00Z_v1_0__time publisher advertiser rows click_sum
2011-01-01T01:00:00Z ultratrimfast.com google.com 1 0
2011-01-01T01:00:00Z bieberfever.com google.com 3 1
Segment sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0__time publisher advertiser rows click_sum
2011-01-01T02:00:00Z ultratrimfast.com google.com 2 1
segmentGranularity为小时,所以对应的段都是小时级别。queryGranularity为小时,聚合的结果对应的__time也是整点,会将每小时的数据全部聚合到其所属小时的开始时间。 另外说明,倒数第二例为总共的行数,最后一列为点击数。sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0
中的v1通常为Task启动时获取的TaskLock的version,可以理解为Task启动的时间。
对于时间列和指标列处理比较简单,直接用LZ4压缩存起来就ok,一旦查询知道去找哪几行,只需要将它们解压,然后用相应的操作符来操作它们就可以了。维度列就没那么简单了,因为它们需要被过滤和聚合,因此每个维度需要下面三个数据结构。
一个map,Key是维度的值,值是一个整型的id
一个存储列的值得列表,用1中的map编码的list
对于列中的每个值对应一个bitmap,这个bitmap用来指示哪些行包含这个个值。
对于上图的Page列,它的存储是这样的
1: 字典
{"Justin BIeber": 0,"Ke$ha": 1
}2. 值的列表
[0,0,1,1]3. bitMap
value="Justin Bieber": [1, 1, 0, 0]
value="Ke$ha": [0, 0, 1, 1]
历史节点
每个历史节点维持一个和Zookeeper的长连接监测一组path来获取新的Segment信息。历史节点互相不进行通信,他们依靠zk来等待协调节点来协调。
协调节点负责把新的Segment分发给历史节点,协调节点通过在zk的指定路径下创建一个entry来向历史节点做分发。
当历史节点发现一个新的entry出现在path中,它首先会检查本地文件缓存看有有没Segment信息,如果没有Segment信息,历史节点会从zk上下载新的Segment的元信息。Segment的元信息包括Segment存在Deep Storage的位置和如何解压和处理Segment。一旦一个历史节点完成对一个Segment的处理,这个历史节点会在zk上的一个路径声明对这个Segment提供查询服务,此刻这个Segment就可以查询了。
查询节点
Broker节点负责将查询路由到历史节点和实时节点,Broker节点通过zk来知道哪些Segment存在哪个节点上。Broker也会把查询的结果进行Merge
大多数Druid查询包含一个区间对象,这个对象用来指定查询所要查的区间段。Druid的Segment也通过时间段进行分割散落在整个集群中。假设有一个简单的数据源,这个数据源有七个Segment,每个Segment包含一周中的某一天的数据。任何一个时间范围超过一天的查询都会落到不止一个Segment上。这些Segment可能分布在集群中不同的节点上。因此这种查询就会涉及到多个节点。
为了确定发送到哪个节点上,Broker会从Historial和RealTime的节点来获取他们提供查询的Segment的信息,然后构建一个时间轴,当收到特定的时间区间的查询时,Broker通过时间轴来选择节点。
Broker节点会维护一个LRU缓存,缓存存着每个Segment的结果,缓存可以是一个本地的缓存或者多个节点共用的外部的缓存如 memcached。当Broker收到查询时候,它首先将查询映射成一堆Segment的查询,其中的一个子集的结果可能已经存在缓存中,他们可以直接从缓存中拉出来,那些没在缓存中的将被发送到相应节点。
协调节点
协调节点负责Segment的管理和分发,协调节点指挥历史节点来加载或者删除Segment,以及Segment的冗余和平衡Segment。协调节点会周期性的进行扫描,每次扫描会根据集群当前的状态来决定进一步的动作。和历史节点和Broker一样,协调节点通过zk来获取Segment信息,同时协调节点还通过数据库来获取可用的Segment信息和规则。在一个Segment提供查询之前,可用的历史节点会按照容量去排序,容量最小的具有最高的优先级,协调节点就会让它去加载这个Segment然后提供服务。
- 清理Segment,Druid会将集群中的Segment和数据库中的Segment进行对比,如果集群有的的数据库中没有的会被清理掉。同时那些老的被新的替换的Segment也会被清理掉。
- Segment可用性, 历史节点可能因为某种原因不可用,协调节点会发现节点不可用了,会将这个节点上的Segment转移到其他的节点。Segment不会立即被转移,如果在配置的时间段内节点恢复了,历史节点会从本地缓存加载Segment。恢复服务
- Segment负载均衡,协调节点会找到Segment最多的节点和Segment最少的节点,当他们的比例超过一个设定的值的时候,协调节点会从Segment最多的节点转移到Segment最少的节点
索引服务
索引服务是一个高可用的,分布式的服务来运行索引相关的Task。索引服务会创建或者销毁Segment。索引服务是一个Master/Slave架构。索引服务是三个组件的集合
- peon组件用来跑索引任务。
- Middle Manager组件用来管理peons
- Overlord向MiddleManager分发任务。
索引服务
Overlord节点负责接受任务,协调任务分发,创建锁,和返回状态给调用者。Overlord节点可以以本地模式或者远程模式运行。本地模式会直接创建Peon,远程模式会通过Middle Manager创建任务。
实时节点
实时节点提供实时索引服务,通过实时节点索引的数据立即可查。实时节点会周期性的构建Segment,并且把这些Segment推到历史节点并修改元数据。
参考:https://www.jianshu.com/p/852bb8cfed6b
采用技术
除了 MPP 架构外,它还运用到了四点重要的技术,分别是:
- 预聚合
- 列式存储
- 字典编码
- 位图索引
预聚合算是 Druid 的一个非常大的亮点,通过预聚合可以减少数据的存储以及避免查询时很多不必要的计算。
特性
为分析而设计:为OLAP工作流的探索性分析而构建,支持各种过滤、聚合和查询等类;
快速的交互式查询:Druid的低延迟数据摄取架构允许事件在他们创建后毫秒内可被查询到;
高可用性:Druid的数据在系统更新时依然可用,规模的扩大和缩小都不会造成数据丢失;
可扩展:Druid已实现每天能够处理数十亿事件和TB级数据。
使用场景
1、需要交互式聚合和快速探究大量数据时;
2、需要实时查询分析时;
3、具有大量数据时,如每天数亿事件的新增、每天数10T数据的增加;
4、对数据尤其是大数据进行实时分析时;
5、需要一个高可用、高容错、高性能数据库时。
Druid 使用建议
本小节主要想结合实际问题,给大家提供一些 Druid 的使用建议,供大家参考。
①什么样的业务适合用 Druid?
建议如下:
时序化数据:Druid 可以理解为时序数据库,所有的数据必须有时间字段。
实时数据接入可容忍丢数据(tranquility):目前 tranquility 有丢数据的风险,所以建议实时和离线一起用,实时接当天数据,离线第二天把今天的数据全部覆盖,保证数据完备性。
OLAP 查询而不是 OLTP 查询:Druid 查询并发有限,不适合 OLTP 查询。
非精确的去重计算:目前 Druid 的去重都是非精确的。
无 Join 操作:Druid 适合处理星型模型的数据,不支持关联操作。
数据没有 update 更新操作,只对 segment 粒度进行覆盖:由于时序化数据的特点,Druid 不支持数据的更新。
k8s集群部署
参考git:https://github.com/626626cdllp/k8s/tree/master/druid
python 操作druid
参考git:
https://pythonhosted.org/pydruid/
https://druid.apache.org/blog/2014/04/15/intro-to-pydruid.html
hue链接druid
http://gethue.com/quick-task-how-to-query-apache-druid-analytic-database/
Druid 简介,架构,部署,python连接,hue链接druid相关推荐
- python连接sqlserver_python 链接sqlserver 写接口实例
我是使用pymssql完成的sqlserver,首先下载符合版本的pymssql的whl,然后安装,在pycharm的default setting->project Interpreter中确 ...
- 数据层优化-jdbc连接池简述、druid简介
终于回到既定轨道上了,这一篇讲讲数据库连接池的相关知识,线程池以后有机会再结合项目单独写篇文章(自己给自己挖坑,不知道什么时候能填上),从这一篇文章开始到本阶段结束的文章都会围绕数据库和dao层的优化 ...
- python后台架构Django教程——连接读写mysql数据库
全栈工程师开发手册 (作者:栾鹏) python教程全解 本文衔接至python后台架构Django开发全解. 有其他问题请先阅读:http://blog.csdn.net/luanpeng82548 ...
- python链接mysql 判断是否成功_【初学python】使用python连接mysql数据查询结果并显示...
因为测试工作经常需要与后台数据库进行数据比较和统计,所以采用python编写连接数据库脚本方便测试,提高工作效率,脚本如下(python连接mysql需要引入第三方库MySQLdb,百度下载安装) # ...
- python链接hbase模块_HBase实战(1):使用Python连接Hbase数据库
来源于 https://blog.csdn.net/duan_zhihua/java/article/details/80622166 使用Python连接Hbase数据库 1,Hbase下载. 下载 ...
- Asible简介及部署
Asible简介及部署 1.Ansible基本概述 Ansible 能做什么 Ansible 软件特点 Ansible基础架构 2.Ansible服务安装 1)安装ansible(不用手动启动服务) ...
- Elasticsearch7从入门到精通(简介、部署、原理、开发、ELK)
Elasticsearch7从入门到精通(简介.部署.原理.开发.ELK) 第1章.Elasticsearch简介 1-1.Elasticsearch介绍 Elasticsearch官方网站:http ...
- 《Python分布式计算》 第5章 云平台部署Python (Distributed Computing with Python)
序言 第1章 并行和分布式计算介绍 第2章 异步编程 第3章 Python的并行计算 第4章 Celery分布式应用 第5章 云平台部署Python 第6章 超级计算机群使用Python 第7章 测试 ...
- Nginx网站服务与LNMP架构部署(详解)
Nginx网站服务与LNMP架构部署 1.Nginx服务基础 2.编译安装Ngiax 3.Nginx的运行控制 4.配置文件nginx.conf 5.Nginx虚拟主机 6.LNMP架构部署 1.源码 ...
最新文章
- eclipse修改文件代码不起作用,输出时还是老的,估计是缓存问题
- BZOJ2132 圈地计划
- Scala集合实现WordCount单词统计代码
- 常见的社会潜规则有哪些?
- MSSQL获取指定日期的SQL语句
- 火山PC画板打造UI
- 双因素认证令牌_安全令牌:防止双因素令牌认证攻击
- java真垃圾_JAVA吧真的很垃圾!!!
- macOS10.13.6及以下版本不能自动升级到更高版本的解决方案
- Spring5基础知识
- 手把手教你用深度学习做物体检测(二):数据标注
- 互联网的行业都有哪些岗位?
- LeetCode50——一题学会快速幂算法
- 手把手教你实战开发黑白棋实时对战游戏
- 《网络协议》笔记-网络分层
- docker安装wnameless/oracle-xe-11g并运行(手写超详细)
- 应用检查后台启动权限方法(小米官方给出的)
- SAP中输出采购订单GR/IR标识清单
- 五笔打字:速成手册---半小时学会五笔打字
- 洛谷P1075 质因数分解C语言
热门文章
- 方法区jdk1.7,1.8版本的构造变化
- 结构体中操作c语言,C语言中结构体的操作
- html5期末考试题答案,HTML5期末考试题型
- LIRe 源代码分析 6:检索(ImageSearcher)[以颜色布局为例]
- DirectShow 在 VS2010 中开发环境的设置
- python字符串描述错误的_Python字符串错误字符
- spss与python和sql区别_Python/Excel/SPSS/SQL数据处理方法比较之2 - 数据查看
- 计算机硬件密码,计算机硬件技术基础综合性实验任务书(08)密码门锁的模拟_C
- on() 和 click() 的区别:二者在绑定静态控件时没有区别,但是如果面对动态产生的控件,只有 on() 能成功的绑定到动态控件中。以下实例中原先的 HTML 元素点击其身后的 Dele
- Oracle如何使用PL/SQL调试存储过程