Apache Flume 如何解析消息中的事件时间

数据开发工作中,从上游消息队列抽取数据是一项常规的 ETL 流程。在基于 Hadoop 构建的数据仓库体系中,我们通常会使用 Flume 将事件日志从 Kafka 抽取到 HDFS,然后针对其开发 MapReduce 脚本,或直接创建以时间分区的 Hive 外部表。这项流程中的关键一环是提取日志中的事件时间,因为实时数据通常会包含延迟,且在系统临时宕机的情况下,我们需要追回遗漏的数据,因而使用的时间戳必须是事件产生的时间。Flume 提供的诸多工具能帮助我们非常便捷地实现这一点。

Apache Flume

HDFS Sink 和时间戳头信息

以下是一个基本的 HDFS Sink 配置:

1
2
3
a1.sinks = k1
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /user/flume/ds_alog/dt=%Y%m%d

%Y%m%d 是该 Sink 支持的时间占位符,它会使用头信息中 timestamp 的值来替换这些占位符。HDFS Sink 还提供了 hdfs.useLocalTimeStamp 选项,直接使用当前系统时间来替换时间占位符,但这并不是我们想要达到的目的。

我们还可以使用 Hive Sink 直接将事件日志导入成 Hive 表,它能直接和 Hive 元数据库通信,自动创建表分区,并支持分隔符分隔和 JSON 两种序列化形式。当然,它同样需要一个 timestamp 头信息。不过,我们没有选择 Hive Sink,主要出于以下原因:

  • 它不支持正则表达式,因此我们无法从类似访问日志这样的数据格式中提取字段列表;
  • 它所提取的字段列表是根据 Hive 表信息产生的。假设上游数据源在 JSON 日志中加入了新的键值,直至我们主动更新 Hive 元信息,这些新增字段将被直接丢弃。对于数据仓库来说,完整保存原始数据是很有必要的。

阅读全文

Spark Streaming 中如何实现 Exactly-Once 语义

Exactly-once 语义是实时计算的难点之一。要做到每一条记录只会被处理一次,即使服务器或网络发生故障时也能保证没有遗漏,这不仅需要实时计算框架本身的支持,还对上游的消息系统、下游的数据存储有所要求。此外,我们在编写计算流程时也需要遵循一定规范,才能真正实现 Exactly-once。本文将讲述如何结合 Spark Streaming 框架、Kafka 消息系统、以及 MySQL 数据库来实现 Exactly-once 的实时计算流程。

Spark Streaming

引例

首先让我们实现一个简单而完整的实时计算流程。我们从 Kafka 接收用户访问日志,解析并提取其中的时间和日志级别,并统计每分钟错误日志的数量,结果保存到 MySQL 中。

示例日志:

1
2
3
2017-07-30 14:09:08 ERROR some message
2017-07-30 14:09:20 INFO some message
2017-07-30 14:10:50 ERROR some message

结果表结构,其中 log_time 字段会截取到分钟级别:

1
2
3
4
create table error_log (
log_time datetime primary key,
log_count int not null default 0
);

阅读全文

通过 SQL 查询学习 Pandas 数据处理

Pandas 是一款广泛使用的数据处理工具。结合 NumPy 和 Matplotlib 类库,我们可以在内存中进行高性能的数据清洗、转换、分析及可视化工作。虽然 Python 本身是一门非常容易学习的语言,但要熟练掌握 Pandas 丰富的 API 接口及正确的使用方式,还是需要投入一定时间的。对于数据开发工程师或分析师而言,SQL 语言是标准的数据查询工具。本文提供了一系列的示例,如何将常见的 SQL 查询语句使用 Pandas 来实现。

Pandas 的安装和基本概念并不在本文讲述范围内,请读者到官网上阅读相关文档,或者阅读《利用 Python 进行数据分析》一书。我推荐大家使用 Anaconda Python 套件,其中集成了 Spyder 集成开发环境。在运行下文的代码之前,请先引入 Pandas 和 NumPy 包:

1
2
import pandas as pd
import numpy as np

FROM - 读取数据

首先,我们需要将数据加载到工作区(内存)。Pandas 原生支持非常多的数据格式,CSV 是较常见的一种。我们以航班延误时间数据集为例(下载地址):

1
2
3
4
date,delay,distance,origin,destination
02221605,3,358,BUR,SMF
01022100,-5,239,HOU,DAL
03210808,6,288,BWI,ALB

我们可以使用 pd.read_csv 函数加载它:

1
2
df = pd.read_csv('flights.csv', dtype={'date': str})
df.head()

这条命令会将 flights.csv 文件读入内存,使用首行作为列名,并自动检测每一列的数据类型。其中,由于 date 一列的日期格式是 %m%d%H%M,自动转换成数字后会失去月份的前异零(02 月的 0),因此我们显式指定了该列的 dtype,告知 Pandas 保留原值。

阅读全文

使用 WebSocket 和 Python 编写日志查看器

在生产环境运维工作中,查看线上服务器日志是一项常规工作。如果这项工作可以在浏览器中进行,而无需登录服务器执行 tail -f 命令,就太方便了。我们可以使用 WebSocket 技术轻松实现这一目标。在本文中,我将带各位一起使用 Python 编写一个日志查看工具。

基于 WebSocket 的日志查看器

WebSocket 简介

WebSocket 是一个标准化协议,构建在 TCP 之上,能够在客户端和服务端之间建立一个全双工的通信渠道。这里的客户端和服务端通常是用户浏览器和 Web 服务器。在 WebSocket 诞生之前,如果我们想保持这样的一个长连接,就需要使用诸如长轮询、永久帧、Comet 等技术。而现今 WebSocket 已经得到了所有主流浏览器的支持,我们可以使用它开发出在线聊天室、游戏、实时仪表盘等软件。此外,WebSocket 可以通过 HTTP Upgrade 请求来建立连接,并使用 80 端口通信,从而降低对现有网络环境的影响,如无需穿越防火墙。

阅读全文

为什么不用 ES6 完全替换 Lodash

Lodash 是一款非常知名的 JavaScript 工具库,能够让开发者十分便捷地操纵数组和对象。我则是非常喜欢用它提供的函数式编程风格来操作集合类型,特别是链式调用和惰性求值。然而,随着 ECMAScript 2015 Standard (ES6) 得到越来越多主流浏览器的支持,以及像 Babel 这样,能够将 ES6 代码编译成 ES5 从而在旧浏览器上运行的工具日渐流行,人们会发现许多 Lodash 提供的功能已经可以用 ES6 来替换了。然而真的如此吗?我认为,Lodash 仍然会非常流行,因为它可以为程序员提供更多的便利,并且优化我们编程的方式。

_.mapArray#map 是有区别的

在处理集合对象时,_.map_.reduce_.filter、以及 _.forEach 的使用频率很高,而今 ES6 已经能够原生支持这些操作:

1
2
3
4
5
6
7
8
9
10
_.map([1, 2, 3], (i) => i + 1)
_.reduce([1, 2, 3], (sum, i) => sum + i, 0)
_.filter([1, 2, 3], (i) => i > 1)
_.forEach([1, 2, 3], (i) => { console.log(i) })

// 使用 ES6 改写
[1, 2, 3].map((i) => i + 1)
[1, 2, 3].reduce((sum, i) => sum + i, 0)
[1, 2, 3].filter((i) => i > 1)
[1, 2, 3].forEach((i) => { console.log(i) })

但是,Lodash 的 _.map 函数功能更强大,它能够操作对象类型,提供了遍历和过滤的快捷方式,能够惰性求值,对 null 值容错,并且有着更好的性能。

阅读全文

使用 Crossfilter 和 dc.js 构建交互式报表

在对多维数据集进行图表分析时,我们希望在图表之间建立联系,选择图表中的一部分数据后,其他图表也会相应变动。这项工作可以通过开发完成,即在服务端对数据进行过滤,并更新所有图表。此外,我们还可以借助 Crossfilter 和 dc.js 这两个工具,直接在浏览器中对数据进行操作。

航班延误统计

这是 Crossfilter 官方网站提供的示例,基于 ASA Data Expo 数据集的航班延误统计。下面我们将介绍如何用 dc.js 来实现这份交互式报表。项目源码可以在 JSFiddle 中浏览,演示的数据量减少到 1000 条。

阅读全文

Hive+Druid 实现快速查询;回归分析是机器学习吗;StructuredStreaming 可用于生产环境

结合 Apache Hive 和 Druid 实现高速 OLAP 查询

使用 HiveQL 预汇总数据并保存至 Druid

Hadoop 生态中,我们使用 Hive 将 SQL 语句编译为 MapReduce 任务,对海量数据进行操作;Druid 则是一款独立的分布式列式存储系统,通常用于执行面向最终用户的即席查询和实时分析。

Druid 的高速查询主要得益于列式存储和倒排索引,其中倒排索引是和 Hive 的主要区别。数据表中的维度字段越多,查询速度也会越快。不过 Druid 也有其不适用的场景,如无法支持大数据量的 Join 操作,对标准 SQL 的实现也十分有限。

Druid 和 Hive 的结合方式是这样的:首先使用 Hive 对数据进行预处理,生成 OLAP Cube 存入 Druid;当发生查询时,使用 Calcite 优化器进行分析,使用合适的引擎(Hive 或 Druid)执行操作。如,Druid 擅长执行维度汇总、TopN、时间序列查询,而 Hive 则能胜任 Join、子查询、UDF 等操作。

原文:https://dzone.com/articles/ultra-fast-olap-analytics-with-apache-hive-and-dru

阅读全文

开发人员必知的 5 种开源框架

作者:John Esposito

软件侵吞着世界已经四年多了,但开发人员看待软件的方式稍有不同。我们一直在致力于解决实际问题,而很少思考软件开发的基石。当问题变得更庞大、解决方案更复杂时,一些实用的、不怎么产生泄漏的抽象工具就显得越来越重要。

简单地来说,在那些追求生产效率的开发者眼中,框架 正在吞食着世界。那究竟是哪些框架、各自又在吞食着哪一部分呢?

开源界的开发框架实在太多了,多到近乎疯狂的地步。我从2015年各种领域的榜单中选取了最受欢迎的5种框架。对于前端框架(我所擅长的领域),我只选取那些真正的客户端框架,这是因为现今的浏览器和移动设备已经具备非常好的性能,越来越多的单页应用(SPA)正在避免和服务端交换数据。

  1. 展现层:Bootstrap

我们从技术栈的顶端开始看——展现层,这一开发者和普通用户都会接触到的技术。展现层的赢家毫无疑问仍是Bootstrap。Bootstrap的流行度非常之惊人,远远甩开了它的老对手Foundation,以及新星Material Design Lite。在BuiltWith上,Bootstrap占据主导地位;而在GitHub上则长期保持Star数Fork数最多的记录。

如今,Bootstrap仍然有着非常活跃的开发社区。8月,Bootstrap发布了v4内测版,庆祝它的四岁生日。这个版本是对现有功能的简化和扩充,主要包括:增强可编程性;从Less迁移至Sass;将所有HTML重置代码集中到一个模块;大量自定义样式可直接通过Sass变量指定;所有JavaScript插件都改用ES6重写等。开发团队还开设了官方主题市场,进一步扩充现有的主题生态

  1. 网页MVC:AngularJS

随着网页平台技术越来越成熟,开发者们可以远离仍在使用标记语言进行着色的DOM对象,转而面对日渐完善的抽象层进行开发。这一趋势始于现代单页应用(SPA)对XMLHttpRequest的高度依赖,而其中流行的SPA框架当属AngularJS

AngularJS有什么特别之处呢?一个词:指令(directive)。一个简单的ng-就能让标签“起死回生”(从静态的标记到动态的JS代码)。依赖注入也是很重要的功能,许多Angular特性都致力于简化维护成本,并进一步从DOM中抽象出来。其基本原则就是将声明式的展现层代码和命令式的领域逻辑充分隔离开来,这种做法对于使用过POM或ORM的人尤为熟悉(我们之中还有人体验过XAML)。这一思想令人振奋,解放了开发者,甚至让人第一眼看上去有些奇怪——因为它赋予了HTML所不该拥有的能力。

有些遗憾的是,AngualrJS的“杀手锏”双向绑定(让视图和模型数据保持一致)将在Angular2中移除,已经临近公测。虽然这一魔法般的特性即将消失,却带来了极大的性能提升,并降低了调试的难度(可以想象一下在悬崖边行走的感觉)。随着单页应用越来越庞大和复杂,这种权衡会变得更有价值。

阅读全文

使用 Spring AOP 向领域模型注入依赖

贫血领域模型这篇译文中,Martin阐述了这种“反模式”的症状和问题,并引用了领域驱动设计中的话来说明领域模型和分层设计之间的关系。对于Spring项目的开发人员来说,贫血领域模型十分常见:模型(或实体)仅仅包含对数据表的映射,通常是一组私有属性和公有getter/setter,所有的业务逻辑都写在服务层中,领域模型仅仅用来传递数据。为了编写真正的领域模型,我们需要将业务逻辑移至模型对象中,这就引出另一个问题:业务逻辑通常需要调用其他服务或模型,而使用new关键字或由JPA创建的对象是不受Spring托管的,也就无法进行依赖注入。解决这个问题的方法有很多,比较之后我选择使用面向切面编程来实现。

面向切面编程

面向切面编程,或AOP,是一种编程范式,和面向对象编程(OOP)互为补充。简单来说,AOP可以在不修改既有代码的情况下改变代码的行为。开发者通过定义一组规则,在特定的类方法前后增加逻辑,如记录日志、性能监控、事务管理等。这些逻辑称为切面(Aspect),规则称为切点(Pointcut),在调用前还是调用后执行称为通知(Before advice, After advice)。最后,我们可以选择在编译期将这些逻辑写入类文件,或是在运行时动态加载这些逻辑,这是两种不同的织入方式(Compile-time weaving, Load-time weaving)。

对于领域模型的依赖注入,我们要做的就是使用AOP在对象创建后调用Spring框架来注入依赖。幸运的是,Spring AOP已经提供了@Configurable注解来帮助我们实现这一需求。

阅读全文

贫血领域模型

原文:http://www.martinfowler.com/bliki/AnemicDomainModel.html

贫血领域模型是一个存在已久的反模式,目前仍有许多拥趸者。一次我和Eric Evans聊天谈到它时,都觉得这个模型似乎越来越流行了。作为领域模型的推广者,我们觉得这不是一件好事。

贫血领域模型的最初症状是:它第一眼看起来还真像这么回事儿。项目中有许多对象,它们的命名都是根据领域来的。对象之间有着丰富的连接方式,和真正的领域模型非常相似。但当你检视这些对象的行为时,会发现它们基本上没有任何行为,仅仅是一堆getter和setter的集合。其实这些对象在设计之初就被定义为只能包含数据,不能加入领域逻辑。这些逻辑要全部写入一组叫Service的对象中。这些Service构建在领域模型之上,使用这些模型来传递数据。

这种反模式的恐怖之处在于,它完全是和面向对象设计背道而驰。面向对象设计主张将数据和行为绑定在一起,而贫血领域模型则更像是一种面向过程设计,我和Eric在Smalltalk时就极力反对这种做法。更糟糕的时,很多人认为这些贫血领域对象是真正的对象,从而彻底误解了面向对象设计的涵义。

阅读全文