数仓架构(离线和实时)--企业版

数仓架构图–企业版

1. 背景

  1. 数仓,这是一个并不新颖的词语。在PC时代,就有传统数仓,当时数据一般存放在数据库中,一般是Oracle或者Mysql集群中。因为那时候数据量还不是非常大,所以使用数据库集群就可以进行数据的存储和查询分析,集合前端web页面就能做数据交互式的查询和展示。
  2. 进入互联网时代之后,由于移动设备和移动通信技术快速发展,来自移动端的数据几何倍数增加,传统数仓技术已经无法支撑这么海量的数据存储和查询分析。现代化数仓应运而生。
    PS:
  • 移动互联网时代,因为都是敏捷开发,为了更好研究客户喜好,改进用户功能和体验,不管是web页面还是app应用,都会将PC时代就有的用户行为埋点功能加上,采集这些用户行为数据日志信息之后,进行存储,分析,提炼有效信息。
  • 行为数据埋点,就是当用户打开软件开始到离开软件,中间的动作和行为做记录,如点击一个按钮,收藏,关闭,滑动等等。触发一个业务行为如浏览某个页面,分享等等,甚至app进入后台,关闭app等都会被记录下来。
  • 除了行为日志数据之外,还有来自越来越复杂业务端的埋点数据,业务数据等也都需要进行分析处理,用来提炼有效信息。
    大数定理,当数据样本足够大,就一定可以将提炼的信息尽可能接近于事实。今日头条的推荐算法,美国提出的高频交易都是突破了传统观念的技术方向,以数据说话,就是从数据中提炼理论,而不是先设想出一个理论再去验证使用。只要样本足够完整足够大,数据不会说谎。

2. 架构

数仓架构(离线和实时)--企业版_第1张图片

2.1. 移动端和业务后台做埋点统计和上传

  1. 移动端的埋点,一般分为即时埋点和延后埋点,顾名思义,即时埋点就是触发一个动作,就将用户行为埋点数据上传到日志服务器(一般称之为行为日志埋点服务器,日志埋点服务器,日志服务器等不同叫法)。延后埋点就是,考虑到移动端网络信号不稳定原因,一般会将埋点数据一条一条存放到移动端的文件中,等满足触发条件时,再批量上传到日志服务器。
    注意,移动端由于设备性能差异性较大,网络情况复杂,一般不会设置很复杂的日志上传机制,并且允许有一部分数据丢失来应对移动端各种复杂情况。
  2. 业务后台埋点,当业务后台触发一些行为时,也会将这些数据上传到日志服务器中。这主要是考虑到进行用户行为流程分析时,一些指标不好在移动端进行采集如订单状态、支付状态、贷款授信状态等的及时变化。

2.2 flume日志采集

  1. 因为日志服务器一般是以集群形式存在,日志文件存放在集群各个节点服务器上。这时候一般采用分布式日志采集框架进行采集,flume只是目前比较主流的框架,还可以根据业务需求选择其他日志框架;如果有极致要求,甚至需要自行开发日志采集框架。
  2. flume采集架构简单说明
  • 在日志采集时,一般使用tailDir Source,这个可以监控多个文件夹,还可以实现断点续传(会记录偏移量)
  • 选择channel时,一般是三种选择,file channel、memory channel、kafka channel。

file channel,使用文件做缓存,速度相对最慢,但胜在稳定,断电也不怕数据丢失。
memory channel,速度最快,但断电数据就会丢失
kafka channel,适合需要将数据最后导入kafka集群的场景。

  • 选择sink时,可以根据需求,如jdbc sink,hdfs sink等
  1. flume是有事务功能,体现在2个阶段,source到channel,channel到sink,事务的本质就是进行一个批量操作并且记录这个批量操作的执行状态。flume的事务在三种事务实现理念中选择的是at least once(另外2种是at most once, exactly once)。特别情况下,数据会有重复。
  2. flume有拦截器,选择器,监控器。
  • 拦截器就是在数据进入source之后,可以对每条数据做过滤,拦截,打标记。
  • 选择器就是可以根据每条数据的特征如拦截器打上的标记对数据做有选择分发分流。
  • 监控器,顾名思义,可以对flume做状态监控

flume的最小采集单位是agent,一个agent中由3个模块组成,source,channel,sink。
可以将一个agent看做是一个水泵,source就是进水口,channel就是水泵缓冲空间,sink就是出水口。channel是用来平衡进水口和出水口之间的速度差异的。
agent之间可以按照需求进行级联,组成网络。

注意,如果使用hdfs sink,则注意设置rollSize、rollInterval、rollCount来避免大量小文件产生。

2.3 kafka 削峰平谷,解耦,异步

  1. kafka是一个分布式消息缓存框架,内部按照topic对消息进行存储。为了保证数据安全,会有数据副本partition。
  2. kafka中,有producer和consumer生产者和消费者2种角色
  3. partition数据副本种,也有leader和follower区分。
  4. kafka因为有数据副本机制,为了权衡数据吞吐量和数据一致性,设计了ack机制。

当ack为0时,只要kafka收到了数据,不管有没有写入到内存或者硬盘中,都返回ok。
当ack为1时,只要所有ISR(in synchronizing replication)数据副本中有一个是写入了数据,就返回ok。
如果ack为-1,则所有ISR数据副本都写入成功才会返回ok。
所以,一般选择ack为1,兼顾吞吐量和数据安全性

  1. kafka的分区分配策略,range(默认)、roundrobin、sticky(在roundrobin上优化,不会对分区做再分配)
  2. exactly once = at least once + 幂等,并不是纯粹的精确一次。保证一部分数据不重复,不丢失。当kafka集群宕机,一部分数据可能会重复。
  3. kafka的高可用和zookeeper相关,在0.9版本之前,一个topic中消息的偏移量offset保存在zookeeper中,这一点和跟多框架是一样的做法。在0.9版本之后,kafka自己保存了一个offset记录。
  4. kafka的数据读写,如果涉及到磁盘,采取的是顺序读写机制,采用Pagecache,0拷贝的方式来保证读写效率。
  1. pagecache:
    Kafka重度依赖底层操作系统提供的PageCache功能。当上层有写操作时,操作系统只是将数据写入PageCache,同时标记Page属性为Dirty。当读操作发生时,先从PageCache中查找,如果发生缺页才进行磁盘调度,最终返回需要的数据。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。同时如果有其他进程申请内存,回收PageCache的代价又很小,所以现代的OS都支持PageCache。

这里大家应该知道,为什么程序员电脑标配变成了16GB内存,部分程序员开始上32GB甚至64GB内存,特别程序员直接用服务器级别,128GB甚至256GB内存的原因就在于此

  1. 0拷贝
    传统的网络I/O操作流程,大体上分为以下4步。
    <1. OS从硬盘把数据读到内核区的PageCache。
    <2. 用户进程把数据从内核区Copy到用户区。
    ❤️. 然后用户进程再把数据写入到Socket,数据流入内核区的Socket Buffer上。
    <4. OS再把数据从Buffer中Copy到网卡的Buffer上,这样完成一次发送。
    其中2、3两步没有必要,完全可以直接在内核区完成数据拷贝,0拷贝就是做这个工作的
  1. kafka事务,producer事务和consumer事务;producer事务,因为维护了一个开分区的全局id,即使整个服务器重启,因为事务状态保存下来,进行中事务可以得到恢复,进而可以继续。

2.4 sqoop 结构化数据和分布式存储之间互相传输(阿里的dataX也很不错)

  1. sqoop属于hadoop生态,底部就是运行一个mapreduce程序进行数据传输,不过只有map阶段,没有reduce阶段。
  2. 注意sqoop导入导出null的问题,因为hive的null,mysql的null存储形式不一致,需要做sqoop的参数设置来预防。
  • 这一点其实在数仓的ODS层做数据格式规范化一样需要注意 。有时候一个公司不同部门,对于相同类型数据定义都会千差万别,如果跨公司合作,就更需要注意这一点。
  1. sqoop底层就是一个mapreduce程序,所以也需要注意数据倾斜问题。split-by按照某一列切分表,num-mappers启动多少个map进行数据导入。解决数据倾斜,一般是想办法增加并行度,调整数据划分规则等方法。当然,有钱可以直接加机器内存配置,也是ok的。
  2. 如果使用sqoop往mysql导入数据,注意不要使用orc或者parquet文件格式,换为text文件格式。
  • 实际上,在大数据企业开发中,hive偏爱orc格式,在hive中,orc格式文件读写查询都是很高效率的,比parquet还高。但parquet文件格式,各个框架对它支持更好,所以很多时候大数据开发文件存储一般使用parquet。
  • 为什么不使用text,因为这个不可以压缩,数据还是最原始方式,parquet则可以压缩,有索引,列式存储等各种优点。
  • sqoop中设置参数,直接将parquet转为text,也可以使用临时表做转换,还可以建表时就不把需要导出数据到mysql的表建立为parquet。

2.5 spark streaming 流式处理

  1. 不是所有业务场景都适合或者使用流式处理
  2. spark streaming是一个准实时处理框架,采用微批次概念。如果是真正的流式处理,使用flink会更加合适。
  3. 常见坑
  1. spark streaming第一次运行数据丢失
    将kafka参数的auto.offset.reset设置成earliest
  2. spark streaming精准一次消费
    ①手动维护偏移量 ②处理完业务数据后,再进行提交偏移量操作
  3. spark streaming控制每秒消费数据速度
    spark.streaming.kafka.maxRatePerPartition参数来设置
    Spark Streaming从kafka分区每秒拉取的条数
  4. spark streaming 背压机制
    把spark.streaming.backpressure.enabled 参数设置为ture,开启背压机制后Spark Streaming会根据延迟动态去kafka消费数据,上限由spark.streaming.kafka.maxRatePerPartition参数控制,所以两个参数一般会一起使用。其实就是更加智能化,通过kafka输入数据流速设置来控制spark streaming的消费速度。
  5. Spark Streaming 一个stage耗时:
    Spark Streaming stage耗时由最慢的task决定,所以数据倾斜时某个task运行慢会导致整个Spark Streaming都运行非常慢。也就是木桶理论。这也是为什么要防止分布式运行时发生数据倾斜的原因
  6. Spark Streaming 默认分区个数:
    Spark Streaming默认分区个数与所对接的kafka topic分区个数一致,Spark Streaming里一般不会使用repartition算子增大分区,因为repartition会进行shuffle增加耗时
  7. Spark Streaming消费kafka数据的两种方式:
    ①ReceiverAPI:需要一个专门的Executor去接收数据,然后发送给其他的Executor做计算。存在的问题,接收数据的Executor和计算的Executor速度会有所不同,特别在接收数据的Executor速度大于计算的Executor速度,会导致计算数据的节点内存溢出
    ②DirectAPI:是由计算的Executor来主动消费Kafka的数据,速度由自身控制
  8. SparkStreaming窗口函数的原理:
    窗口函数就是在原来定义的SparkStreaming计算批次大小的基础上再次进行封装,每次计算多个批次的数据,同时还需要传递一个滑动步长的参数,用来设置当次计算任务完成之后下一次从什么地方开始计算.

2.6 HDFS和Yarn

2.6.1 HDFS

  1. HDFS负责文件的存储和备份,海量数据目前主流的大数据框架还是HDFS。
  2. HDFS拿到的数据一般是按照分类,一天一个目录,特别场景,可能还需要针对小时建立子目录。
    注意,海量数据处理中,不管是ODS,DW层(DWD、DWS)、ADS的数据,一般都会按照天进行数据存储,这样方便对数据做管理。分区表的概念在这里体现的很彻底
  3. HDFS小文件处理

因为HDFS机制,namenode存储每一个文件的元数据信息,这个元数据信息是占据一定空间150字节,太多的小文件会极大消耗namenode,而namenode在hdfs运行时需要加载到内存中来应对HDFS集群中的快速查询和修改。
解决办法一般如下几种

  1. har归档方式,将多个小文件放入到一个文件中,一般自定义inputformat,将多个小文件数据放入sequenceFile中
  2. 采用CombineTextInputFormat,这个会将小文件合并到一次,整体达到128MB时再切片,减少切片次数,降低maptask开启个数。(默认是一个文件一个maptask,而分布式计算不适合处理小文件在于任务分发,预处理,网络传输就需要占据很多时间,实际处理小文件耗时可能小于这些耗时)
  3. 开启jvm重用(注意有小文件才开启)
    Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。
    缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。
  1. shuffle过程及其优化
  1. map端join
  2. 数据倾斜预防
    – 提前在map端combine,减少传输数据量
    –导致数据倾斜的key,想办法打散,如增加随机字符串
    –增加reducer数量,增加并行度
    –做自定义分区器,自定定义key分区规则
    –加机器配置(有钱土豪专用办法,氪金大法,一个TB内存,四路CPU走起)

2.6.2 Yarn

  1. yarn是一个资源调度平台,在此之上,可以运行mapreduce,可以运行spark等程序。
  2. yarn主要角色是resource manager,node manager,app master。
  • 当一个程序想要运行在yarn上时,需要先跟resource manager提交程序
  • 然后resource manager会分配一个节点做为app master,
  • 这个app master先根据提交的程序地址信息,把程序相关数据下载下来,然后计算程序运行所需要的资源,然后再把资源信息发送给resource manager,resource manager将这个程序安排进任务队列中,然后根据集群资源情况,安排任务运行。
  • 当资源足够时,就会安排程序运行,这时候resource manager就会把集群节点信息告诉app master,然后app master跟这些节点通信,将任务和数据信息分发下去,然后调度这些task的运行,如MR程序,就会分为map task和reduce task运行。
  1. yarn的调度器,FIFO,容量Capacity调度器,公平调度器。
  • apache默认是容量调度器,CDH默认是公平调度器,当并行度要求高,采用公平调度器。
  • yarn任务队列,默认是default一个。
  • 一般按照业务或者执行引擎进行队列创建,这样有利于进行任务优先级管理,也可以做任务隔离,防止一个程序出错,卡死所有任务队列
  1. 注意,Yarn对于任务程序也是有限制的,不过可以调整。同样的,对于硬件资源默认占用,也有设置,默认8GB内存,8核心占用。如果是高配置机器,注意调整这个参数,否则配置再高,Yarn也不会去使用。
  1. 对于硬件资源占用上,Yarn继承了Hadoop时代的思想,21世纪初,硬件资源如CPU和内存还是很宝贵,所以计算时,中间会有大量数据落地到磁盘,一是保证数据稳定性,一是降低对CPU和内存的占用,保证程序在低配置集群机器上也可以运行起来。
  2. 而2016年才开源的clickhouse已经完全不一样了,默认就会压榨50%一半的CPU资源,速度很快。这种思想也完全不一样了,现在硬件资源相对便宜很多,也充裕很多了。
  3. 现在有相当一部分大数据框架往纯内存方面发展,其中技术的基础假定就是硬件资源主要是内存资源更加充裕,不用怀疑,512GB内存甚至1TB内存单节点的集群已经有土豪公司在使用了。这样带来的一个影响就是,纯内存数据库,纯内存大数据计算框架更加旁边,以后也会变得更多,如impala这种框架。

2.7 Hive

  1. hive本质可以看做是一个转换器,将sql转换为mapreduce、tez、spark程序运行
  2. hive可以将结构化数据转换为一张表,方便使用sql对这些数据做查询
  3. hive的表元数据存储在数据库中,企业开发一般配置将元数据存储到mysql中(为什么不是oracle,因为穷,阿里巴巴都用不起才搞去IOE化),数据本身存储在HDFS中。
  4. hive概念
  • 客户端,
  • meta store(元数据存放默认在derby数据库中,一般配置在mysql中)
  • hive转换流程(sql编译器,解析器,优化器,执行器)
  • 执行引擎(MR、Tez、Spark)
  • 存储,HDFS
  1. hive和mysql比较
  • hive适合存放海量结构化数据,小批量数据反而不适合
  • mysql则适合小而美数据,功能也更加完善和强大
  • 查询速度,hive在海量数据时快,mysql在小数据量时遥遥领先
  • mysql适合增删改查,hive只擅长查询
  1. hive内部表和外部表
  • 内部表,hive会将hdfs中对应数据迁移到表对应文件夹下,删除表时,会把数据文件一起删除。这个适合存放业务数据
  • 外部表,hive不会讲将hdfs对应数据迁移到表对应文件夹下,删除表时,数据文件不会受影响。
  • 实际企业开发中,一般都是建立外部表,因为数据是很重要的资产。
  1. hive小技巧
  • 使用distinct时,一般可以使用先group by 再处理的方式替代distinct
  • order by是全局排序,使用要注意
  • sort by是每个reducer中内部先排序
  • distribute by(MR中自定义分区,结合sort by可以很好利用分布式处理的优点),类似先在每个分区排序,最后结果归并,这样要快很多。
  • cluster by(distribute by和sort by字段相同时使用)
  • map join默认打开,不要关闭
  • 行列过滤
  • 建立分区表,一般年月日来分区,查询快
  • 合理设置map,reduce个数,这个没有定数,看业务需求而来
  • 小文件合并
  1. 函数
  • over 开窗
  • rank 开窗
  • row number
  • first value
  • udf自定义函数(udaf,udtf)

2.8 数据分层

  1. DIM 维度表,其实从数据上来说,可以把维度表看成是一种映射表
  • 因为数据存储一般不会把所有信息都存在一张表里面,那样的化,表太大。
  • 而且数据也不好复用。例如省市区信息一般会使用id来代表省市区,其他表格中就存储这个id,需要时再从这个维度表查询
  • 这样一个大的信息块,就可以拆分为多个小的信息块,还方便复用。这就跟做代码拆分分层是一个道理。
  1. ODS,这是贴源层,也就操作数据层,最原始的数据就放在这一层,数据量也是最大的,保存时间相对来说也是最短的,一般保存3个月。
  • ODS,大部分公司都是存储行为日志数据为主,日志数据属于半结构化数据,一般json格式为主。
  • 这一层数据采集回来的时候,一般会做一些基本数据预处理,例如数据分区保存,数据分类分流等等
  1. DWD,数据明细层,将数据从ODS层抽离到DWD层,会对数据做进一步的处理
  • 去除json中废弃字段,或者无效字段。这个在行为日志改版的迭代中,由于用户的app版本更新不及时等原因,会比较常遇到
  • 过滤掉json格式错误的数据,也就是常说的脏数据
  • 过滤掉缺失了关键信息的日志数据,这个很多时候由于埋点代码bug等原因会导致关键信息缺失
  • 过滤掉不符合时间段的数据,因为DWD数据是从每天ODS中每天的数据采集,例如5号凌晨0点30分开始采集4号的数据,如果这时候发现了3号的数据,就抛弃掉。也有公司会另存,然后重新导入到 ODS层去。但由于网络和日志上报机制原因,无法彻底解决日志数据延迟到达的问题。
  • 有一些公司还会对爬虫数据做基本过滤,这个一般是web日志。不过由于先在爬虫框架和爬虫技术越来越强大,简单过滤作用不大。
  1. DWS层,一般为数据服务层,基于DWD做轻度聚合,或者做大宽表(join各种维度表),或者做服务层表(类似提前把一部分ADS功能下放到DWS层做预先聚合处理)

  2. ADS,应用服务层,一般这里对接的就是各种公司需求方,如产品,运营,财务等部门。这一层的数据聚合程度也是最高的。这一层的数据,很多时候存放到mysql、HBase等可以做纳秒级响应的数据存储服务中。
    OLAP引擎很多时候会从这里直接拿数据,有的公司直接使用mysql结合superset做OLAP

3. 总结

  1. 数仓并不适合每个公司,数仓适合处理海量数据,如果数据量不是很大,数据分析需求不大,可以直接使用ELK套件,或者直接买神策的服务即可。
  2. 数仓目前由于技术生态以及业务需求多变的原因,没有一个统一的框架可以应对所有业务需求,所以数仓一般灵活架构。
  • 数据会分层
  • 技术框架一般会有多套,有适合离线业务的,有适合实时处理的,有适合智能推荐的,有适合OLAP数据处理的,有适合自定义多维度查询的,具体业务,具体分析。没有一个单一框架可以应对所有业务需求
  • 技术框架比较多,框架之间版本兼容也是很令人头疼的问题,CDH应运而生,但CDH问题就是兼容性没问题,但一个是高级功能需要付费,一个是里面框架版本相对较老。使用apache 框架,则版本需要自己摸索,可能一不小心就会遇到一个版本兼容问题。
  1. 数仓只是技术,最终技术为业务服务,所以很多公司的数仓会经历很多次技术变革来应对业务变化,没有一层不变的技术框架,有时候公司整体业务方向调整,整个数仓技术需要重新选型都是有可能的。例如先在国内已经在逐步从离线数仓往实时数仓转变,带来好处就是实时性更高,坏处就是技术挑战更大,迁移成本高昂。
  2. 大数据技术日新月异,在确立了技术框架之后,每个技术层级选用什么框架,都是需要谨慎考量的。因为大数据部门不是独立运作,往往需要跟业务后台,前端,运营甚至财务部门协作,需要兼顾这些部门的业务需求以及技术框架来做技术选型,还需要充分考虑后续业务发展和变化,更重要是使用和学习门槛,不是每个公司中团队都大牛如云,修改源码轻轻松松。

你可能感兴趣的:(大数据,实时数仓,离线数仓,数据仓库,大数据,cloudera,数据库)