Hadoop详细介绍
Hadoop是一个分布式系统基础架构,由Apache基金会开发。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力高速运算和存储。Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有着高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上。而且它提供高传输率(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求(requirements)这样可以流的形式访问(streaming access)文件系统中的数据。
分布式文件系统HDFS
Hadoop Distributed File System,简称HDFS,是一个分布式文件系统。HDFS有着高容错性(fault-tolerent)的特点,并且设计用来部署在低廉的(low-cost)硬件上。而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求(requirements)这样可以实现流的形式访问(streaming access)文件系统中的数据。HDFS开始是为开源的apache项目nutch的基础结构而创建,HDFS是hadoop项目的一部分,而hadoop又是lucene的一部分。
大规模数据集软件架构MapReduce
MapReduce是Google提出的一个软件架构,用于大规模数据集(大于1TB)的并行运算。概念”Map(映射)”和”Reduce(化简)”,和他们的主要思想,都是从函数式编程语言借来的,还有从矢量编程语言借来的特性。
当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(化简)函数,用来保证所有映射的键值对中的每一个共享相同的键组。
YAEN详细介绍
YARN是新一代Hadoop资源管理器,通过YARN,用户可以运行和管理同一个物理集群机上的多种作业,例如MapReduce批处理和图形处理作业。这样不仅可以巩固一个组织管理的系统数目,而且可以对相同的数据进行不同类型的数据分析。某些情况下,整个数据流可以执行在同一个集群机上。
Hive详细介绍
Hive是一个基于Hadoop的数据仓库平台。通过hive,我们可以方便地进行ETL的工作。hive定义了一个类似于SQL的查询语言:HQL,能 够将用户编写的QL转化为相应的Mapreduce程序基于Hadoop执行。
Hive是Facebook 2008年8月刚开源的一个数据仓库框架,其系统目标与 Pig 有相似之处,但它有一些Pig目前还不支持的机制,比如:更丰富的类型系统、更类似SQL的查询语言、Table/Partition元数据的持久化等。
Hcatalog 详细介绍
Apache HCatalog是基于Apache Hadoop之上的数据表和存储管理服务。
包括:
Pig详细介绍
Pig是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin,该语言的编译器会把类SQL的数据分析请求转换为一系列经过优化处理的MapReduce运算。Pig为复杂的海量数据并行计算提供了一个简单的操作和编程接口。
Apache Ambari 详细介绍
Apache Ambari是一个基于Web的Apache Hadoop集群的供应、管理和监控。Ambari目前已支持大多数Hadoop组件,包括HDFS、MapReduce、Hive、Pig、 Hbase、Zookeper、Sqoop和Hcatalog等。
Apache Ambari 支持HDFS、MapReduce、Hive、Pig、Hbase、Zookeper、Sqoop和Hcatalog等的集中管理。也是5个顶级hadoop管理工具之一。
Ambari主要取得了以下成绩:
Ambari使用Ganglia收集度量指标,用Nagios支持系统报警,当需要引起管理员的关注时(比如,节点停机或磁盘剩余空间不足等问题),系统将向其发送邮件。
此外,Ambari能够安装安全的(基于Kerberos)Hadoop集群,以此实现了对Hadoop 安全的支持,提供了基于角色的用户认证、授权和审计功能,并为用户管理集成了LDAP[轻量目录访问协议]和Active Directory。
Ganglia详细介绍
Ganglia是用于高性能计算系统(如集群和网格)的可扩展分布式监控系统。它基于针对集群联盟的分层设计。它利用广泛使用的技术,例如用于数据表示的XML,用于紧凑型,便携式数据传输的XDR和用于数据存储和可视化的RRDtool。它使用精心设计的数据结构和算法来实现非常低的每节点开销和高并发性。该实现是强大的,已被移植到广泛的操作系统和处理器架构,目前正在世界各地的数千个集群中使用。它已经被用来连接大学校园和世界各地的群集,并且可以扩展到处理具有2000个节点的群集。
Nagios
Nagios是一个监视系统运行状态和网络信息的监视系统。Nagios能监视所指定的本地或远程主机以及服务,同时提供异常通知功能等
Nagios可运行在Linux/Unix平台之上,同时提供一个可选的基于浏览器的WEB界面以方便系统管理人员查看网络状态,各种系统问题,以及日志等等。
Nagios 有一个 Windows 下的客户端: http://www.oschina.net/p/nsclientpp
Nagios的主要功能特点:
Apache Spark详细介绍
Apache Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。
Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。
尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoo 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。
Cloudera Impala详细的介绍
Cloudera 发布实时查询开源项目 Impala (黑斑羚)!多款产品实测表明,比原来基于MapReduce的Hive SQL查询速度提升3~90倍。Impala是Google Dremel的模仿,但在SQL功能上青出于蓝胜于蓝。
Impala采用与Hive相同的元数据、SQL语法、ODBC驱动程序和用户接口(Hue Beeswax),这样在使用CDH产品时,批处理和实时查询的平台是统一的。目前支持的文件格式是文本文件和SequenceFiles(可以压缩为Snappy、GZIP和BZIP,前者性能最好)。其他格式如Avro, RCFile, LZO文本和Doug Cutting的Trevni将在正式版中支持。
Parquet详细介绍
Parquet是一种面向列存存储的文件格式,Cloudera的大数据在线分析(OLAP)项目Impala中使用该格式作为列存储。
Apache Parquet 是一个列存储格式,主要用于 Hadoop 生态系统。对数据处理框架、数据模型和编程语言无关。
Apache Kylin详细介绍
Apache Kylin 是一个开源的分布式的 OLAP 分析引擎,来自 eBay 公司开发,基于 Hadoop 提供 SQL 接口和 OLAP 接口,支持 TB 到 PB 级别的数据量。
Apache kylin是:
Apache kylin总结的特点
其他值得关注的特性包括:
Apache Storm详细介绍
Apache Storm 的前身是 Twitter Storm 平台,目前已经归于 Apache 基金会管辖。
Apache Storm 是一个免费开源的分布式实时计算系统。简化了流数据的可靠处理,像 Hadoop 一样实现实时批处理。Storm 很简单,可用于任意编程语言。Apache Storm 采用 Clojure 开发。
Storm 有很多应用场景,包括实时数据分析、联机学习、持续计算、分布式 RPC、ETL 等。Storm 速度非常快,一个测试在单节点上实现每秒一百万的组处理。
目前已经有包括阿里百度在内的数家大型互联网公司在使用该平台。
Zookeeper详细介绍
ZooKeeper是Hadoop的正式子项目,它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
Zookeeper是Google的Chubby一个开源的实现.是高有效和可靠的协同工作系统.Zookeeper能够用来leader选举,配置信息维护等.在一个分布式的环境中,我们需要一个Master实例或存储一些配置信息,确保文件写入的一致性等.Zookeeper能够保证如下3点:
Watches are ordered with respect to other events, other watches, and
asynchronous replies. The ZooKeeper client libraries ensures that
everything is dispatched in order.
A client will see a watch event for a znode it is watching before seeing the new data that corresponds to that znode.
The order of watch events from ZooKeeper corresponds to the order of the updates as seen by the ZooKeeper service.
在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据.如果在创建znode时Flag设置 为EPHEMERAL,那么当这个创建这个znode的节点和Zookeeper失去连接后,这个znode将不再存在在Zookeeper 里.Zookeeper使用Watcher察觉事件信息,当客户端接收到事件信息,比如连接超时,节点数据改变,子节点改变,可以调用相应的行为来处理数 据.Zookeeper的Wiki页面展示了如何使用Zookeeper来处理事件通知,队列,优先队列,锁,共享锁,可撤销的共享锁,两阶段提交.
那么Zookeeper能帮我们作什么事情呢?简单的例子:假设我们我们有个20个搜索引擎的服务器(每个负责总索引中的一部分的搜索任务)和一个 总服务器(负责向这20个搜索引擎的服务器发出搜索请求并合并结果集),一个备用的总服务器(负责当总服务器宕机时替换总服务器),一个web的 cgi(向总服务器发出搜索请求).搜索引擎的服务器中的15个服务器现在提供搜索服务,5个服务器正在生成索引.这20个搜索引擎的服务器经常要让正在 提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以搜索提供服务了.使用Zookeeper可以保证总服务器自动 感知有多少提供搜索引擎的服务器并向这些服务器发出搜索请求,备用的总服务器宕机时自动启用备用的总服务器,web的cgi能够自动地获知总服务器的网络 地址变化.这些又如何做到呢?
提供搜索引擎的服务器都在Zookeeper中创建znode,zk.create(“/search/nodes/node1”,
“hostname”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateFlags.EPHEMERAL);
总服务器可以从Zookeeper中获取一个znode的子节点的列表,zk.getChildren(“/search/nodes”, true);
总服务器遍历这些子节点,并获取子节点的数据生成提供搜索引擎的服务器列表.
当总服务器接收到子节点改变的事件信息,重新返回第二步.
总服务器在Zookeeper中创建节点,zk.create(“/search/master”, “hostname”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateFlags.EPHEMERAL);
备用的总服务器监控Zookeeper中的”/search/master”节点.当这个znode的节点数据改变时,把自己启动变成总服务器,并把自己的网络地址数据放进这个节点.
web的cgi从Zookeeper中”/search/master”节点获取总服务器的网络地址数据并向其发送搜索请求.
web的cgi监控Zookeeper中的”/search/master”节点,当这个znode的节点数据改变时,从这个节点获取总服务器的网络地址数据,并改变当前的总服务器的网络地址.
Sqoop详细介绍
Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导入到Hadoop的HDFS中,也可以将HDFS的数据导入到关系型数据库中。
Apache Flume详细介绍
Flume 是一个分布式、可靠和高可用的服务,用于收集、聚合以及移动大量日志数据,使用一个简单灵活的架构,就流数据模型。这是一个可靠、容错的服务。
Kafka详细介绍
Kafka是一种高吞吐量的分布式发布订阅消息系统,她有如下特性:
kafka的目的是提供一个发布订阅解决方案,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。
Apache Tez详细介绍
Tez 是 Apache 最新的支持 DAG 作业的开源计算框架,它可以将多个有依赖的作业转换为一个作业从而大幅提升DAG作业的性能。Tez并不直接面向最终用户——事实上它允许开发者为最终用户构建性能更快、扩展性更好的应用程序。Hadoop传统上是一个大量数据批处理平台。但是,有很多用例需要近乎实时的查询处理性能。还有一些工作则不太适合MapReduce,例如机器学习。Tez的目的就是帮助Hadoop处理这些用例场景。
Oozie 详细介绍
ozie 是一个开源的工作流和协作服务引擎,基于 Apache Hadoop 的数据处理任务。Oozie 是可扩展的、可伸缩的面向数据的服务,运行在Hadoop 平台上。
Oozie 包括一个离线的Hadoop处理的工作流解决方案,以及一个查询处理 API。
MongoDB详细介绍
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
内部架构
它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:
所谓“面向集合”(Collenction-Orented),意思是数据被分组存储在数据集中,被称为一个集合(Collenction)。每个 集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定 义任何模式(schema)。
模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各中复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized dOcument Format)。
Neo4j详细介绍
Neo4j是一个网络——面向网络的数据库——也就是说,它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络上而不是表中。网络(从数学角度叫做图)是一个灵活的数据结构,可以应用更加敏捷和快速的开发模式。
你可以把Neo4j看作是一个高性能的图引擎,该引擎具有成熟和健壮的数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。
Apache Avro详细介绍
Avro(读音类似于[ævrə])是Hadoop的一个子项目,由Hadoop的 创始人Doug Cutting(也是Lucene,Nutch等项目的创始人)牵头开发。Avro是一个数据序列化系统,设计用于支持大 批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro提供的机制使动态语言可以方便地处理 Avro数据。
Kubernetes详细介绍
Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
Kubernetes一个核心的特点就是能够自主的管理容器来保证云平台中的容器按照用户的期望状态运行着(比如用户想让apache一直运行,用户不需要关心怎么去做,Kubernetes会自动去监控,然后去重启,新建,总之,让apache一直提供服务),管理员可以加载一个微型服务,让规划器来找到合适的位置,同时,Kubernetes也系统提升工具以及人性化方面,让用户能够方便的部署自己的应用(就像canary deployments)。
现在Kubenetes着重于不间断的服务状态(比如web服务器或者缓存服务器)和原生云平台应用(Nosql),在不久的将来会支持各种生产云平台中的各种服务,例如,分批,工作流,以及传统数据库。
在Kubenetes中,所有的容器均在Pod中运行,一个Pod可以承载一个或者多个相关的容器,在后边的案例中,同一个Pod中的容器会部署在同一个物理机器上并且能够共享资源。一个Pod也可以包含O个或者多个磁盘卷组(volumes),这些卷组将会以目录的形式提供给一个容器,或者被所有Pod中的容器共享,对于用户创建的每个Pod,系统会自动选择那个健康并且有足够容量的机器,然后创建类似容器的容器,当容器创建失败的时候,容器会被node agent自动的重启,这个node agent叫kubelet,但是,如果是Pod失败或者机器,它不会自动的转移并且启动,除非用户定义了 replication controller。
用户可以自己创建并管理Pod,Kubernetes将这些操作简化为两个操作:基于相同的Pod配置文件部署多个Pod复制品;创建可替代的Pod当一个Pod挂了或者机器挂了的时候。而Kubernetes API中负责来重新启动,迁移等行为的部分叫做“replication controller”,它根据一个模板生成了一个Pod,然后系统就根据用户的需求创建了许多冗余,这些冗余的Pod组成了一个整个应用,或者服务,或者服务中的一层。一旦一个Pod被创建,系统就会不停的监控Pod的健康情况以及Pod所在主机的健康情况,如果这个Pod因为软件原因挂掉了或者所在的机器挂掉了,replication controller 会自动在一个健康的机器上创建一个一摸一样的Pod,来维持原来的Pod冗余状态不变,一个应用的多个Pod可以共享一个机器。
我们经常需要选中一组Pod,例如,我们要限制一组Pod的某些操作,或者查询某组Pod的状态,作为Kubernetes的基本机制,用户可以给Kubernetes Api中的任何对象贴上一组 key:value的标签,然后,我们就可以通过标签来选择一组相关的Kubernetes Api 对象,然后去执行一些特定的操作,每个资源额外拥有一组(很多) keys 和 values,然后外部的工具可以使用这些keys和vlues值进行对象的检索,这些Map叫做annotations(注释)。
Kubernetes支持一种特殊的网络模型,Kubernetes创建了一个地址空间,并且不动态的分配端口,它可以允许用户选择任何想使用的端口,为了实现这个功能,它为每个Pod分配IP地址。
现代互联网应用一般都会包含多层服务构成,比如web前台空间与用来存储键值对的内存服务器以及对应的存储服务,为了更好的服务于这样的架构,Kubernetes提供了服务的抽象,并提供了固定的IP地址和DNS名称,而这些与一系列Pod进行动态关联,这些都通过之前提到的标签进行关联,所以我们可以关联任何我们想关联的Pod,当一个Pod中的容器访问这个地址的时候,这个请求会被转发到本地代理(kube proxy),每台机器上均有一个本地代理,然后被转发到相应的后端容器。Kubernetes通过一种轮训机制选择相应的后端容器,这些动态的Pod被替换的时候,Kube proxy时刻追踪着,所以,服务的 IP地址(dns名称),从来不变。
所有Kubernetes中的资源,比如Pod,都通过一个叫URI的东西来区分,这个URI有一个UID,URI的重要组成部分是:对象的类型(比如pod),对象的名字,对象的命名空间,对于特殊的对象类型,在同一个命名空间内,所有的名字都是不同的,在对象只提供名称,不提供命名空间的情况下,这种情况是假定是默认的命名空间。UID是时间和空间上的唯一。
Hue详细介绍
Hue 是运营和开发Hadoop应用的图形化用户界面。Hue程序被整合到一个类似桌面的环境,以web程序的形式发布,对于单独的用户来说不需要额外的安装。
Nanocubes 详细介绍
Nanocubes 是一个大数据可视化的工具,32Tb Twitter数据,在一台16GB内存的机器上流畅、交互式地可视化。
HTools详细介绍
HTools是一款专业的Hadoop管理工具,不管您是非专业IT人士,还是多年经验的技术人员,本工具都会为您提供优质的管理服务和轻松的操作过程, 释放无谓的工作压力,提高Hadoop的管理水平。我们以最权威的专家为您量身定做的Hadoop管理工具,本系统提供优秀的用户体验,让您能够轻松的管 理Hadoop集群环境。
友善的向导式操作流程
图形报表、日志分析供您明了查看各节点使用情况
智能诊断,修复故障并发出短信、邮件故障告警
图形化UI、拖拖拽拽即可管理管理HDFS数据
傻瓜式操作优化Hadoop,方便快捷
免客户端部署,无需安装HTools客户端
版本控制灵活,不绑定Hadoop的JDK版本
一键智能搜索当前网段可部署节点
支持多个Hadoop集群同时监管
支持同时管理多个Hadoop集群和节点
支持7 × 24小时多集群实时监控
支持节点热插拔,服务不间断的情况下随时对节点进行扩展和调整
支持系统配置文件的推送和同步
PrestoDB详细介绍
Presto是Facebook最新研发的数据查询引擎,可对250PB以上的数据进行快速地交互式分析。据称该引擎的性能是 Hive 的 10 倍以上。
PrestoDB 是 Facebook 推出的一个大数据的分布式 SQL 查询引擎。可对从数 G 到数 P 的大数据进行交互式的查询,查询的速度达到商业数据仓库的级别。
Presto 可以查询包括 Hive、Cassandra 甚至是一些商业的数据存储产品。单个 Presto 查询可合并来自多个数据源的数据进行统一分析。
Presto 的目标是在可期望的响应时间内返回查询结果。Facebook 在内部多个数据存储中使用 Presto 交互式查询,包括 300PB 的数据仓库,超过 1000 个 Facebook 员工每天在使用 Presto 运行超过 3 万个查询,每天扫描超过 1PB 的数据。此外包括 Airbnb 和 Dropbox 也在使用 Presto 产品。
Presto 是一个分布式系统,运行在集群环境中,完整的安装包括一个协调器 (coordinator) 和多个 workers。查询通过例如 Presto CLI 的客户端提交到协调器,协调器负责解析、分析和安排查询到不同的 worker 上执行。
此外,Presto 需要一个数据源来运行查询。当前 Presto 包含一个插件用来查询 Hive 上的数据,要求:
Hadoop CDH4
远程 Hive metastore service
Presto 不使用 MapReduce ,只需要 HDFS
Apache Beam详细介绍
Apache Beam 是 Apache 软件基金会越来越多的数据流项目中最新增添的成员,是 Google 在2016年2月份贡献给 Apache 基金会的孵化项目。
这个项目的名称表明了设计:结合了批处理(Batch)模式和数据流(Stream)处理模式。它基于一种统一模式,用于定义和执行数据并行处理管道(pipeline),这些管理随带一套针对特定语言的SDK用于构建管道,以及针对特定运行时环境的Runner用于执行管道。
Apache Beam 的主要目标是统一批处理和流处理的编程范式,为无限,乱序,web-scale的数据集处理提供简单灵活,功能丰富以及表达能力十分强大的SDK。Apache Beam项目重点在于数据处理的编程范式和接口定义,并不涉及具体执行引擎的实现,Apache Beam希望基于Beam开发的数据处理程序可以执行在任意的分布式计算引擎上。
OpenSOC详细介绍
OpenSOC:安全大数据分析框架。OpenSOC已经加入Apache工程改名为Apache Metron。
思科在 BroCON 大会上亮相了其安全大数据分析架构 OpenSOC,引起了广泛关注。OpenSOC 是一个针对网络包和流的大数据分析框架,它是大数据分析与安全分析技术的结合, 能够实时的检测网络异常情况并且可以扩展很多节点,它的存储使用开源项目 Hadoop,实时索引使用开源项目 ElasticSearch,在线流分析使用著名的开源项目 Storm。OpenSOC 概念性体系架构如下图所示:
OpenSOC 主要功能包括:
可扩展的接收器和分析器能够监视任何Telemetry数据源
是一个扩展性很强的框架,且支持各种Telemetry数据流
支持对Telemetry数据流的异常检测和基于规则实时告警
通过预设时间使用Hadoop存储Telemetry的数据流
支持使用ElasticSearch实现自动化实时索引Telemetry数据流
支持使用Hive利用SQL查询存储在Hadoop中的数据
能够兼容ODBC/JDBC和继承已有的分析工具
具有丰富的分析应用,且能够集成已有的分析工具
支持实时的Telemetry搜索和跨Telemetry的匹配
支持自动生成报告、和异常报警
支持原数据包的抓取、存储、重组
支持数据驱动的安全模型
OpenSOC 官方文档介绍了以下五大优点:
由思科全力支持,适用于内部多用户
免费、开源、基于Apache协议授权
基于高可扩展平台(Hadoop、Kafka、Storm)实现
基于可扩展的插件式设计
具有灵活的部署模式,可在企业内部部署或者云端部署
具有集中化的管理流程、人员和数据
Apache Metron详细介绍
Apache Metron 是一个网络安全的实时数据处理、分析、查询、可视化框架。
Metron 集成了各种开源大数据技术,为安全监控和分析提供了集中工具。 Metron 拥有支持大规模摄取、处理、检索与信息可视化的所有适当元素,一些关键的网络数据将推动数据保护、监控、分析与检测,并且有助于对恶意的非法行为予以回应。
亮点包括:
捕获、存储和规范化所有类型的安全机制;
高速远程检测;
实时处理和应用改进;
高效信息存储;
提供通过系统传递的数据和警报的集中视图的接口
使用统计摘要数据结构,即使在最大的数据集上也可执行安全分析
JStorm 详细介绍
JStorm 是参考 Apache Storm 实现的实时流式计算框架,在网络IO、线程模型、资源调度、可用性及稳定性上做了持续改进,已被越来越多企业使用。JStorm 可以看作是 storm 的java增强版本,除了内核用纯java实现外,还包括了thrift、python、facet ui。从架构上看,其本质是一个基于zk的分布式调度系统
JStorm 的性能是Apache Storm 的4倍, 可以自由切换行模式或 mini-batch 模式:
]]>编程题A:求一个整数的平方根,不保留小数。
编程题B:
1、hadoop集群、namenode如何做到数据同步?
2、hdfs副本存放策略
3、HA如何在挂掉一台namenode节点的状态下,自动切换到另一台?
4、mapreduce shuffle过程
5、mapreduce优化
1、你能二次源码修改支持parquent格式吗?
1、抽取某个数据库下的某张表+条件 怎么抽取?
2、sqoop增量导入
1、rowkey如何设计
2、hbase热点问题
3、协处理器
4、hbase优化
5、hbase的二级索引
1、数据倾斜
2、hive能加索引吗?
1、rdd dataset dataframe 概念
2、mapflat
3、spark资源分配
1、怎么保证数据零丢失?和spark streaming结合说说看?
2、怎么解决数据重复问题?
3、某个kafka节点挂掉对生产和消费有影响吗?
4、生产大于消费 lag产生大量的滞后怎么解决?
1、btree
2、索引
3、拉链表
1、如何查找在Linux目录下的某个文本里的包含相关内容的操作?
大数据零基础:
1.VMware Workstation9 下安装 CentOS6.5( 安装图文教程 )
2.Linux最常用命令及快捷键整理
3.配置多台机器SSH相互通信信任
4.Memory参数,你真的懂吗?
5.yum安装xxx包时出错,提示No package xxx available.
6.CentOS6.x使用163和epel yum源的选择
7.Centos6.5 python2.6.6 升级到2.7.5
8.CentOS清理swap和buffer/cache
9.记录在shell脚本中使用sudo echo x > 时,抛Permission denied错误
1.Hadoop2.8.1全网最详细编译
2.Hadoop全网最详细的伪分布式部署(HDFS)
3.Hadoop全网最详细的伪分布式部署(MapReduce+Yarn)
4.Hadoop常用命令大全01
5.Hadoop-2.7.2+zookeeper-3.4.6完全分布式环境搭建(HDFS、YARN HA)
6.Hadoop2.x 参数汇总
7.YARN的Memory和CPU调优配置详解
8.资源调度yarn之生产详解
12.Hadoop之Yarn架构设计(command memory cpu)
1.Hive全网最详细的编译及部署
2.Hive DDL,你真的了解吗?
3.Hive自定义函数(UDF)的编程开发,你会吗?
4.Hive自定义函数(UDF)的部署使用,你会吗?
5. 2min快速了解,Hive内部表和外部表
6. 5min掌握,Hive的HiveServer2 和JDBC客户端&代码的生产使用
7.生产中Hive静态和动态分区表,该怎样抉择呢?
9.从Hive中的stored as file_foramt看hive调优
[11.hive实战 (https://blog.csdn.net/liweihope/article/details/88584985)
1.大数据压缩格式,你们真的了解吗?
2.Hive压缩格式的生产应用
3.大数据存储格式,你们真的了解吗?
4.Hive存储格式的生产应用
批处理ETL已亡,Kafka才是数据处理的未来【buy视频】
1.Spark2.2.0 全网最详细的源码编译
2.Spark-2.2.0-bin-2.6.0-cdh5.12.1.tgz 编译方法总结!
3.生产改造Spark1.6源代码,create table语法支持Oracle列表分区
4.Spark History Server Web UI配置
5.Spark on YARN-Cluster和YARN-Client的区别
6.Spark RDD、DataFrame和DataSet的区别
7.Spark RDD、DataFrame和DataSet的区别
10.Spark调优的关键之——RDD Cache缓存使用详解
13.Spark SQL 外部数据源(External DataSource)
15.Apache Spark 技术团队开源机器学习平台 MLflow
16.生产开发必用-Spark RDD转DataFrame的两种方法
17.最前沿!带你读Structured Streaming重量级论文!
18.Apache Spark和DL/AI结合,谁与争锋? 期待Spark3.0的到来!
20.Spark Streaming 状态管理函数,你了解吗
1.数据Flink实战系列
2.最全的Flink部署及开发案例(KafkaSource+SinkToMySQL)
大数据之实时数据源同步中间件–生产上Canal与Maxwell颠峰对决
1.Java可扩展线程池之ThreadPoolExecutor
生产项目:
1.Spark实时分析预警平台(架构+提交流程+现场排错)【free视频】
2.Spark实时分析预警平台项目(在进阶班课表)
3.Strom互联网金融实时计算与分析项目(在进阶班课表)
4.构建企业级PaaS平台项目(在进阶班课表)
1.基于Spark的某互联网直播平台大数据分析项目实战第3季,正在报名!单击查看前2季的目录.
2.线下班生产项目第10期,国庆节线下4天课程,正在报名!
大数据平台运维:
1.CDH下载各种软件包
2.CDH4/5集群正确启动和停止顺序
3.CDH5 快速入门手册v1.0(体系架构+目录详解)
4.CDH4/5配置文件之深度解析
5.CDH5之Trash
1.记录一次帮网友解决CDH集群机器的时钟偏差
2.CDH集群机器,安装多个CDH版,会出现命令找不到,如hadoop,hdfs等等
3.CDH5.8.2安装之Hash verification failed
4.记录CDH Spark2的spark2-submit的一个No such file or directory问题
5.记录CDH5.10一个clients.NetworkClient: Bootstrap broker ip:9092 disconnected问题
6.记录自定义kafka的parcel库,CDH安装kafka服务,无法安装过去的排雷过程
7.记录CDH安装的一个坑:could not contact scm server at localhost:7182, giving up
8.CDH5之Found class jline.Terminal, but interface was expected
9.CDH5之Exhausted available authentication methods
10.CDH5之Unexpected error.Unable to verify database connection
Hadoop2.x、Zookeeper、Flume、Hive、Hbase、Kafka、Spark2.x、SparkStreaming、MySQL、Hue、J2EE、websoket、Echarts
目标
1、完成大数据项目的架构设计,安装部署,架构继承与开发、用户可视化交互设计
2、完成实时在线数据分析
3、完成离线数据分析
具体功能
1)捕获用户浏览日志信息
2)实时分析前20名流量最高的新闻话题
3)实时统计当前线上已曝光的新闻话题
4)统计哪个时段用户浏览量最高
5)报表
Hadoop2.x、Zookeeper、Flume、Hive、Hbase
Kafka、Spark2.x、SparkStreaming
MySQL、Hue、J2EE、websoket、Echarts
虚拟机: VMware、centos
虚拟机ssh: SecureCRT(在windows上链接多个虚拟机)
修改源码:idea
查看各种数据:notepad++(安装NppFTP插件,修改虚拟机中配置文件,好用的一批)
所有软件下载地址:
链接:https://pan.baidu.com/s/1aF_VmdXJVIjeB0WzAtfeEQ
提取码:cuao
图片来自于卡夫卡公司
利用VMware虚拟机+centos完成,基本要求笔记本电脑内存在8G以上。
最低要去克隆出3台虚拟机,每台给2G内存。
1、第一章:项目需求分析与设计
https://www.willxu.xyz/2018/12/19/project/1%E3%80%81%E9%A1%B9%E7%9B%AE%E9%9C%80%E6%B1%82/
2、第二章:linux环境准备与设置
https://www.willxu.xyz/2018/12/19/project/2%E3%80%81linux%E9%85%8D%E7%BD%AE/
3、第三章:Hadoop2.X分布式集群部署
https://www.willxu.xyz/2018/12/19/project/3%E3%80%81hadoop%E9%83%A8%E7%BD%B2/
4、第四章:Zookeeper分布式集群部署
https://www.willxu.xyz/2018/12/29/project/4%E3%80%81zk%E9%83%A8%E7%BD%B2/
5、第五章:hadoop的高可用配置(HA)
https://www.willxu.xyz/2018/12/29/project/5%E3%80%81ha%E5%AE%9E%E7%8E%B0/
6、第六章:hadoop的HA下的高可用HBase部署
https://www.willxu.xyz/2018/12/30/project/6%E3%80%81hbase%E9%83%A8%E7%BD%B2/
7、第七章:Kafka简介和分布式部署
https://www.willxu.xyz/2019/01/01/project/7%E3%80%81kafka%E9%83%A8%E7%BD%B2/
8、第八章:Flume简介和分布式部署
https://www.willxu.xyz/2019/01/01/project/8%E3%80%81flume%E9%83%A8%E7%BD%B2/
9、第九章:Flume源码修改与HBase+Kafka集成
https://www.willxu.xyz/2019/01/20/project/9%E3%80%81flume-hbase-kfk%E9%85%8D%E7%BD%AE/
10、第十章:Flume+HBase+Kafka集成全流程测试
https://www.willxu.xyz/2019/01/20/project/10%E3%80%81flume-hbase-kfk%E8%81%94%E8%B0%83/
11、第十一章:mysql、Hive安装与集成
https://www.willxu.xyz/2019/01/22/project/11%E3%80%81mysql-hive/
12、第十二章:Hive与Hbase集成
https://www.willxu.xyz/2019/01/23/project/12%E3%80%81hive-hbase/
13、第十三章:Cloudera HUE大数据可视化分析
https://www.willxu.xyz/2019/01/26/project/13%E3%80%81hue/
14、第十四章:Spark2.X集群安装与spark on yarn部署
https://www.willxu.xyz/2019/01/30/project/14%E3%80%81spark%20on%20yarn/
15、第十五章:基于IDEA环境下的Spark2.X程序开发
https://www.willxu.xyz/2019/01/30/project/15%E3%80%81spark-idea/
16、第十六章:Spark Streaming实时数据处理
https://www.willxu.xyz/2019/02/03/project/16%E3%80%81spark-streaming1/
链接:https://pan.baidu.com/s/1-PQta6SCgps91oFNTkl6Qg
提取码:sh8x
]]>Zookeeper 是 一个典型的分布式数据一致性的解决方案.
Zookeeper的典型应用场景:
zookeeper有两种运行模式: 集群模式和单机模式,还有一种伪集群模式,在单机模式下模拟集群的zookeeper服务
zookeeper 的核心是原子广播,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 zab 协议。 zab 协议有两种模式,分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,zab 就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。
客户端端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,然后客户端可以根据 znode 变化来做出业务上的改变
使用zookeeper实现分布式锁的算法流程,假设锁空间的根节点为/lock:
常见的分布式一致性协议有: 两阶段提交协议,三阶段提交协议,向量时钟,RWN协议,paxos协议,Raft协议. zk采用的是paxos协议.
两阶段提交协议,简称2PC,是比较常用的解决分布式事务问题的方式,要么所有参与进程都提交事务,要么都取消事务,即实现ACID中的原子性(A)的常用手段。
3PC就是在2PC基础上将2PC的提交阶段细分位两个阶段:预提交阶段和提交阶段
通过向量空间祖先继承的关系比较, 使数据保持最终一致性,这就是向量时钟的基本定义。
NWR是一种在分布式存储系统中用于控制一致性级别的一种策略。在Amazon的Dynamo云存储系统中,就应用NWR来控制一致性。
让我们先来看看这三个字母的含义:
N:在分布式存储系统中,有多少份备份数据
W:代表一次成功的更新操作要求至少有w份数据写入成功
R: 代表一次成功的读数据操作要求至少有R份数据成功读取
NWR值的不同组合会产生不同的一致性效果,当W+R>N的时候,整个系统对于客户端来讲能保证强一致性。当W+R 以常见的N=3、W=2、R=2为例:
N=3,表示,任何一个对象都必须有三个副本(Replica),W=2表示,对数据的修改操作(Write)只需要在3个Replica中的2个上面完成就返回,R=2表示,从三个对象中要读取到2个数据对象,才能返回。
在分布式系统中,数据的单点是不允许存在的。即线上正常存在的Replica数量是1的情况是非常危险的,因为一旦这个Replica再次错误,就 可能发生数据的永久性错误。假如我们把N设置成为2,那么,只要有一个存储节点发生损坏,就会有单点的存在。所以N必须大于2。N约高,系统的维护和整体 成本就越高。工业界通常把N设置为3。
当W是2、R是2的时候,W+R>N,这种情况对于客户端就是强一致性的。
这里选取3台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器Server1启动时,其单独无法进行和完成Leader选举,当第二台服务器Server2启动时,此时两台机器可以相互通信,每台机器都试图找到Leader,于是进入Leader选举过程。选举过程如下
(1) 每个Server发出一个投票。由于是初始情况,Server1和Server2都会将自己作为Leader服务器来进行投票,每次投票会包含所推举的服务器的myid和ZXID,使用(myid, ZXID)来表示,此时Server1的投票为(1, 0),Server2的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
(2) 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
(3) 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行PK,PK规则如下
· 优先检查ZXID。ZXID比较大的服务器优先作为Leader。
· 如果ZXID相同,那么就比较myid。myid较大的服务器作为Leader服务器。
对于Server1而言,它的投票是(1, 0),接收Server2的投票为(2, 0),首先会比较两者的ZXID,均为0,再比较myid,此时Server2的myid最大,于是更新自己的投票为(2, 0),然后重新投票,对于Server2而言,其无须更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
(4) 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于Server1、Server2而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了Leader。
(5) 改变服务器状态。一旦确定了Leader,每个服务器就会更新自己的状态,如果是Follower,那么就变更为FOLLOWING,如果是Leader,就变更为LEADING。
在3.4.0后的Zookeeper的版本只保留了TCP版本的FastLeaderElection选举算法。当一台机器进入Leader选举时,当前集群可能会处于以下两种状态
· 集群中已经存在Leader。
· 集群中不存在Leader。
对于集群中已经存在Leader而言,此种情况一般都是某台机器启动得较晚,在其启动之前,集群已经在正常工作,对这种情况,该机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器而言,仅仅需要和Leader机器建立起连接,并进行状态同步即可。而在集群中不存在Leader情况下则会相对复杂,其步骤如下
(1) 第一次投票。无论哪种导致进行Leader选举,集群的所有机器都处于试图选举出一个Leader的状态,即LOOKING状态,LOOKING机器会向所有其他机器发送消息,该消息称为投票。投票中包含了SID(服务器的唯一标识)和ZXID(事务ID),(SID, ZXID)形式来标识一次投票信息。假定Zookeeper由5台机器组成,SID分别为1、2、3、4、5,ZXID分别为9、9、9、8、8,并且此时SID为2的机器是Leader机器,某一时刻,1、2所在机器出现故障,因此集群开始进行Leader选举。在第一次投票时,每台机器都会将自己作为投票对象,于是SID为3、4、5的机器投票情况分别为(3, 9),(4, 8), (5, 8)。
(2) 变更投票。每台机器发出投票后,也会收到其他机器的投票,每台机器会根据一定规则来处理收到的其他机器的投票,并以此来决定是否需要变更自己的投票,这个规则也是整个Leader选举算法的核心所在,其中术语描述如下
· vote_sid:接收到的投票中所推举Leader服务器的SID。
· vote_zxid:接收到的投票中所推举Leader服务器的ZXID。
· self_sid:当前服务器自己的SID。
· self_zxid:当前服务器自己的ZXID。
每次对收到的投票的处理,都是对(vote_sid, vote_zxid)和(self_sid, self_zxid)对比的过程。
规则一:如果vote_zxid大于self_zxid,就认可当前收到的投票,并再次将该投票发送出去。
规则二:如果vote_zxid小于self_zxid,那么坚持自己的投票,不做任何变更。
规则三:如果vote_zxid等于self_zxid,那么就对比两者的SID,如果vote_sid大于self_sid,那么就认可当前收到的投票,并再次将该投票发送出去。
规则四:如果vote_zxid等于self_zxid,并且vote_sid小于self_sid,那么坚持自己的投票,不做任何变更。
结合上面规则,给出下面的集群变更过程。
(3) 确定Leader。经过第二轮投票后,集群中的每台机器都会再次接收到其他机器的投票,然后开始统计投票,如果一台机器收到了超过半数的相同投票,那么这个投票对应的SID机器即为Leader。此时Server3将成为Leader。
由上面规则可知,通常那台服务器上的数据越新(ZXID会越大),其成为Leader的可能性越大,也就越能够保证数据的恢复。如果ZXID相同,则SID越大机会越大。
]]>Producer:消息生产者
Producer可以发送消息到Topic
Producer发送消息后,可以选择是否要确认消息写入成功(ACK,Acknowledgment)
消息key:Producer可以给消息加上key,带相同key的消息会被分发到同一个Partition,这样就可以保证带相同key的消息的消费是有序的
Broker:每个Broker里包含了不同Topic的不同Partition,Partition中包含了有序的消息
Consumer:消息消费者
Consumer可以从Topic读取消息进行消费
Consumer Group:
Consumer offset:
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 同 ActiveMQ | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
功能支持 | MQ 领域的功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
此问题其实等价于保证消息队列消费的幂等性
主要需要结合实际业务来操作:
唯一可能导致消费者弄丢数据的情况,就是说,你消费到了这个消息,然后消费者那边自动提交了 offset,让 Kafka 以为你已经消费好了这个消息,但其实你才刚准备处理这个消息,你还没处理,你自己就挂了,此时这条消息就丢咯。
这不是跟 RabbitMQ 差不多吗,大家都知道 Kafka 会自动提交 offset,那么只要关闭自动提交 offset,在处理完之后自己手动提交 offset,就可以保证数据不会丢。但是此时确实还是可能会有重复消费,比如你刚处理完,还没提交 offset,结果自己挂了,此时肯定会重复消费一次,自己保证幂等性就好了。
生产环境碰到的一个问题,就是说我们的 Kafka 消费者消费到了数据之后是写到一个内存的 queue 里先缓冲一下,结果有的时候,你刚把消息写入内存 queue,然后消费者会自动提交 offset。然后此时我们重启了系统,就会导致内存 queue 里还没来得及处理的数据就丢失了。
这块比较常见的一个场景,就是 Kafka 某个 broker 宕机,然后重新选举 partition 的 leader。大家想想,要是此时其他的 follower 刚好还有些数据没有同步,结果此时 leader 挂了,然后选举某个 follower 成 leader 之后,不就少了一些数据?这就丢了一些数据啊。
生产环境也遇到过,我们也是,之前 Kafka 的 leader 机器宕机了,将 follower 切换为 leader 之后,就会发现说这个数据就丢了。
所以此时一般是要求起码设置如下 4 个参数:
replication.factor
参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。min.insync.replicas
参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。acks=all
:这个是要求每条数据,必须是写入所有 replica 之后,才能认为是写成功了。retries=MAX
(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里了。我们生产环境就是按照上述要求配置的,这样配置之后,至少在 Kafka broker 端就可以保证在 leader 所在 broker 发生故障,进行 leader 切换时,数据不会丢失。
如果按照上述的思路设置了 acks=all
,一定不会丢,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。
Spark Streaming使用Direct模式对接上游kafka。无论kafka有多少个partition, 使用Direct模式总能保证SS中有相同数量的partition与之相对, 也就是说SS中的KafkaRDD的并发数量在Direct模式下是由上游kafka决定的。 在这个模式下,kafka的offset是作为KafkaRDD的一部分存在,会存储在checkpoints中, 由于checkpoints只存储offset内容,而不存储数据,这就使得checkpoints是相对轻的操作。 这就使得SS在遇到故障时,可以从checkpoint中恢复上游kafka的offset,从而保证exactly once
第一种“鸵鸟做法”,就是期望下游(数据)具有幂等特性。
多次尝试总是写入相同的数据,例如,saveAs***Files 总是将相同的数据写入生成的文件
使用事务更新
所有更新都是事务性的,以便更新完全按原子进行。这样做的一个方法如下: 使用批处理时间(在foreachRDD中可用)和RDD的partitionIndex(分区索引)来创建identifier(标识符)。 该标识符唯一地标识streaming application 中的blob数据。 使用该identifier,blob 事务地更新到外部系统中。也就是说,如果identifier尚未提交,则以 (atomicall)原子方式提交分区数据和identifier。否则,如果已经提交,请跳过更新。
ack=0/1/-1的不同情况:
Ack = 0
producer不等待broker的ack,broker一接收到还没有写入磁盘就已经返回,当broker故障时有可能丢失数据;
Ack = 1
producer等待broker的ack,partition的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将会丢失数据;
Ack = -1
producer等待broker的ack,partition的leader和follower全部落盘成功后才返回ack,数据一般不会丢失,延迟时间长但是可靠性高。
生产中主要以 Ack=-1为主,如果压力过大,可切换为Ack=1. Ack=0的情况只能在测试中使用.
如果consumer要找offset是1008的消息,那么,
1,按照二分法找到小于1008的segment,也就是00000000000000001000.log和00000000000000001000.index
2,用目标offset减去文件名中的offset得到消息在这个segment中的偏移量。也就是1008-1000=8,偏移量是8。
3,再次用二分法在index文件中找到对应的索引,也就是第三行6,45。
4,到log文件中,从偏移量45的位置开始(实际上这里的消息offset是1006),顺序查找,直到找到offset为1008的消息。查找期间kafka是按照log的存储格式来判断一条消息是否结束的。
log.cleanup.policy=delete启用删除策略
将数据压缩,只保留每个key最后一个版本的数据。
首先在broker的配置中设置log.cleaner.enable=true启用cleaner,这个默认是关闭的。
在topic的配置中设置log.cleanup.policy=compact启用压缩策略。
如上图,在整个数据流中,每个Key都有可能出现多次,压缩时将根据Key将消息聚合,只保留最后一次出现时的数据。这样,无论什么时候消费消息,都能拿到每个Key的最新版本的数据。
压缩后的offset可能是不连续的,比如上图中没有5和7,因为这些offset的消息被merge了,当从这些offset消费消息时,将会拿到比这个offset大的offset对应的消息,比如,当试图获取offset为5的消息时,实际上会拿到offset为6的消息,并从这个位置开始消费。
这种策略只适合特俗场景,比如消息的key是用户ID,消息体是用户的资料,通过这种压缩策略,整个消息集里就保存了所有用户最新的资料。
压缩策略支持删除,当某个Key的最新版本的消息没有内容时,这个Key将被删除,这也符合以上逻辑。
Field | Description |
---|---|
Attributes | 该字节包含有关消息的元数据属性。 最低的2位包含用于消息的压缩编解码器。 其他位应设置为0。 |
Crc | CRC是消息字节的其余部分的CRC32。 这用于检查代理和使用者上的消息的完整性。 |
key是用于分区分配的可选参数。 key可以为null。 | |
MagicByte | 这是用于允许向后兼容的消息二进制格式演变的版本ID。 当前值为0。 |
Offset | 这是kafka中用作日志序列号的偏移量。 当producer发送消息时,它实际上并不知道偏移量,并且可以填写它喜欢的任何值。 |
Value | 该值是实际的消息内容,作为不透明的字节数组。 Kafka支持递归消息,在这种情况下,它本身可能包含消息集。 消息可以为null。 |
kafka 不能脱离 zookeeper 单独使用,因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器。
kafka 有两种数据保存策略:按照过期时间保留和按照存储的消息大小保留。
这个时候 kafka 会执行数据清除工作,时间和大小不论那个满足条件,都会清空数据。
]]>Hbase主要包含HMaster/HRegionServer/Zookeeper
HRegionServer 负责实际数据的读写. 当访问数据时, 客户端直接与RegionServer通信.
HBase的表根据Row Key的区域分成多个Region, 一个Region包含这这个区域内所有数据. 而Region server负责管理多个Region, 负责在这个Region server上的所有region的读写操作.
HMaster 负责管理Region的位置, DDL(新增和删除表结构)
Zookeeper 负责维护和记录整个Hbase集群的状态
zookeeper探测和记录Hbase集群中服务器的状态信息.如果zookeeper发现服务器宕机,它会通知Hbase的master节点.
RowKey长度原则
Rowkey是一个二进制码流,Rowkey的长度被很多开发者建议说设计在10~100个字节,不过建议是越短越好,不要超过16个字节。
原因如下:
数据的持久化文件HFile中是按照KeyValue存储的,如果Rowkey过长比如100个字节,1000万列数据光Rowkey就要占用100*1000万=10亿个字节,将近1G数据,这会极大影响HFile的存储效率;
MemStore将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低,系统将无法缓存更多的数据,这会降低检索效率。因此Rowkey的字节长度越短越好。
目前操作系统是都是64位系统,内存8字节对齐。控制在16个字节,8字节的整数倍利用操作系统的最佳特性。
RowKey散列原则
如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率。
RowKey唯一原则
必须在设计上保证其唯一性。
Hbase的优点及应用场景:
Hbase的缺点:
HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。
配置HBase高可用,只需要启动两个HMaster,让Zookeeper自己去选择一个Master Acitve即可
zk的在这里起到的作用就是用来管理master节点,以及帮助hbase做master选举
对表内数据的增删查改是可以正常进行的,因为hbase client 访问数据只需要通过 zookeeper 来找到 rowkey 的具体 region 位置即可. 但是对于创建表/删除表等的操作就无法进行了,因为这时候是需要HMaster介入, 并且region的拆分,合并,迁移等操作也都无法进行了
首先,客户端需要获知其想要读取的信息的Region的位置,这个时候,Client访问hbase上数据时并不需要Hmaster参与(HMaster仅仅维护着table和Region的元数据信息,负载很低),只需要访问zookeeper,从meta表获取相应region信息(地址和端口等)。【Client请求ZK获取.META.所在的RegionServer的地址。】
客户端会将该保存着RegionServer的位置信息的元数据表.META.进行缓存。然后在表中确定待检索rowkey所在的RegionServer信息(得到持有对应行键的.META表的服务器名)。【获取访问数据所在的RegionServer地址】
根据数据所在RegionServer的访问信息,客户端会向该RegionServer发送真正的数据读取请求。服务器端接收到该请求之后需要进行复杂的处理。
先从MemStore找数据,如果没有,再到StoreFile上读(为了读取的效率)。
当 Flink 集群启动后,首先会启动一个 JobManger 和一个或多个的 TaskManager。由 Client 提交任务给 JobManager,JobManager 再调度任务到各个 TaskManager 去执行,然后 TaskManager 将心跳和统计信息汇报给 JobManager。TaskManager 之间以流的形式进行数据的传输。上述三者均为独立的 JVM 进程。
以yarn模式Per-job方式为例概述作业提交执行流程
当执行executor() 之后,会首先在本地client 中将代码转化为可以提交的 JobGraph
如果提交为Per-Job模式,则首先需要启动AM, client会首先向资源系统申请资源, 在yarn下即为申请container开启AM, 如果是Session模式的话则不需要这个步骤
Yarn分配资源, 开启AM
在谈到 flink 所实现的 exactly-once语义时,主要是2个层面上的,首先 flink在0.9版本以后已经实现了基于state的内部一致性语义, 在1.4版本以后也可以实现端到端 Exactly-Once语义
Flink 提供 exactly-once 的状态(state)投递语义,这为有状态的(stateful)计算提供了准确性保证。也就是状态是不会重复使用的,有且仅有一次消费
这里需要注意的一点是如何理解state语义的exactly-once,并不是说在flink中的所有事件均只会处理一次,而是所有的事件所影响生成的state只有作用一次.
在上图中, 假设每两条消息后出发一次checkPoint操作,持久化一次state. TaskManager 在 处理完 event c 之后被shutdown, 这时候当 JobManager重启task之后, TaskManager 会从 checkpoint 1 处恢复状态,重新执行流处理,也就是说 此时 event c 事件 的的确确是会被再一次处理的. 那么 这里所说的一致性语义是何意思呢? 本身,flink每处理完一条数据都会记录当前进度到 state中, 也就是说在 故障前, 处理完 event c 这件事情已经记录到了state中,但是,由于在checkPoint 2 之前, 就已经发生了宕机,那么 event c 对于state的影响并没有被记录下来,对于整个flink内部系统来说就好像没有发生过一样, 在 故障恢复后, 当触发 checkpoint 2 时, event c 的 state才最终被保存下来. 所以说,可以这样理解, 进入flink 系统中的 事件 永远只会被 一次state记录并checkpoint下来,而state是永远不会发生重复被消费的, 这也就是 flink内部的一致性语义,就叫做 状态 Exactly once.
2017年12月份发布的Apache Flink 1.4版本,引进了一个重要的特性:TwoPhaseCommitSinkFunction.,它抽取了两阶段提交协议的公共部分,使得构建端到端Excatly-Once的Flink程序变为了可能。这些外部系统包括Kafka0.11及以上的版本,以及一些其他的数据输入(data sources)和数据接收(data sink)。它提供了一个抽象层,需要用户自己手动去实现Exactly-Once语义.
为了提供端到端Exactly-Once语义,除了Flink应用程序本身的状态,Flink写入的外部存储也需要满足这个语义。也就是说,这些外部系统必须提供提交或者回滚的方法,然后通过Flink的checkpoint来协调
Flink 中定义一个窗口主要需要以下三个组件。
Window Assigner:用来决定某个元素被分配到哪个/哪些窗口中去。
Trigger:触发器。决定了一个窗口何时能够被计算或清除,每个窗口都会拥有一个自己的Trigger。
Evictor:可以译为“驱逐者”。在Trigger触发之后,在窗口被处理之前,Evictor(如果有Evictor的话)会用来剔除窗口中不需要的元素,相当于一个filter。
首先上图中的组件都位于一个算子(window operator)中,数据流源源不断地进入算子,每一个到达的元素都会被交给 WindowAssigner。WindowAssigner 会决定元素被放到哪个或哪些窗口(window),可能会创建新窗口。因为一个元素可以被放入多个窗口中,所以同时存在多个窗口是可能的。注意,Window
本身只是一个ID标识符,其内部可能存储了一些元数据,如TimeWindow
中有开始和结束时间,但是并不会存储窗口中的元素。窗口中的元素实际存储在 Key/Value State 中,key为Window
,value为元素集合(或聚合值)。为了保证窗口的容错性,该实现依赖了 Flink 的 State 机制(参见 state 文档)。
每一个窗口都拥有一个属于自己的 Trigger,Trigger上会有定时器,用来决定一个窗口何时能够被计算或清除。每当有元素加入到该窗口,或者之前注册的定时器超时了,那么Trigger都会被调用。Trigger的返回结果可以是 continue(不做任何操作),fire(处理窗口数据),purge(移除窗口和窗口中的数据),或者 fire + purge。一个Trigger的调用结果只是fire的话,那么会计算窗口并保留窗口原样,也就是说窗口中的数据仍然保留不变,等待下次Trigger fire的时候再次执行计算。一个窗口可以被重复计算多次知道它被 purge 了。在purge之前,窗口会一直占用着内存。
当Trigger fire了,窗口中的元素集合就会交给Evictor
(如果指定了的话)。Evictor 主要用来遍历窗口中的元素列表,并决定最先进入窗口的多少个元素需要被移除。剩余的元素会交给用户指定的函数进行窗口的计算。如果没有 Evictor 的话,窗口中的所有元素会一起交给函数进行计算。
计算函数收到了窗口的元素(可能经过了 Evictor 的过滤),并计算出窗口的结果值,并发送给下游。窗口的结果值可以是一个也可以是多个。DataStream API 上可以接收不同类型的计算函数,包括预定义的sum()
,min()
,max()
,还有 ReduceFunction
,FoldFunction
,还有WindowFunction
。WindowFunction 是最通用的计算函数,其他的预定义的函数基本都是基于该函数实现的。
Flink 对于一些聚合类的窗口计算(如sum,min)做了优化,因为聚合类的计算不需要将窗口中的所有数据都保存下来,只需要保存一个result值就可以了。每个进入窗口的元素都会执行一次聚合函数并修改result值。这样可以大大降低内存的消耗并提升性能。但是如果用户定义了 Evictor,则不会启用对聚合窗口的优化,因为 Evictor 需要遍历窗口中的所有元素,必须要将窗口中所有元素都存下来。
flink中的窗口主要分为3大类共5种窗口:
Time Window 时间窗口
Tumbing Time Window 滚动时间窗口
实现统计每一分钟(或其他长度)窗口内 计算的效果
Sliding Time Window 滑动时间窗口
实现每过xxx时间 统计 xxx时间窗口的效果. 比如,我们可以每30秒计算一次最近一分钟用户购买的商品总数。
Count Window 计数窗口
Tumbing Count Window 滚动计数窗口
当我们想要每100个用户购买行为事件统计购买总数,那么每当窗口中填满100个元素了,就会对窗口进行计算,这种窗口我们称之为翻滚计数窗口(Tumbling Count Window)
Sliding Count Window 滑动计数窗口
和Sliding Time Window含义是类似的,例如计算每10个元素计算一次最近100个元素的总和
Session Window 会话窗口
在这种用户交互事件流中,我们首先想到的是将事件聚合到会话窗口中(一段用户持续活跃的周期),由非活跃的间隙分隔开。如上图所示,就是需要计算每个用户在活跃期间总共购买的商品数量,如果用户30秒没有活动则视为会话断开(假设raw data stream是单个用户的购买行为流)
Apache Flink内部有四种state的存储实现,具体如下:
flink的反压经历了两个发展阶段,分别是基于TCP的反压(<1.5)和基于credit的反压(>1.5)
flink中的消息发送通过RS(ResultPartition),消息接收通过IC(InputGate),两者的数据都是以 LocalBufferPool的形式来存储和提取,进一步的依托于Netty的NetworkBufferPool,之后更底层的便是依托于TCP的滑动窗口机制,当IC端的buffer池满了之后,两个task之间的滑动窗口大小便为0,此时RS端便无法再发送数据
基于TCP的反压最大的问题是会造成整个TaskManager端的反压,所有的task都会受到影响
RS与IC之间通过backlog和credit来确定双方可以发送和接受的数据量的大小以提前感知,而不是通过TCP滑动窗口的形式来确定buffer的大小之后再进行反压
flink可以以多种方式部署,包括standlone模式/yarn/Mesos/Kubernetes/Docker/AWS/Google Compute Engine/MAPR等
一般公司中主要采用 on yarn模式
Flink作业提交有两种类型:
需要先启动集群,然后在提交作业,接着会向yarn申请一块空间后,资源永远保持不变。如果资源满了,下一个作业就无法提交,只能等到yarn中的其中一个作业执行完成后,释放了资源,那下一个作业才会正常提交.
客户端模式
对于客户端模式而言,你可以启动多个yarn session,一个yarn session模式对应一个JobManager,并按照需求提交作业,同一个Session中可以提交多个Flink作业。如果想要停止Flink Yarn Application,需要通过yarn application -kill命令来停止.
分离式模式
对于分离式模式,并不像客户端那样可以启动多个yarn session,如果启动多个,会出现下面的session一直处在等待状态。JobManager的个数只能是一个,同一个Session中可以提交多个Flink作业。如果想要停止Flink Yarn Application,需要通过yarn application -kill命令来停止
直接在YARN上提交运行Flink作业(Run a Flink job on YARN),这种方式的好处是一个任务会对应一个job,即没提交一个作业会根据自身的情况,向yarn申请资源,直到作业执行完成,并不会影响下一个作业的正常运行,除非是yarn上面没有任何资源的情况下
Session | |
---|---|
共享Dispatcher和Resource Manager | Dispatcher和Resource Manager |
共享资源(即 TaskExecutor) | 按需要申请资源 (即 TaskExecutor) |
适合规模小,执行时间短的作业 |
Flink中有三种时间概念,分别是 Processing Time、Event Time 和 Ingestion Time
Processing Time 是指事件被处理时机器的系统时间。
当流程序在 Processing Time 上运行时,所有基于时间的操作(如时间窗口)将使用当时机器的系统时间。每小时 Processing Time 窗口将包括在系统时钟指示整个小时之间到达特定操作的所有事件
Event Time 是事件发生的时间,一般就是数据本身携带的时间。这个时间通常是在事件到达 Flink 之前就确定的,并且可以从每个事件中获取到事件时间戳。在 Event Time 中,时间取决于数据,而跟其他没什么关系。Event Time 程序必须指定如何生成 Event Time 水印,这是表示 Event Time 进度的机制
Ingestion Time 是事件进入 Flink 的时间。 在源操作处,每个事件将源的当前时间作为时间戳,并且基于时间的操作(如时间窗口)会利用这个时间戳
Ingestion Time 在概念上位于 Event Time 和 Processing Time 之间。 与 Processing Time 相比,它稍微贵一些,但结果更可预测。因为 Ingestion Time 使用稳定的时间戳(在源处分配一次),所以对事件的不同窗口操作将引用相同的时间戳,而在 Processing Time 中,每个窗口操作符可以将事件分配给不同的窗口(基于机器系统时间和到达延迟)
与 Event Time 相比,Ingestion Time 程序无法处理任何无序事件或延迟数据,但程序不必指定如何生成水印
会话窗口主要是将某段时间内活跃度较高的数据聚合成一个窗口进行计算,窗口的触发条件是 Session Gap, 是指在规定的时间内如果没有数据活跃接入,则认为窗口结束,然后触发窗口结果
Session Windows窗口类型比较适合非连续性数据处理或周期性产生数据的场景,根据用户在线上某段时间内的活跃度对用户行为进行数据统计
1 | val sessionWindowStream = inputStream |
Session Window 本质上没有固定的起止时间点,因此底层计算逻辑和Tumbling窗口及Sliding 窗口有一定的区别,
Session Window 为每个进入的数据都创建了一个窗口,最后再将距离窗口Session Gap 最近的窗口进行合并,然后计算窗口结果
]]>Cluster Manager(Master):在standalone模式中即为Master主节点,控制整个集群,监控worker。在YARN模式中为资源管理器
Worker节点:从节点,负责控制计算节点,启动Executor或者Driver。
Driver: 运行Application 的main()函数
Executor:执行器,是为某个Application运行在worker node上的一个进程
spark中的shuffle主要有3种:
Hash Shuffle 2.0以后移除
在map阶段(shuffle write),每个map都会为下游stage的每个partition写一个临时文件,假如下游stage有1000个partition,那么每个map都会生成1000个临时文件,一般来说一个executor上会运行多个map task,这样下来,一个executor上会有非常多的临时文件,假如一个executor上运行M个map task,下游stage有N个partition,那么一个executor上会生成MN个文件。另一方面,如果一个executor上有K个core,那么executor同时可运行K个task,这样一来,就会同时申请KN个文件描述符,一旦partition数较多,势必会耗尽executor上的文件描述符,同时生成K*N个write handler也会带来大量内存的消耗。
在reduce阶段(shuffle read),每个reduce task都会拉取所有map对应的那部分partition数据,那么executor会打开所有临时文件准备网络传输,这里又涉及到大量文件描述符,另外,如果reduce阶段有combiner操作,那么它会把网络中拉到的数据保存在一个HashMap
中进行合并操作,如果数据量较大,很容易引发OOM操作。
Sort Shuffle 1.1开始(sort shuffle也经历过优化升级,详细见参考文章1)
在map阶段(shuffle write),会按照partition id以及key对记录进行排序,将所有partition的数据写在同一个文件中,该文件中的记录首先是按照partition id排序一个一个分区的顺序排列,每个partition内部是按照key进行排序存放,map task运行期间会顺序写每个partition的数据,并通过一个索引文件记录每个partition的大小和偏移量。这样一来,每个map task一次只开两个文件描述符,一个写数据,一个写索引,大大减轻了Hash Shuffle大量文件描述符的问题,即使一个executor有K个core,那么最多一次性开K*2个文件描述符。
在reduce阶段(shuffle read),reduce task拉取数据做combine时不再是采用HashMap
,而是采用ExternalAppendOnlyMap
,该数据结构在做combine时,如果内存不足,会刷写磁盘,很大程度的保证了鲁棒性,避免大数据情况下的OOM。
Unsafe Shuffle 1.5开始, 1.6与Sort shuffle合并
从spark 1.5.0开始,spark开始了钨丝计划(Tungsten),目的是优化内存和CPU的使用,进一步提升spark的性能。为此,引入Unsafe Shuffle,它的做法是将数据记录用二进制的方式存储,直接在序列化的二进制数据上sort而不是在java 对象上,这样一方面可以减少memory的使用和GC的开销,另一方面避免shuffle过程中频繁的序列化以及反序列化。在排序过程中,它提供cache-efficient sorter,使用一个8 bytes的指针,把排序转化成了一个指针数组的排序,极大的优化了排序性能.
现在2.1 分为三种writer, 分为 BypassMergeSortShuffleWriter, SortShuffleWriter 和 UnsafeShuffleWriter
上面是使用哪种 writer 的判断依据, 是否开启 mapSideCombine 这个判断,是因为有些算子会在 map 端先进行一次 combine, 减少传输数据。 因为 BypassMergeSortShuffleWriter 会临时输出Reducer个(分区数目)小文件,所以分区数必须要小于一个阀值,默认是小于200
UnsafeShuffleWriter需要Serializer支持relocation,Serializer支持relocation:原始数据首先被序列化处理,并且再也不需要反序列,在其对应的元数据被排序后,需要Serializer支持relocation,在指定位置读取对应数据
Partitioner主要有两个实现类:HashPartitioner和RangePartitioner,HashPartitioner是大部分transformation的默认实现,sortBy、sortByKey使用RangePartitioner实现,也可以自定义Partitioner.
HashPartitioner
numPartitions方法返回传入的分区数,getPartition方法使用key的hashCode值对分区数取模得到PartitionId,写入到对应的bucket中。
RangePartitioner
RangePartitioner是先根据所有partition中数据的分布情况,尽可能均匀地构造出重分区的分隔符,再将数据的key值根据分隔符进行重新分区
Spark 中和 join 相关的算子有这几个:join
、fullOuterJoin
、leftOuterJoin
、rightOuterJoin
join
join函数会输出两个RDD中key相同的所有项,并将它们的value联结起来,它联结的key要求在两个表中都存在,类似于SQL中的INNER JOIN。但它不满足交换律,a.join(b)与b.join(a)的结果不完全相同,值插入的顺序与调用关系有关。
leftOuterJoin
leftOuterJoin会保留对象的所有key,而用None填充在参数RDD other中缺失的值,因此调用顺序会使结果完全不同。如下面展示的结果,
rightOuterJoin
rightOuterJoin与leftOuterJoin基本一致,区别在于它的结果保留的是参数other这个RDD中所有的key。
fullOuterJoin
fullOuterJoin会保留两个RDD中所有的key,因此所有的值列都有可能出现缺失的情况,所有的值列都会转为Some对象。
A list of partitions
RDD是一个由多个partition(某个节点里的某一片连续的数据)组成的的list;将数据加载为RDD时,一般会遵循数据的本地性(一般一个hdfs里的block会加载为一个partition)。
A function for computing each split
RDD的每个partition上面都会有function,也就是函数应用,其作用是实现RDD之间partition的转换。
A list of dependencies on other RDDs
RDD会记录它的依赖 ,为了容错(重算,cache,checkpoint),也就是说在内存中的RDD操作时出错或丢失会进行重算。
Optionally,a Partitioner for Key-value RDDs
可选项,如果RDD里面存的数据是key-value形式,则可以传递一个自定义的Partitioner进行重新分区,例如这里自定义的Partitioner是基于key进行分区,那则会将不同RDD里面的相同key的数据放到同一个partition里面
Optionally, a list of preferred locations to compute each split on
最优的位置去计算,也就是数据的本地性。
区别宽窄依赖的核心点是 子RDD的partition与父RDD的partition是否是1对多的关系,如果是这样的关系的话,
说明多个父rdd的partition需要经过shuffle过程汇总到一个子rdd的partition,这样就是一次宽依赖,在DAGScheduler中会产生stage的切分.
总的来说,spark分为两大类算子:
Transformation 变换/转换算子:这种变换并不触发提交作业,完成作业中间过程处理
Transformation 操作是延迟计算的,也就是说从一个RDD 转换生成另一个 RDD 的转换操作不是马上执行,需要等到有 Action 操作的时候才会真正触发运算
Action 行动算子:这类算子会触发 SparkContext 提交 Job 作业
Action 算子会触发 Spark 提交作业(Job),并将数据输出 Spark系统
输入分区与输出分区一对一型
输入分区与输出分区多对一型
输入分区与输出分区多对多型
输出分区为输入分区子集型
Cache型
输入分区与输出分区一对一
对单个RDD或两个RDD聚集
连接
无输出
HDFS算子
Scala集合和数据类型
NONE :什么类型都不是
DISK_ONLY:磁盘
DISK_ONLY_2:磁盘;双副本
MEMORY_ONLY: 内存;反序列化;把RDD作为反序列化的方式存储,假如RDD的内容存不下,剩余的分区在以后需要时会重新计算,不会刷到磁盘上。
MEMORY_ONLY_2:内存;反序列化;双副本
MEMORY_ONLY_SER:内存;序列化;这种序列化方式,每一个partition以字节数据存储,好处是能带来更好的空间存储,但CPU耗费高
MEMORY_ONLY_SER_2 : 内存;序列化;双副本
MEMORY_AND_DISK:内存 + 磁盘;反序列化;双副本;RDD以反序列化的方式存内存,假如RDD的内容存不下,剩余的会存到磁盘
MEMORY_AND_DISK_2 : 内存 + 磁盘;反序列化;双副本
MEMORY_AND_DISK_SER:内存 + 磁盘;序列化
MEMORY_AND_DISK_SER_2:内存 + 磁盘;序列化;双副本
Transformation 操作是延迟计算的,也就是说从一个RDD 转换生成另一个 RDD 的转换操作不是马上执行,需要等到有 Acion 操作的时候才会真正触发运算,这也就是懒加载.
目前,除了local模式为本地调试模式以为, Spark支持三种分布式部署方式,分别是standalone、spark on mesos和 spark on YARN
Standalone模式
即独立模式,自带完整的服务,可单独部署到一个集群中,无需依赖任何其他资源管理系统。从一定程度上说,该模式是其他两种的基础。目前Spark在standalone模式下是没有任何单点故障问题的,这是借助zookeeper实现的,思想类似于Hbase master单点故障解决方案。将Spark standalone与MapReduce比较,会发现它们两个在架构上是完全一致的:
Spark On YARN模式
spark on yarn 的支持两种模式:
yarn-cluster和yarn-client的区别在于yarn appMaster,每个yarn app实例有一个appMaster进程,是为app启动的第一个container;负责从ResourceManager请求资源,获取到资源后,告诉NodeManager为其启动container。yarn-cluster和yarn-client模式内部实现还是有很大的区别。如果你需要用于生产环境,那么请选择yarn-cluster;而如果你仅仅是Debug程序,可以选择yarn-client。
Spark On Mesos模式
Spark运行在Mesos上会比运行在YARN上更加灵活,更加自然。目前在Spark On Mesos环境中,用户可选择两种调度模式之一运行自己的应用程序
粗粒度模式(Coarse-grained Mode):每个应用程序的运行环境由一个Dirver和若干个Executor组成,其中,每个Executor占用若干资源,内部可运行多个Task(对应多少个“slot”)。应用程序的各个任务正式运行之前,需要将运行环境中的资源全部申请好,且运行过程中要一直占用这些资源,即使不用,最后程序运行结束后,回收这些资源。
细粒度模式(Fine-grained Mode):鉴于粗粒度模式会造成大量资源浪费,Spark On Mesos还提供了另外一种调度模式:细粒度模式,这种模式类似于现在的云计算,思想是按需分配。与粗粒度模式一样,应用程序启动时,先会启动executor,但每个executor占用资源仅仅是自己运行所需的资源,不需要考虑将来要运行的任务,之后,mesos会为每个executor动态分配资源,每分配一些,便可以运行一个新任务,单个Task运行完之后可以马上释放对应的资源。
spark-submit
提交代码,执行 new SparkContext()
,在 SparkContext 里构造 DAGScheduler
和 TaskScheduler
。stage的划分依据就是看是否产生了shuflle(即宽依赖),遇到一个shuffle操作就划分为前后两个stage.
spark可以在集群运行时启动一个或多个standby Master,当 Master 出现异常时,会根据规则启动某个standby master接管,在standlone模式下有如下几种配置
ZOOKEEPER
集群数据持久化到zk中,当master出现异常时,zk通过选举机制选出新的master,新的master接管是需要从zk获取持久化信息
FILESYSTEM
集群元数据信息持久化到本地文件系统, 当master出现异常时,只需要在该机器上重新启动master,启动后新的master获取持久化信息并根据这些信息恢复集群状态
CUSTOM
自定义恢复方式,对 standloneRecoveryModeFactory 抽象类 进行实现并把该类配置到系统中,当master出现异常时,会根据用户自定义行为恢复集群
None
不持久化集群的元数据, 当 master出现异常时, 新启动的Master 不进行恢复集群状态,而是直接接管集群
Worker 以定时发送心跳给 Master, 让 Master 知道 Worker 的实时状态,当worker出现超时时,Master 调用 timeOutDeadWorker 方法进行处理,在处理时根据 Worker 运行的是 Executor 和 Driver 分别进行处理
spark的内存结构分为3大块:storage/execution/系统自留
storage 内存:用于缓存 RDD、展开 partition、存放 Direct Task Result、存放广播变量。在 Spark Streaming receiver 模式中,也用来存放每个 batch 的 blocks
execution 内存:用于 shuffle、join、sort、aggregation 中的缓存、buffer
系统自留:
在 spark 运行过程中使用:比如序列化及反序列化使用的内存,各个对象、元数据、临时变量使用的内存,函数调用使用的堆栈等
作为误差缓冲:由于 storage 和 execution 中有很多内存的使用是估算的,存在误差。当 storage 或 execution 内存使用超出其最大限制时,有这样一个安全的误差缓冲在可以大大减小 OOM 的概率
顾名思义,broadcast 就是将数据从一个节点发送到其他各个节点上去。这样的场景很多,比如 driver 上有一张表,其他节点上运行的 task 需要 lookup 这张表,那么 driver 可以先把这张表 copy 到这些节点,这样 task 就可以在本地查表了。如何实现一个可靠高效的 broadcast 机制是一个有挑战性的问题。先看看 Spark 官网上的一段话:
Broadcast variables allow the programmer to keep a read-only variable cached on each machine rather than shipping a copy of it with tasks. They can be used, for example, to give every node a copy of a large input dataset in an efficient manner. Spark also attempts to distribute broadcast variables using efficient broadcast algorithms to reduce communication cost.
这就涉及一致性的问题,如果变量可以被更新,那么一旦变量被某个节点更新,其他节点要不要一块更新?如果多个节点同时在更新,更新顺序是什么?怎么做同步?还会涉及 fault-tolerance 的问题。为了避免维护数据一致性问题,Spark 目前只支持 broadcast 只读变量。
因为每个 task 是一个线程,而且同在一个进程运行 tasks 都属于同一个 application。因此每个节点(executor)上放一份就可以被所有 task 共享。
driver program 例子:
1 | val data = List(1, 2, 3, 4, 5, 6) |
driver 使用 sc.broadcast()
声明要 broadcast 的 data,bdata 的类型是 Broadcast。
当 rdd.transformation(func)
需要用 bdata 时,直接在 func 中调用,比如上面的例子中的 map() 就使用了 bdata.value.size。
broadcast 的实现机制很有意思:
Driver 先建一个本地文件夹用以存放需要 broadcast 的 data,并启动一个可以访问该文件夹的 HttpServer。当调用val bdata = sc.broadcast(data)
时就把 data 写入文件夹,同时写入 driver 自己的 blockManger 中(StorageLevel 为内存+磁盘),获得一个 blockId,类型为 BroadcastBlockId。当调用rdd.transformation(func)
时,如果 func 用到了 bdata,那么 driver submitTask() 的时候会将 bdata 一同 func 进行序列化得到 serialized task,注意序列化的时候不会序列化 bdata 中包含的 data。上一章讲到 serialized task 从 driverActor 传递到 executor 时使用 Akka 的传消息机制,消息不能太大,而实际的 data 可能很大,所以这时候还不能 broadcast data。
driver 为什么会同时将 data 放到磁盘和 blockManager 里面?放到磁盘是为了让 HttpServer 访问到,放到 blockManager 是为了让 driver program 自身使用 bdata 时方便(其实我觉得不放到 blockManger 里面也行)。
那么什么时候传送真正的 data?在 executor 反序列化 task 的时候,会同时反序列化 task 中的 bdata 对象,这时候会调用 bdata 的 readObject() 方法。该方法先去本地 blockManager 那里询问 bdata 的 data 在不在 blockManager 里面,如果不在就使用下面的两种 fetch 方式之一去将 data fetch 过来。得到 data 后,将其存放到 blockManager 里面,这样后面运行的 task 如果需要 bdata 就不需要再去 fetch data 了。如果在,就直接拿来用了。
下面探讨 broadcast data 时候的两种实现方式:
顾名思义,HttpBroadcast 就是每个 executor 通过的 http 协议连接 driver 并从 driver 那里 fetch data。
Driver 先准备好要 broadcast 的 data,调用sc.broadcast(data)
后会调用工厂方法建立一个 HttpBroadcast 对象。该对象做的第一件事就是将 data 存到 driver 的 blockManager 里面,StorageLevel 为内存+磁盘,blockId 类型为 BroadcastBlockId。
同时 driver 也会将 broadcast 的 data 写到本地磁盘,例如写入后得到 /var/folders/87/grpn1_fn4xq5wdqmxk31v0l00000gp/T/spark-6233b09c-3c72-4a4d-832b-6c0791d0eb9c/broadcast_0
, 这个文件夹作为 HttpServer 的文件目录。
Driver 和 executor 启动的时候,都会生成 broadcastManager 对象,调用 HttpBroadcast.initialize(),driver 会在本地建立一个临时目录用来存放 broadcast 的 data,并启动可以访问该目录的 httpServer。
Fetch data:在 executor 反序列化 task 的时候,会同时反序列化 task 中的 bdata 对象,这时候会调用 bdata 的 readObject() 方法。该方法先去本地 blockManager 那里询问 bdata 的 data 在不在 blockManager 里面,如果不在就使用 http 协议连接 driver 上的 httpServer,将 data fetch 过来。得到 data 后,将其存放到 blockManager 里面,这样后面运行的 task 如果需要 bdata 就不需要再去 fetch data 了。如果在,就直接拿来用了。
HttpBroadcast 最大的问题就是 driver 所在的节点可能会出现网络拥堵,因为 worker 上的 executor 都会去 driver 那里 fetch 数据。
为了解决 HttpBroadast 中 driver 单点网络瓶颈的问题,Spark 又设计了一种 broadcast 的方法称为 TorrentBroadcast,这个类似于大家常用的 BitTorrent 技术。基本思想就是将 data 分块成 data blocks,然后假设有 executor fetch 到了一些 data blocks,那么这个 executor 就可以被当作 data server 了,随着 fetch 的 executor 越来越多,有更多的 data server 加入,data 就很快能传播到全部的 executor 那里去了。
HttpBroadcast 是通过传统的 http 协议和 httpServer 去传 data,在 TorrentBroadcast 里面使用在上一章介绍的 blockManager.getRemote() => NIO ConnectionManager 传数据的方法来传递,读取数据的过程与读取 cached rdd 的方式类似,可以参阅 CacheAndCheckpoint 中的最后一张图。
下面讨论 TorrentBroadcast 的一些细节:
Driver 先把 data 序列化到 byteArray,然后切割成 BLOCK_SIZE(由 spark.broadcast.blockSize = 4MB
设置)大小的 data block,每个 data block 被 TorrentBlock 对象持有。切割完 byteArray 后,会将其回收,因此内存消耗虽然可以达到 2 * Size(data),但这是暂时的。
完成分块切割后,就将分块信息(称为 meta 信息)存放到 driver 自己的 blockManager 里面,StorageLevel 为内存+磁盘,同时会通知 driver 自己的 blockManagerMaster 说 meta 信息已经存放好。通知 blockManagerMaster 这一步很重要,因为 blockManagerMaster 可以被 driver 和所有 executor 访问到,信息被存放到 blockManagerMaster 就变成了全局信息。
之后将每个分块 data block 存放到 driver 的 blockManager 里面,StorageLevel 为内存+磁盘。存放后仍然通知 blockManagerMaster 说 blocks 已经存放好。到这一步,driver 的任务已经完成。
executor 收到 serialized task 后,先反序列化 task,这时候会反序列化 serialized task 中包含的 bdata 类型是 TorrentBroadcast,也就是去调用 TorrentBroadcast.readObject()。这个方法首先得到 bdata 对象,然后发现 bdata 里面没有包含实际的 data。怎么办?先询问所在的 executor 里的 blockManager 是会否包含 data(通过查询 data 的 broadcastId),包含就直接从本地 blockManager 读取 data。否则,就通过本地 blockManager 去连接 driver 的 blockManagerMaster 获取 data 分块的 meta 信息,获取信息后,就开始了 BT 过程。
BT 过程:task 先在本地开一个数组用于存放将要 fetch 过来的 data blocks arrayOfBlocks = new Array[TorrentBlock](totalBlocks)
,TorrentBlock 是对 data block 的包装。然后打乱要 fetch 的 data blocks 的顺序,比如如果 data block 共有 5 个,那么打乱后的 fetch 顺序可能是 3-1-2-4-5。然后按照打乱后的顺序去 fetch 一个个 data block。fetch 的过程就是通过 “本地 blockManager -本地 connectionManager-driver/executor 的 connectionManager-driver/executor 的 blockManager-data” 得到 data,这个过程与 fetch cached rdd 类似。每 fetch 到一个 block 就将其存放到 executor 的 blockManager 里面,同时通知 driver 上的 blockManagerMaster 说该 data block 多了一个存储地址。这一步通知非常重要,意味着 blockManagerMaster 知道 data block 现在在 cluster 中有多份,下一个不同节点上的 task 再去 fetch 这个 data block 的时候,可以有两个选择了,而且会随机选择一个去 fetch。这个过程持续下去就是 BT 协议,随着下载的客户端越来越多,data block 服务器也越来越多,就变成 p2p下载了。关于 BT 协议,Wikipedia 上有一个动画)。
整个 fetch 过程结束后,task 会开一个大 Array[Byte],大小为 data 的总大小,然后将 data block 都 copy 到这个 Array,然后对 Array 中 bytes 进行反序列化得到原始的 data,这个过程就是 driver 序列化 data 的反过程。
最后将 data 存放到 task 所在 executor 的 blockManager 里面,StorageLevel 为内存+磁盘。显然,这时候 data 在 blockManager 里存了两份,不过等全部 executor 都 fetch 结束,存储 data blocks 那份可以删掉了。
@Andrew-Xia 回答道:不会怎样,就是这个rdd在每个executor中实例化一份。
公共数据的 broadcast 是很实用的功能,在 Hadoop 中使用 DistributedCache,比如常用的-libjars
就是使用 DistributedCache 来将 task 依赖的 jars 分发到每个 task 的工作目录。不过分发前 DistributedCache 要先将文件上传到 HDFS。这种方式的主要问题是资源浪费,如果某个节点上要运行来自同一 job 的 4 个 mapper,那么公共数据会在该节点上存在 4 份(每个 task 的工作目录会有一份)。但是通过 HDFS 进行 broadcast 的好处在于单点瓶颈不明显,因为公共 data 首先被分成多个 block,然后不同的 block 存放在不同的节点。这样,只要所有的 task 不是同时去同一个节点 fetch 同一个 block,网络拥塞不会很严重。
对于 Spark 来讲,broadcast 时考虑的不仅是如何将公共 data 分发下去的问题,还要考虑如何让同一节点上的 task 共享 data。
对于第一个问题,Spark 设计了两种 broadcast 的方式,传统存在单点瓶颈问题的 HttpBroadcast,和类似 BT 方式的 TorrentBroadcast。HttpBroadcast 使用传统的 client-server 形式的 HttpServer 来传递真正的 data,而 TorrentBroadcast 使用 blockManager 自带的 NIO 通信方式来传递 data。TorrentBroadcast 存在的问题是慢启动和占内存,慢启动指的是刚开始 data 只在 driver 上有,要等 executors fetch 很多轮 data block 后,data server 才会变得可观,后面的 fetch 速度才会变快。executor 所占内存的在 fetch 完 data blocks 后进行反序列化时需要将近两倍 data size 的内存消耗。不管哪一种方式,driver 在分块时会有两倍 data size 的内存消耗。
对于第二个问题,每个 executor 都包含一个 blockManager 用来管理存放在 executor 里的数据,将公共数据存放在 blockManager 中(StorageLevel 为内存+磁盘),可以保证在 executor 执行的 tasks 能够共享 data。
其实 Spark 之前还尝试了一种称为 TreeBroadcast 的机制,详情可以见技术报告 Performance and Scalability of Broadcast in Spark。
更深入点,broadcast 可以用多播协议来做,不过多播使用 UDP,不是可靠的,仍然需要应用层的设计一些可靠性保障机制。
数据倾斜是一种很常见的问题(依据二八定律),简单来说,比方WordCount中某个Key对应的数据量非常大的话,就会产生数据倾斜,导致两个后果:
聚合倾斜
双重聚合(局部聚合+全局聚合)
场景: 对RDD进行reduceByKey等聚合类shuffle算子,SparkSQL的groupBy做分组聚合这两种情况
思路:首先通过map给每个key打上n以内的随机数的前缀并进行局部聚合,即(hello, 1) (hello, 1) (hello, 1) (hello, 1)变为(1_hello, 1) (1_hello, 1) (2_hello, 1),并进行reduceByKey的局部聚合,然后再次map将key的前缀随机数去掉再次进行全局聚合;
原理: 对原本相同的key进行随机数附加,变成不同key,让原本一个task处理的数据分摊到多个task做局部聚合,规避单task数据过量。之后再去随机前缀进行全局聚合;
优点:效果非常好(对聚合类Shuffle操作的倾斜问题);
缺点:范围窄(仅适用于聚合类的Shuffle操作,join类的Shuffle还需其它方案)
join倾斜
将reduce join转为map join
场景: 对RDD或Spark SQL使用join类操作或语句,且join操作的RDD或表比较小(百兆或1,2G); 思路:使用broadcast和map类算子实现join的功能替代原本的join,彻底规避shuffle。对较小RDD直接collect到内存,并创建broadcast变量;并对另外一个RDD执行map类算子,在该算子的函数中,从broadcast变量(collect出的较小RDD)与当前RDD中的每条数据依次比对key,相同的key执行你需要方式的join;
原理: 若RDD较小,可采用广播小的RDD,并对大的RDD进行map,来实现与join同样的效果。简而言之,用broadcast-map代替join,规避join带来的shuffle(无Shuffle无倾斜); 优点:效果很好(对join操作导致的倾斜),根治;
缺点:适用场景小(大表+小表),广播(driver和executor节点都会驻留小表数据)小表也耗内存
采样倾斜key并分拆join操作
场景: 两个较大的(无法采用方案五)RDD/Hive表进行join时,且一个RDD/Hive表中少数key数据量过大,另一个RDD/Hive表的key分布较均匀(RDD中两者之一有一个更倾斜);
思路:
优点: 前提是join导致的倾斜(某几个key倾斜),避免占用过多内存(只需对少数倾斜key扩容n倍);
缺点: 对过多倾斜key不适用。
用随机前缀和扩容RDD进行join
场景: RDD中有大量key导致倾斜; 思路:与方案六类似。
原理: 与方案六只有唯一不同在于这里对不倾斜RDD中所有数据进行扩大n倍,而不是找出倾斜key进行扩容;
优点: 对join类的数据倾斜都可处理,效果非常显著;
缺点: 缓解,扩容需要大内存
Driver Program是用户编写的提交给Spark集群执行的application,它包含两部分
一般来说transformation算子均是在worker上执行的,其他类型的代码在driver端执行
]]>order by
order by 是要对输出的结果进行全局排序,这就意味着**只有一个reducer**才能实现(多个reducer无法保证全局有序)但是当数据量过大的时候,效率就很低。如果在严格模式下(hive.mapred.mode=strict),则必须配合limit使用
sort by
sort by 不是全局排序,只是在进入到reducer之前完成排序,只保证了每个reducer中数据按照指定字段的有序性,是局部排序。配置mapred.reduce.tasks=[nums]可以对输出的数据执行归并排序。可以配合limit使用,提高性能
distribute by
distribute by 指的是按照指定的字段划分到不同的输出reduce文件中,和sort by一起使用时需要注意,
distribute by必须放在前面
cluster by
cluster by 可以看做是一个特殊的distribute by+sort by,它具备二者的功能,但是只能实现倒序排序的方式,不能指定排序规则为asc 或者desc
内嵌Derby方式
这个是Hive默认的启动模式,一般用于单元测试,这种存储方式有一个缺点:在同一时间只能有一个进程连接使用数据库。
Local方式
本地MySQL
Remote方式
远程MySQL,一般常用此种方式
Hive中除了支持和传统数据库中一样的内关联(JOIN)、左关联(LEFT JOIN)、右关联(RIGHT JOIN)、全关联(FULL JOIN),还支持左半关联(LEFT SEMI JOIN)
内关联(JOIN)
只返回能关联上的结果。
左外关联(LEFT [OUTER] JOIN)
以LEFT [OUTER] JOIN关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段置为NULL。
右外关联(RIGHT [OUTER] JOIN)
和左外关联相反,以RIGTH [OUTER] JOIN关键词后面的表作为主表,和前面的表做关联,返回记录数和主表一致,关联不上的字段为NULL。
全外关联(FULL [OUTER] JOIN)
以两个表的记录为基准,返回两个表的记录去重之和,关联不上的字段为NULL。
LEFT SEMI JOIN
以LEFT SEMI JOIN关键字前面的表为主表,返回主表的KEY也在副表中的记录
笛卡尔积关联(CROSS JOIN)
返回两个表的笛卡尔积结果,不需要指定关联键。
Impala是基于Hive的大数据实时分析查询引擎,直接使用Hive的元数据库Metadata,意味着impala元数据都存储在Hive的metastore中。并且impala兼容Hive的sql解析,实现了Hive的SQL语义的子集,功能还在不断的完善中。
在小表和大表进行join时,将小表放在前边,效率会高,hive会将小表进行缓存
主要分为6个阶段:
Hive使用Antlr实现语法解析.根据Antlr制定的SQL语法解析规则,完成SQL语句的词法/语法解析,将SQL转为抽象语法树AST.
遍历AST,生成基本查询单元QueryBlock.QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出.
OperatorTree生成MapReduce Job.遍历OperatorTree,翻译成MR任务.
优化任务. 使用物理优化器对MR任务进行优化,生成最终执行任务
在Hive中,用户可以自定义一些函数,用于扩展HiveQL的功能,而这类函数叫做UDF(用户自定义函数)。UDF分为两大类:UDAF(用户自定义聚合函数)和UDTF(用户自定义表生成函数)。
Hive有两个不同的接口编写UDF程序。一个是基础的UDF接口,一个是复杂的GenericUDF接口。
1 | id,name,subject,score |
按照各个科目的成绩排名 取 Top3
1 | select a.* from |
1 | cookieId createTime pv |
获取每个用户前1/4次的访问记录
1 | SELECT a.* from |
NTILE(n),用于将分组数据按照顺序切分成n片,返回当前切片值
]]>HDFS 采用的是 Master/Slave 架构,一个 HDFS 集群包含一个单独的 NameNode 和多个 DataNode 节点
NameNode 负责管理整个分布式系统的元数据,主要包括:
这些数据保存在内存中,同时在磁盘保存两个元数据管理文件:fsimage 和 editlog。
这两个文件相结合可以构造完整的内存数据。
Secondary NameNode 并不是 NameNode 的热备机,而是定期从 NameNode 拉取 fsimage 和 editlog 文件,并对两个文件进行合并,形成新的 fsimage 文件并传回 NameNode,这样做的目的是减轻 NameNod 的工作压力,本质上 SNN 是一个提供检查点功能服务的服务点。
负责数据块的实际存储和读写工作,Block 默认是64MB(HDFS2.0改成了128MB),当客户端上传一个大文件时,HDFS 会自动将其切割成固定大小的 Block,为了保证数据可用性,每个 Block 会以多备份的形式存储,默认是3份。
Active NameNode 和 Standby NameNode:两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务;
ZKFailoverController(主备切换控制器,FC):ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换(当然 NameNode 目前也支持不依赖于 Zookeeper 的手动主备切换);
Zookeeper 集群:为主备切换控制器提供主备选举支持;
共享存储系统:共享存储系统是实现 NameNode 的高可用最为关键的部分,共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。主 NameNode 和备 NameNode 通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主 NameNode 在确认元数据完全同步之后才能继续对外提供服务。
DataNode 节点:因为主 NameNode 和备 NameNode 需要共享 HDFS 的数据块和 DataNode 之间的映射关系,为了使故障切换能够快速进行,DataNode 会同时向主 NameNode 和备 NameNode 上报数据块的位置信息。
RM 是一个全局的资源管理器,负责整个系统的资源管理和分配,它主要有两个组件构成:
调度器根据容量、队列等限制条件(如某个队列分配一定的资源,最多执行一定数量的作业等),将系统中的资源分配给各个正在运行的应用程序。要注意的是,该调度器是一个纯调度器,它不再从事任何与应用程序有关的工作,比如不负责重新启动(因应用程序失败或者硬件故障导致的失败),这些均交由应用程序相关的 ApplicationMaster 完成。调度器仅根据各个应用程序的资源需求进行资源分配,而资源分配单位用一个抽象概念 资源容器(Resource Container,也即 Container),Container 是一个动态资源分配单位,它将内存、CPU、磁盘、网络等资源封装在一起,从而限定每个任务使用的资源量。此外,该调度器是一个可插拔的组件,用户可根据自己的需求设计新的调度器,YARN 提供了多种直接可用的调度器,比如 Fair Scheduler 和 Capacity Schedule 等。
应用程序管理器负责管理整个系统中所有应用程序,包括应用程序提交、与调度器协商资源以 AM、监控 AM 运行状态并在失败时重新启动它等。
NM 是每个节点上运行的资源和任务管理器,一方面,它会定时向 RM 汇报本节点上的资源使用情况和各个 Container 的运行状态;另一方面,它接收并处理来自 AM 的 Container 启动/停止等各种请求。
提交的每个作业都会包含一个 AM,主要功能包括:
MapReduce 就是原生支持 ON YARN 的一种框架,可以在 YARN 上运行 MapReduce 作业。有很多分布式应用都开发了对应的应用程序框架,用于在 YARN 上运行任务,例如 Spark,Storm、Flink 等。
Container 是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等,当 AM 向 RM 申请资源时,RM 为 AM 返回的资源便是用 Container 表示的。 YARN 会为每个任务分配一个 Container 且该任务只能使用该 Container 中描述的资源。
MapReduce分为两个阶段: Map 和 Ruduce.
Map阶段:
spill.此阶段分为sort和combine.首先分区过得数据会经过排序之后写入环形内存缓冲区.在达到阈值之后守护线程将数据溢出分区文件.
merge. spill结果会有很多个文件,但最终输出只有一个,故有一个merge操作会合并所有的本地文件,并且该文件会有一个对应的索引文件.
Reduce阶段:
create
方法,创建一个文件输出流(FSDataOutputStream)对象;close
方法,完成文件写入;资源调度方式的改变
在1.x, 使用Jobtracker负责任务调度和资源管理,单点负担过重,在2.x中,新增了yarn作为集群的调度工具.在yarn中,使用ResourceManager进行 资源管理, 单独开启一个Container作为ApplicationMaster来进行任务管理.
HA模式
在1.x中没有HA模式,集群中只有一个NameNode,而在2.x中可以启用HA模式,存在一个Active NameNode 和Standby NameNode.
HDFS Federation
Hadoop 2.0中对HDFS进行了改进,使NameNode可以横向扩展成多个,每个NameNode分管一部分目录,进而产生了HDFS Federation,该机制的引入不仅增强了HDFS的扩展性,也使HDFS具备了隔离性
hadoop-env.sh: 用于定义hadoop运行环境相关的配置信息,比如配置JAVA_HOME环境变量、为hadoop的JVM指定特定的选项、指定日志文件所在的目录路径以及master和slave文件的位置等;
core-site.xml: 用于定义系统级别的参数,如HDFS URL、Hadoop的临时目录以及用于rack-aware集群中的配置文件的配置等,此中的参数定义会覆盖core-default.xml文件中的默认配置;
hdfs-site.xml: HDFS的相关设定,如文件副本的个数、块大小及是否使用强制权限等,此中的参数定义会覆盖hdfs-default.xml文件中的默认配置;
mapred-site.xml:HDFS的相关设定,如reduce任务的默认个数、任务所能够使用内存的默认上下限等,此中的参数定义会覆盖mapred-default.xml文件中的默认配置;
Hadoop上大量HDFS元数据信息存储在NameNode内存中,因此过多的小文件必定会压垮NameNode的内存.
每个元数据对象约占150byte,所以如果有1千万个小文件,每个文件占用一个block,则NameNode大约需要2G空间。如果存储1亿个文件,则NameNode需要20G空间.
显而易见的解决这个问题的方法就是合并小文件,可以选择在客户端上传时执行一定的策略先合并,或者是使用Hadoop的CombineFileInputFormat<K,V>实现小文件的合并
NameNode:
SecondaryNameNode(非HA模式):
NodeManager:
JournalNode(HA下启用):
Hadoop | Hive | Spark | Flink | HBase | Kafka | Zookeeper |
在提交大数据作业到集群上运行时,通常需要先将项目打成 JAR 包。这里以 Maven 为例,常用打包方式如下:
以下分别进行详细的说明。
不在 POM 中配置任何插件,直接使用 mvn package
进行项目打包,这对于没有使用外部依赖包的项目是可行的。但如果项目中使用了第三方 JAR 包,就会出现问题,因为 mvn package
打的 JAR 包中是不含有依赖包,会导致作业运行时出现找不到第三方依赖的异常。这种方式局限性比较大,因为实际的项目往往很复杂,通常都会依赖第三方 JAR。
大数据框架的开发者也考虑到这个问题,所以基本所有的框架都支持在提交作业时使用 --jars
指定第三方依赖包,但是这种方式的问题同样很明显,就是你必须保持生产环境与开发环境中的所有 JAR 包版本一致,这是有维护成本的。
基于上面这些原因,最简单的是采用 All In One
的打包方式,把所有依赖都打包到一个 JAR 文件中,此时对环境的依赖性最小。要实现这个目的,可以使用 Maven 提供的 maven-assembly-plugin
或 maven-shade-plugin
插件。
Assembly
插件支持将项目的所有依赖、文件都打包到同一个输出文件中。目前支持输出以下文件类型:
在 POM.xml 中引入插件,指定打包格式的配置文件 assembly.xml
(名称可自定义),并指定作业的主入口类:
1 | <build> |
assembly.xml 文件内容如下:
1 | <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" |
采用 maven-assembly-plugin 进行打包时命令如下:
1 | mvn assembly:assembly |
打包后会同时生成两个 JAR 包,其中后缀为 jar-with-dependencies
是含有第三方依赖的 JAR 包,后缀是由 assembly.xml
中 <id>
标签指定的,可以自定义修改。
maven-shade-plugin
比 maven-assembly-plugin
功能更为强大,比如你的工程依赖很多的 JAR 包,而被依赖的 JAR 又会依赖其他的 JAR 包,这样,当工程中依赖到不同的版本的 JAR 时,并且 JAR 中具有相同名称的资源文件时,shade 插件会尝试将所有资源文件打包在一起时,而不是和 assembly 一样执行覆盖操作。
通常使用 maven-shade-plugin
就能够完成大多数的打包需求,其配置简单且适用性最广,因此建议优先使用此方式。
采用 maven-shade-plugin
进行打包时候,配置示例如下:
1 | <plugin> |
以上配置来源于 Storm Github,在上面的配置中,排除了部分文件,这是因为有些 JAR 包生成时,会使用 jarsigner 生成文件签名 (完成性校验),分为两个文件存放在 META-INF 目录下:
如果某些包的存在重复引用,这可能会导致在打包时候出现 Invalid signature file digest for Manifest main attributes
异常,所以在配置中排除这些文件。
使用 maven-shade-plugin 进行打包的时候,打包命令和普通打包一样:
1 | mvn package |
打包后会生成两个 JAR 包,提交到服务器集群时使用非 original 开头的 JAR。
通常上面两种打包能够满足大多数的使用场景。但是如果你想把某些没有被 Maven 管理 JAR 包打入到最终的 JAR 中,比如你在 resources/lib
下引入的其他非 Maven 仓库中的 JAR,此时可以使用 maven-jar-plugin
和 maven-dependency-plugin
插件将其打入最终的 JAR 中。
1 | <build> |
通常为了避免冲突,官方文档都会建议你排除集群中已经提供的 JAR 包,如下:
Spark 官方文档 Submitting Applications 章节:
When creating assembly jars, list Spark and Hadoop as
provided
dependencies; these need not be bundled since they are provided by the cluster manager at runtime.
Strom 官方文档 Running Topologies on a Production Cluster 章节:
Then run mvn assembly:assembly to get an appropriately packaged jar. Make sure you exclude the Storm jars since the cluster already has Storm on the classpath.
按照以上说明,排除 JAR 包的方式主要有两种:
<scope>provided</scope>
标签,此时该 JAR 包会被排除,但是不建议使用这种方式,因为此时你在本地运行也无法使用该 JAR 包;maven-assembly-plugin
或 maven-shade-plugin
的配置文件中使用 <exclude>
进行排除。如果你使用到 Scala 语言进行编程,此时需要特别注意 :默认情况下 Maven 是不会把 scala
文件打入最终的 JAR 中,需要额外添加 maven-scala-plugin
插件,常用配置如下:
1 | <plugin> |
关于 Maven 各个插件的详细配置可以查看其官方文档:
关于 maven-shade-plugin 的更多配置也可以参考该博客: maven-shade-plugin 入门指南
]]>这里分享一些自己学习过程中觉得不错的资料和开发工具。
上面的书籍我都列出了出版日期,可以看到大部分书籍的出版时间都比较久远了,虽然这些书籍比较经典,但是很多书籍在软件版本上已经滞后了很多。所以推荐优先选择各个框架的官方文档作为学习资料。大数据框架的官方文档都很全面,并且对知识点的讲解都做到了简明扼要。这里以 Spark RDD 官方文档 为例,你会发现不仅清晰的知识点导航,而且所有示例都给出了 Java,Scala,Python 三种语言的版本,除了官方文档,其他书籍很少能够做到这一点。
一款开源、免费的虚拟机管理软件,虽然是轻量级软件,但功能很丰富,基本能够满足全部的使用需求。
官方网站:https://www.virtualbox.org/
大数据的框架通常都部署在服务器上,这里推荐使用 MobaXterm 进行连接。同样是免费开源的,支持多种连接协议,支持拖拽上传文件,支持使用插件扩展。
官方网站:https://mobaxterm.mobatek.net/
Translate Man 是一款浏览器上的翻译插件 (谷歌和火狐均支持)。它采用谷歌的翻译接口,准确性非常高,支持划词翻译,可以辅助进行官方文档的阅读。
ProcessOn 式一个在线绘图平台,使用起来非常便捷,可以用于笔记或者博客配图的绘制。
]]>为方便大家查阅,本仓库所有软件的安装方式单独整理如下:
由于 Apache Hadoop 原有安装包之间兼容性比较差,所以如无特殊需求,本仓库一律选择 CDH (Cloudera’s Distribution, including Apache Hadoop) 版本的安装包。它基于稳定版本的 Apache Hadoop 构建,并做了兼容性测试,是目前生产环境中使用最为广泛的版本。
最新的 CDH 5 的下载地址为:http://archive.cloudera.com/cdh5/cdh/5/ 。这个页面很大且加载速度比较慢,需要耐心等待页面加载完成。上半部分是文档链接,后半部分才是安装包。同一个 CDH 版本的不同框架间都做了集成测试,可以保证没有任何 JAR 包冲突。安装包包名通常如下所示,这里 CDH 版本都是 5.15.2
,前面是各个软件自己的版本 ,未避免出现不必要的 JAR 包冲突,请务必保持 CDH 的版本一致。
1 | hadoop-2.6.0-cdh5.15.2.tar.gz |
Java基础 | NIO | 并发 | JVM | 分布式 | Zookeeper | RPC | Netty | Linux |
---|---|---|---|---|---|---|---|---|
Java基础 | NIO | 并发容器 | JVM | 分布式 | zookeeper | RPC | Netty | Linux |
Hadoop | Hive | Spark | Flink | HBase | Kafka | Zookeeper | Flume | Sqoop | Azkaban |
这里的文章主要是我平时发表在公众号,博客等的文章,精心挑选,以飨读者。
Flink实战进阶 | Spark实战进阶 | Kafka实战进阶 |
本部分引用了Bigdata-Notes的文章,作者是heibaiying,大佬写的文章非常好,欢迎大家关注他的博客。
我个人会持续补充更有深度和实战性的文章~
Spark Core :
Spark SQL :
Spark Streaming :
Kafka基本原理 :
分布式消息队列Kafka原理及与流式计算的集成 :
Storm-Redis 提供了 Storm 与 Redis 的集成支持,你只需要引入对应的依赖即可使用:
1 | <dependency> |
Storm-Redis 使用 Jedis 为 Redis 客户端,并提供了如下三个基本的 Bolt 实现:
RedisLookupBolt
、RedisStoreBolt
、RedisFilterBolt
均继承自 AbstractRedisBolt
抽象类。我们可以通过继承该抽象类,实现自定义 RedisBolt,进行功能的拓展。
这里首先给出一个集成案例:进行词频统计并将最后的结果存储到 Redis。项目结构如下:
用例源码下载地址:storm-redis-integration
项目主要依赖如下:
1 | <properties> |
1 | /** |
产生的模拟数据格式如下:
1 | SparkHBase |
1 | /** |
1 | /** |
实现 RedisStoreMapper 接口,定义 tuple 与 Redis 中数据的映射关系:即需要指定 tuple 中的哪个字段为 key,哪个字段为 value,并且存储到 Redis 的何种数据结构中。
1 | /** |
1 | /** |
可以用直接使用本地模式运行,也可以打包后提交到服务器集群运行。本仓库提供的源码默认采用 maven-shade-plugin
进行打包,打包命令如下:
1 | mvn clean package -D maven.test.skip=true |
启动后,查看 Redis 中的数据:
RedisLookupBolt
、RedisStoreBolt
、RedisFilterBolt
均继承自 AbstractRedisBolt
抽象类,和我们自定义实现 Bolt 一样,AbstractRedisBolt
间接继承自 BaseRichBolt
。
AbstractRedisBolt
中比较重要的是 prepare 方法,在该方法中通过外部传入的 jedis 连接池配置 ( jedisPoolConfig/jedisClusterConfig) 创建用于管理 Jedis 实例的容器 JedisCommandsInstanceContainer
。
1 | public abstract class AbstractRedisBolt extends BaseTickTupleAwareRichBolt { |
JedisCommandsInstanceContainer
的 build()
方法如下,实际上就是创建 JedisPool 或 JedisCluster 并传入容器中。
1 | public static JedisCommandsInstanceContainer build(JedisPoolConfig config) { |
RedisStoreBolt
中比较重要的是 process 方法,该方法主要从 storeMapper 中获取传入 key/value 的值,并按照其存储类型 dataType
调用 jedisCommand 的对应方法进行存储。
RedisLookupBolt 的实现基本类似,从 lookupMapper 中获取传入的 key 值,并进行查询操作。
1 | public class RedisStoreBolt extends AbstractRedisBolt { |
JedisCommands 接口中定义了所有的 Redis 客户端命令,它有以下三个实现类,分别是 Jedis、JedisCluster、ShardedJedis。Strom 中主要使用前两种实现类,具体调用哪一个实现类来执行命令,由传入的是 jedisPoolConfig 还是 jedisClusterConfig 来决定。
RedisMapper 和 TupleMapper 定义了 tuple 和 Redis 中的数据如何进行映射转换。
TupleMapper 主要定义了两个方法:
getKeyFromTuple(ITuple tuple): 从 tuple 中获取那个字段作为 Key;
getValueFromTuple(ITuple tuple):从 tuple 中获取那个字段作为 Value;
定义了获取数据类型的方法 getDataTypeDescription()
,RedisDataTypeDescription 中 RedisDataType 枚举类定义了所有可用的 Redis 数据类型:
1 | public class RedisDataTypeDescription implements Serializable { |
RedisStoreMapper 继承 TupleMapper 和 RedisMapper 接口,用于数据存储时,没有定义额外方法。
RedisLookupMapper 继承 TupleMapper 和 RedisMapper 接口:
下面的例子表示从输入 Tuple
的获取 word
字段作为 key,使用 RedisLookupBolt
进行查询后,将 key 和查询结果 value 组装为 values 并发送到下一个处理单元。
1 | class WordCountRedisLookupMapper implements RedisLookupMapper { |
RedisFilterMapper 继承 TupleMapper 和 RedisMapper 接口,用于查询数据时,定义了 declareOutputFields 方法,声明输出的字段。如下面的实现:
1 |
|
自定义 RedisBolt:主要利用 Redis 中哈希结构的 hincrby key field
命令进行词频统计。在 Redis 中 hincrby
的执行效果如下。hincrby 可以将字段按照指定的值进行递增,如果该字段不存在的话,还会新建该字段,并赋值为 0。通过这个命令可以非常轻松的实现词频统计功能。
1 | HSET myhash field 5 |
1 | /** |
1 | /** |
Storm 官方对 Kafka 的整合分为两个版本,官方说明文档分别如下:
这里我服务端安装的 Kafka 版本为 2.2.0(Released Mar 22, 2019) ,按照官方 0.10.x+ 的整合文档进行整合,不适用于 0.8.x 版本的 Kafka。
1 | <properties> |
1 | /** |
产生的模拟数据格式如下:
1 | SparkHBase |
1 | /** |
进行测试前需要启动 Kakfa:
Kafka 的运行依赖于 zookeeper,需要预先启动,可以启动 Kafka 内置的 zookeeper,也可以启动自己安装的:
1 | zookeeper启动命令 |
启动单节点 kafka 用于测试:
1 | bin/kafka-server-start.sh config/server.properties |
1 | 创建用于测试主题 |
启动一个消费者用于观察写入情况,启动命令如下:
1 | bin/kafka-console-consumer.sh --bootstrap-server hadoop001:9092 --topic storm-topic --from-beginning |
可以用直接使用本地模式运行,也可以打包后提交到服务器集群运行。本仓库提供的源码默认采用 maven-shade-plugin
进行打包,打包命令如下:
1 | mvn clean package -D maven.test.skip=true |
启动后,消费者监听情况如下:
1 | /** |
1 | /** |
这里从 value
字段中获取 kafka 输出的值数据。
在开发中,我们可以通过继承 RecordTranslator
接口定义了 Kafka 中 Record 与输出流之间的映射关系,可以在构建 KafkaSpoutConfig
的时候通过构造器或者 setRecordTranslator()
方法传入,并最后传递给具体的 KafkaSpout
。
默认情况下使用内置的 DefaultRecordTranslator
,其源码如下,FIELDS
中 定义了 tuple 中所有可用的字段:主题,分区,偏移量,消息键,值。
1 | public class DefaultRecordTranslator<K, V> implements RecordTranslator<K, V> { |
这里启动一个生产者用于发送测试数据,启动命令如下:
1 | bin/kafka-console-producer.sh --broker-list hadoop001:9092 --topic storm-topic |
本地运行的项目接收到从 Kafka 发送过来的数据:
用例源码下载地址:storm-kafka-integration
Storm 是一个开源的分布式实时计算框架,可以以简单、可靠的方式进行大数据流的处理。通常用于实时分析,在线机器学习、持续计算、分布式 RPC、ETL 等场景。Storm 具有以下特点:
Hadoop 采用 MapReduce 处理数据,而 MapReduce 主要是对数据进行批处理,这使得 Hadoop 更适合于海量数据离线处理的场景。而 Strom 的设计目标是对数据进行实时计算,这使得其更适合实时数据分析的场景。
Spark Streaming 并不是真正意义上的流处理框架。 Spark Streaming 接收实时输入的数据流,并将数据拆分为一系列批次,然后进行微批处理。只不过 Spark Streaming 能够将数据流进行极小粒度的拆分,使得其能够得到接近于流处理的效果,但其本质上还是批处理(或微批处理)。
storm 和 Flink 都是真正意义上的实时计算框架。其对比如下:
storm | flink | |
---|---|---|
状态管理 | 无状态 | 有状态 |
窗口支持 | 对事件窗口支持较弱,缓存整个窗口的所有数据,窗口结束时一起计算 | 窗口支持较为完善,自带一些窗口聚合方法, 并且会自动管理窗口状态 |
消息投递 | At Most Once At Least Once | At Most Once At Least Once Exactly Once |
容错方式 | ACK 机制:对每个消息进行全链路跟踪,失败或者超时时候进行重发 | 检查点机制:通过分布式一致性快照机制, 对数据流和算子状态进行保存。在发生错误时,使系统能够进行回滚。 |
注 : 对于消息投递,一般有以下三种方案:
- At Most Once : 保证每个消息会被投递 0 次或者 1 次,在这种机制下消息很有可能会丢失;
- At Least Once : 保证了每个消息会被默认投递多次,至少保证有一次被成功接收,信息可能有重复,但是不会丢失;
- Exactly Once : 每个消息对于接收者而言正好被接收一次,保证即不会丢失也不会重复。
在流处理之前,数据通常存储在数据库或文件系统中,应用程序根据需要查询或计算数据,这就是传统的静态数据处理架构。Hadoop 采用 HDFS 进行数据存储,采用 MapReduce 进行数据查询或分析,这就是典型的静态数据处理架构。
而流处理则是直接对运动中数据的处理,在接收数据的同时直接计算数据。实际上,在真实世界中的大多数数据都是连续的流,如传感器数据,网站用户活动数据,金融交易数据等等 ,所有这些数据都是随着时间的推移而源源不断地产生。
接收和发送数据流并执行应用程序或分析逻辑的系统称为流处理器。流处理器的基本职责是确保数据有效流动,同时具备可扩展性和容错能力,Storm 和 Flink 就是其代表性的实现。
流处理带来了很多优点:
可以立即对数据做出反应:降低了数据的滞后性,使得数据更具有时效性,更能反映对未来的预期;
可以处理更大的数据量:直接处理数据流,并且只保留数据中有意义的子集,然后将其传送到下一个处理单元,通过逐级过滤数据,从而降低实际需要处理的数据量;
更贴近现实的数据模型:在实际的环境中,一切数据都是持续变化的,想要通过历史数据推断未来的趋势,必须保证数据的不断输入和模型的持续修正,典型的就是金融市场、股票市场,流处理能更好地处理这些场景下对数据连续性和及时性的需求;
分散和分离基础设施:流式处理减少了对大型数据库的需求。每个流处理程序通过流处理框架维护了自己的数据和状态,这使其更适合于当下最流行的微服务架构。
本用例源码下载地址:storm-hdfs-integration
项目主要依赖如下,有两个地方需要注意:
<repository>
标签指定 CDH 的仓库地址;hadoop-common
、hadoop-client
、hadoop-hdfs
均需要排除 slf4j-log4j12
依赖,原因是 storm-core
中已经有该依赖,不排除的话有 JAR 包冲突的风险;1 | <properties> |
1 | /** |
产生的模拟数据格式如下:
1 | SparkHBase |
这里 HDFS 的地址和数据存储路径均使用了硬编码,在实际开发中可以通过外部传参指定,这样程序更为灵活。
1 | public class DataToHdfsApp { |
可以用直接使用本地模式运行,也可以打包后提交到服务器集群运行。本仓库提供的源码默认采用 maven-shade-plugin
进行打包,打包命令如下:
1 | mvn clean package -D maven.test.skip=true |
运行后,数据会存储到 HDFS 的 /storm-hdfs
目录下。使用以下命令可以查看目录内容:
1 | 查看目录内容 |
集成用例: 进行词频统计并将最后的结果存储到 HBase,项目主要结构如下:
本用例源码下载地址:storm-hbase-integration
1 | <properties> |
1 | /** |
产生的模拟数据格式如下:
1 | SparkHBase |
1 | /** |
1 | /** |
1 | /** |
可以用直接使用本地模式运行,也可以打包后提交到服务器集群运行。本仓库提供的源码默认采用 maven-shade-plugin
进行打包,打包命令如下:
1 | mvn clean package -D maven.test.skip=true |
运行后,数据会存储到 HBase 的 WordCount
表中。使用以下命令查看表的内容:
1 | hbase > scan 'WordCount' |
在上面的用例中我们是手动编码来实现词频统计,并将最后的结果存储到 HBase 中。其实也可以在构建 SimpleHBaseMapper
的时候通过 withCounterFields
指定 count 字段,被指定的字段会自动进行累加操作,这样也可以实现词频统计。需要注意的是 withCounterFields 指定的字段必须是 Long 类型,不能是 String 类型。
1 | SimpleHBaseMapper mapper = new SimpleHBaseMapper() |