Mdrill集群安装记录

3 min read

mdrill是阿里妈妈-adhoc-海量数据多维自助即席查询平台下的一个子项目。旨在帮助用户在几秒到几十秒的时间内,分析百亿级别的任意维度组合的数据。mdrill是一个分布式的在线分析查询系统,基于hadoop,lucene,solr,jstorm等开源系统作为实现,基于SQL的查询语法。

准备阶段

软件准备:

  • jdk1.6.0_45.tar.gz
  • hadoop-0.20.2-cdh3u3.tar.gz
  • alimama-adhoc.tar.gz
  • jzmq-2.1.0-1.el6.x86_64.rpm
  • zeromq-2.1.7-1.el6.x86_64.rpm
  • zookeeper-3.4.5.tar.gz

服务器准备:
如果是线上服务器,建议配置如下:

  • 机器数量:10~12台
  • CPU:E5-2630(6核)*2
  • 内存:>=48GB
  • 硬盘规格数量:>=480GB*12 (SSD最佳,普通磁盘也可)。
    本次安装采用的是线下私有云

    • 服务器三台(CentOS-6.6-x86_64)
    • 内存 8G

基础环境配置

升级系统

yum update

安装lrzsz

lrzsz是一个可以搭配Xshell和SecureCRT能方便的在本地PC机和远程服务器之间传输文件的小工具。
yum install lrzsz -y

关闭IPV6

vi /etc/sysctl.conf
在文件的末尾追加:


完成后刷新配置 :
sysctl -p

关闭防火墙

setenforce 0 #临时禁用,不需要重启
iptables -F #清空iptables
vi /etc/sysconfig/selinux #修改SELINUX=disabled
chkconfig iptables off && chkconfig ip6tables off #重启后永久失效

修改及设置host

修改hosts文件:
vi /etc/hosts
追加如下内容:(注意 这里使用的是局域网IP,在私有云上部署时要特别留意)


修改每台主机上的配置(注意 hostname要与对应IP地址的主机对应)
vi /etc/sysconfig/network
设置如下内容:


为了让hostname快速生效,避免重启,直接在命令行中设置
hostname mdrill01

设置时间同步

设置时区为本地时间(每台主机都需要执行)
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
选择一台主机为始终同步服务器:这里选择的是mdrill01进行安装
yum install ntp -y
安装完成后,修改配置文件:
vi /etc/ntp.conf
将配置文件修改为:


启动ntp:
service ntpd start
设置为开机自启
chkconfig ntpd on
同步服务器设置完毕,切换到mdrill02和mdrill03服务器,进行如下操作
yum install ntpdate -y
并设置为每小时同步一次时间:
vim /etc/crontab
新增如下内容:

新增账号

服务器在使用时不建议使用root账户,在这里我们为每台主机添加mdrill账户
groupadd mdrill
useradd -g mdrill mdrill
passwd mdrill
创建/data目录,并赋予权限
mkdir /data
chown -R mdrill:mdrill /data

设置SSH免密码登陆

每台机器全部切换成mdrill用户
su mdrill
在每天机器上执行如下操作(一路回车即可)
ssh-keygen -t rsa -P ''
mdrill01执行如下操作
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
scp ~/.ssh/authorized_keys mdrill@mdrill02:~/.ssh/authorized_keys
mdrill02执行如下操作
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
scp ~/.ssh/authorized_keys mdrill@mdrill03:~/.ssh/authorized_keys
mdrill02执行如下操作
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
scp ~/.ssh/authorized_keys mdrill@mdrill01:~/.ssh/authorized_keys
scp ~/.ssh/authorized_keys mdrill@mdrill02:~/.ssh/authorized_keys
完成后再登录每条主机执行
chmod 400 ~/.ssh/authorized_keys
至此,免账号登陆就已经打通了

安装阶段

上传准备好的文件

将准备好的文件全部上传到/data目录

  • jdk1.6.0_45.tar.gz
  • hadoop-0.20.2-cdh3u3.tar.gz
  • alimama-adhoc.tar.gz
  • jzmq-2.1.0-1.el6.x86_64.rpm
  • zeromq-2.1.7-1.el6.x86_64.rpm

安装相应的应用

  1. 安装jzmq和zeromq
    由于是rpm包,所以需要转换到root账号安装,
    cd \data
    yum localinstall zeromq-2.1.7-1.el6.x86_64.rpm jzmq-2.1.0-1.el6.x86_64.rpm
    rm /data/*.rpm
    su mdrill
    以上操作需要在3台主机上分别执行
    以下操作仅需在1台主机上执行,等最后完成后同步到其他两台机器即可
  2. 安装jdk
    直接解压压缩包
    tar zxvf jdk1.6.0_45.tar.gz
  3. 安装hadoop
    直接解压压缩包
    tar zxvf hadoop-0.20.2-cdh3u3.tar.gz
  4. 安装zookeeper
    直接解压压缩包
    tar zxvf zookeeper-3.4.5.tar.gz
  5. 安装mdrill
    直接解压压缩包
    tar zxvf alimama-adhoc.tar.gz
    由于mdrill默认的使用的是hadoop-0.20.2,所以需要做下调整
    cp /data/hadoop-0.20.2-cdh3u3/hadoop-core-0.20.2-cdh3u3.jar /data/alimama/adhoc-core/lib/
    cp /data/hadoop-0.20.2-cdh3u3/lib/guava-r09-jarjar.jar /data/alimama/adhoc-core/lib/
    rm /data/alimama/adhoc-core/lib/hadoop-core-0.20.2.jar
  6. 清理安装包
    rm /data/*.tar.gz

配置环境变量

编辑用户配置文件
vi ~/.bashrc
在文件中追加如下内容


先将此文件拷贝到另外两台主机上
scp .bashrc mdrill@mdrill02:~/
scp .bashrc mdrill@mdrill03:~/
为了让环境变量生效,需要每台主机上执行
source ~/.bashrc

修改配置文件

修改hadoop配置文件

cd /data/hadoop-0.20.2-cdh3u3/conf/
vi masters


vi slaves


vi core-site.xml


vi hdfs-site.xml


vi mapred-site.xml


在完成上述配置后,需要创建相应的目录
mkdir /data/tmp
mkdir -p /data/dfs/name
mkdir -p /data/dfs/data

修改zookeeper配置文件

vi /data/zookeeper-3.4.5/conf/zoo.cfg

更新如下内容:


创建相应的目录,并写入zookeeperid
mkdir /data/zookeeper-3.4.5/data
vi /data/zookeeper-3.4.5/data/myid
写入数字1即可

修改mdrill配置文件

vi /data/alimama/adhoc-core/conf/storm.yaml


线上服务器配置建议:每台机器上配置6个shard,1个merger server,均分配5GB的内存

创建配置文件中涉及到的目录
mkdir -p /data/alimama/bluewhale/stormwork
mkdir -p /data/alimama/higoworkerdir

同步所有内容到各台主机

scp -r /data mdrill@mdrill02:/
scp -r /data mdrill@mdrill02:/
由于是同步过去,所以 zookeeper的myid需要在另外两台主机上设置
在mdrill02主机上
vi /data/zookeeper-3.4.5/data/myid


再mdrill03主机上
vi /data/zookeeper-3.4.5/data/myid

启动服务器

启动Hadoop

在启动hadoop前需要先对namenode进行格式化
hadoop namenode -format
由于设置了环境变量,启动起来非常简单
start-all.sh
只要在主节点执行上诉内容,其他两台机器相关的进程会一并启动
如需停止,可运行如下命令
stop-all.sh

相关端口:

  • jobtracker:50030
  • tasktracker:50060

启动zookeeper

在每天主机上执行如下命令即可
zkServer.sh start
如需停止
zkServer.sh stop
如需查看状态
zkServer.sh status

启动mdrill

cd /data/alimama/adhoc-core/bin/
chmod 777 ./bluewhale

nimbus是整个mdrill集群任务的总调度,有点类似hadoop的jobtracker
只需要在其中一台机器启动即可,启动命令如下
nohup ./bluewhale nimbus > nimbus.log &

supervisor用来管理其所在机器的work进程,其角色有点类似hadoop的tasktracker
需要在每台机器上启动,
nohup ./bluewhale supervisor > supervisor.log &

视情况看是否需要启动mdrillui
mkdir ./ui
nohup ./bluewhale mdrillui 1107 ../lib/adhoc-web-0.18-beta.war ./ui >ui.log &
启动后,可以通过浏览器打开对应ip的1107端口,看是否能正常打开即可。

测试mdrill

建表

将建表SQL存储为create.sql到“/data/alimama/adhoc-core/bin/”目录下,


执行如下命令
cd /data/alimama/adhoc-core/bin/
./bluewhale mdrill create ./create.sql

列的数据类型目前只支持4种

  • string :字符串类型
  • tlong :long整形
  • tdouble :浮点型
  • tdate :日期类型
  • text:字符串类型(进行了分词,意味着只能进行全文检索,而不能参与统计与分组)

另外如果数据类型用_mdrill_进行了分割,后面的值表示是否存储,在全文检索模式中特别有用,全文检索模式要把要进行展示的列配置成存储(速度能提升很多)
举例如下
下面这几个为只索引而不存储数据的值


下面这几个为只既索引也存储数据的值


另外如果要跳过某些列,可以将数据类型配置成ignored,表示这个列既不存储也不索引。

注意

  • 建表语句要与数据存储顺序一致
  • thedate:是分区的字段,必须存在,格式为yyyyMMdd格式的字符串,且要与对应的分区目录要对应

其他信息
如果需要经常的进行全文检索,那么可以配置成存储明细,使用额外的存储,换取全文检索的时间
./bluewhale mdrill create ./create.sql true

导入离线数据

数据目录
首先要确定数据表在hdfs上的根目录,比如说/mdrill/tablelist。目录在/data/alimama/adhoc-core/conf/storm.yaml的mdrill配置文件配置。
在该目录下可以有一个至多个数据表,每个数据表目录下会有三个子目录。

  • solr:表的配置目录
  • index:mdrill的索引在hdfs中的存储路径
  • tmp:临时目录

数据格式

  • mdrill默认处理的是sequencefile格式的数据,对key没有要求,value则为对应数据表中一条记录,记录的列与列之间的分隔符为默认\001,如果使用文本格式的,或者分隔符不是\001,创建索引逻辑时要注意传递的参数。
  • mdrill要求数据按照天进行分目录,目录命名必须为dt=yyyyMMdd这种格式
  • 数据的列中必须含有一列叫thedate,其值与其所在的目录dt=yyyyMMdd中的yyyyMMdd相等,thedate实际上为mdrill的分区字段,任何的查询都必须指定thedate分区。如果数据列中的thedate与目录中的dt=yyyyMMdd不相等,那么mdrill以目录的时间为准确时间。
  • mdrill默认必须按照日期分区,使用分区后总存储的数据量会显著提升,每天创建的索引也是增量的,如果确实因为某种原因无法按照日期分区,可以将分区类型设置为single,但是总的数据存储量会减少很多。

生存索引

指令规则:
./bluewhale mdrill index {表名}{hdfs源数据地址} 3650 {起始日期} {数据格式seq|txt,不写默认seq} {分隔符,不写默认\001} {分区下的文件匹配规则默认匹配*0* }

指令示例:
./bluewhale mdrill index st /mdrill/tablelist/st 3650 20140101 txt
./bluewhale mdrill index st /mdrill/tablelist/st 3650 20140101 txt tab "\\*\\*" 3 1

启动表

启动表指令
./bluewhale mdrill table {表1,表2,表3}
示例:
./bluewhale mdrill table st
停止表指令
./bluewhale mdrill drop {表1,表2,表3}
示例:
./bluewhale mdrill drop st

注意
启动表的操作只能执行一次,如果想添加新的表必须先停止表后再启动表。

重启服务

如果是因为mdrill本身的bug,需要重启mdrill,则可以这样做

  1. 先停止表
  2. 在每台机器上杀死所有的mdrill任务
    ps -x|grep bluewhale|grep server|awk '{printf("%s\n",$1)}'|xargs kill
  3. 清理mdrill的临时目录
    rm /data/alimama/bluewhale/stormwork/* -rf
  4. 重新按照原先的步骤 启动mdrill
  5. 启动表

配置实时数据源(如果使用离线模式,请跳过此步)

编辑storm.yaml配置文件,假设要配置为实时的表的名字为p4p_v2

  1. 配置editlog记录的位置,可以选择为local或hdfs
    hdfs模式没有经过严格的测试,如果hadoop集群不是经常的停机维护或者出问题,那么可以考虑使用hdfs模式,这样因为机器宕机或者硬盘损坏导致的数据丢失损失会减少到最小
    local模式表示editlog会记录到本地的硬盘上,如果这台机器硬件损坏或者宕机,那么那些还没有同步到hdfs中的索引数据会丢失(默认同步间隔为4小时,配置目前为硬编码,请参考com.alimama.mdrill.utils.UniqConfig里面的设置)
    higo.realtime.binlog: "local"
  2. 需要先将表配置为实时模式,配置方法如下
    higo.mode.p4p_pv2: "@realtime@"
  3. 配置表的分区:可以为day,month,default
    higo.partion.type.p4p_pv2: "day"
  4. 配置日志解析类
    解析类需要实现com.alimama.mdrillImport.DataParser接口,示例程序如下
    p4p_pv2-parse: "com.alimama.quanjingmonitor.mdrillImport.parse.p4p_pv2"
  5. 配置reader
    reader用于实时的读取数据,然后交给解析类解析后导入到mdrill里
    reader在阿里可以使用tt4(默认已经实现),阿里外部可以考虑使用metaq或者kafka
    需要实现的接口为
    com.alimama.mdrillImport.ImportReader.RawDataReader
    TT4实现的示例为
    com.alimama.quanjingmonitor.mdrillImport.reader.TT4Reader
  6. 配置导入模式为local与merger
    数据导入到mdrill前,如果数据可以进行简单的合并,那么会大量的减少导入到mdrill里的数据量,合并的方式很简单就是按照解析类的getGroup方法进行分组,getSum里的值进行累加而已,如果我们的数据很难进行合并,则建议使用local模式以减少没必要的传输,如果合并比率很高,那么建议使用merger
    p4p_pv2-mode: "local"
  7. 配置各种缓存参数
    p4p_pv2-commitbatch: 5000 //单次向mdrill递交的记录数
    p4p_pv2-commitbuffer: 10000//commit阶段的buffer长度
    p4p_pv2-spoutbuffer: 10000//spout阶段的buffer长度
    p4p_pv2-boltbuffer: 10000 //bolt阶段的buffer长度
  8. 配置缓存的刷新时间:与解析类的getTs()方法组合使用
    p4p_pv2-timeoutSpout: 240 //配置在spout的最大缓存时间
    p4p_pv2-timeoutBolt: 60 //配置在bolt里的最大缓存时间
    p4p_pv2-timeoutCommit: 30 //配置在commit阶段的最大缓存时间

导入实时数据

导入指令
./bluewhale jar ./mdrill.jar com.alimama.mdrillImport.Topology {自定义任务名称} {导入的表列表多个表之间用逗号分隔} {使用的进程总数} {每个进程使用多少mb的内存} {从什么时间开始导入}
示例如下
./bluewhale jar ./mdrill.jar com.alimama.quanjingmonitor.mdrillImport.Topology p4p_pv2topology p4p_pv2 66 512 20131231074710
如果想停止导入数据的程序
./bluewhale kill {自定义的任务名称}
示例如下
./bluewhale kill p4p_pv2topology

测试mdrill查询

mdrill的分区
mdrill的设计默认是使用分区的,也是按照分区进行存储的,除非强制使用single类型的分区外,查询的时候必须指定分区。目前mdrill的分区字段为thedate,格式为yyyyMMdd
在顶层SQL的where条件中必须有如下三种分区设定的一种

  • thedate=’yyyyMMdd’ 直接指定某一个分区
  • thedate in (yyyyMMdd, yyyyMMdd, yyyyMMdd) 给出一系列日期
  • thedate >= yyyyMMdd and thedate<= thedate 给出一个范围

查询明细

  • mdrill可以查询top 10000 条数据的明细,使用limit关键词
  • 对于明细的数据,可以进行排序,也就是order by

统计汇总
mdrill目前支持sum,max,min,count,dist五种汇总函数

  • dist就是sql中的count(distinct(xxx)),但是采用的是近似计算,会有一定的误差具体实现原理,请参考https://github.com/muyannian/higo/wiki/distinct
  • count有两种使用方法
    • count(列名),针对具体某一列进行count统计,当然如果该列值如果存在NULL值,不会作为count计数。
    • count(*),即使存在NULL的列,也会列入计数。

分类汇总

mdrill目前支持多维分类汇总统计,也就是sql中的group by。另外分类汇总后,mdrill可以按照某一列的值进行排序,如果分类汇总后的组数小于10000组为准确排序,如果超过10000组则为近似的排序和计算,有可能存在排序的顺序和计算的结果不正确的情况。

mdrill的过滤
目前mdrill的过滤支持如下几种

  • =:等于
  • <>:不等于
  • >=:大于等于
  • <=:小于等于
  • >:大于
  • <:小于
  • in:属于列表
  • not in:属于列表
  • like:模糊匹配

mdrill FAQ

数据在内存中是如何存储的

  1. mdrill是先进行分shard的,每个shard分布在不同的机器的不同的进程中
  2. 每个shard是按照时间进行分区的,每个分区是一个索引
  3. 每个索引是按照列进行存储的,每次缓存的时候加载一个列的值到内存中,多个分区,多个表,多个列之间LRU方式淘汰
  4. 加载到内存中的列,并非是原始值,而是一个值的整形的代号,比方说用一个数字899代替一个很长的字符串

对内存结构的解释

  1. 将lucene默认的将整个列数据全部都load到内存中的方式修改为load 每个列的值的编码代号,操作的时候也仅仅操作这些代号,真正展现的时候再将这些编号转换成真实的值,编号的数据类型根据某个列的值的重复程度可以为byte,short,int
  2. 将数据进行分区(默认按照时间),用到的数据会加载到分区中,不用的分区会从内存中踢出,采用LRU的方式管理,如果同时需要检索大量的分区,则进行排队处理,一个分区一个分区的处理。
  3. 多个表之间也合并,共享内存,用到的表才会加载到内存中,没用到的则在硬盘中存储。
  4. 原先merger server与shard是在同一个进程中的,每次查询的时候随机使用其中一个shard作为merger server,如果每次查询merger server使用1G的内存,但shard的数量非常多,merger server每次只用一个,但是为每个shard都额外分配1G内存就是浪费,新版mdrill将这两者分开,避免浪费。
  5. 按照内存大小进行LRU,而不是按照field的个数,不同列因为重复读不同对内存的消耗也不一样,按照个数LRU不合理,按照总内存使用LRU
  6. 由于每次逆旋都需要消耗时间,当LRU被淘汰的时候,将逆旋的结果保留到硬盘中,以备下次使用。

worker.childopts与 higo.merge.ports有什么区别

merger server只管理合并数据,shard才是资源使用大户,一般一台机器启动一个merger server就够了 ,没必要启动那么多。

  • worker.childopts用来标记 这台机器可以启动那些端口
  • higo.merge.ports用来标记 这些端口中哪些是merger server的端口

higo.shards.count+higo.mergeServer.count = 启动的总的进程数

  • higo.shards.count:表示启动的shard数量,一个shard就是一个存储索引的solr
  • higo.mergeServer.count:表示启动的merger server的数量,一个merger server也是一个solr,但是他没有索引,仅仅用于合并shard的数据据

参考链接:https://github.com/alibaba/mdrill/

打赏作者
微信支付标点符 wechat qrcode
支付宝标点符 alipay qrcode

K-近邻算法KNN学习笔记

什么是K-近邻算法? K近邻法(k-nearest neighbor, k-NN)是1967年由Cover T
2 min read

使用Prophet进行时间序列预测

Prophet是Facebook开源的预测工具,相比ARIMA模型,Prophet真的是非常的简单。只要读入两
1 min read

采用时间序列预测股价变化

时间序列简介 在数学上,随机过程被定义为一族时间随机变量,即{x(t),t∈T},其中T表示时间t的变动范围。
5 min read

发表评论

电子邮件地址不会被公开。 必填项已用*标注