使用 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重写等。开发团队还开设了官方主题市场,进一步扩充现有的主题生态

2. 网页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时就极力反对这种做法。更糟糕的时,很多人认为这些贫血领域对象是真正的对象,从而彻底误解了面向对象设计的涵义。

阅读全文

HotSpot JVM 中的对象指针压缩

原文:https://wiki.openjdk.java.net/display/HotSpot/CompressedOops

什么是一般对象指针?

一般对象指针(oop, ordinary object pointer)是HotSpot虚拟机的一个术语,表示受托管的对象指针。它的大小通常和本地指针是一样的。Java应用程序和GC子系统会非常小心地跟踪这些受托管的指针,以便在销毁对象时回收内存空间,或是在对空间进行整理时移动(复制)对象。

在一些从Smalltalk和Self演变而来的虚拟机实现中都有一般对象指针这个术语,包括:

部分系统中会使用小整型(smi, small integers)这个名称,表示一个指向30位整型的虚拟指针。这个术语在Smalltalk的V8实现中也可以看到。

为什么需要压缩?

LP64系统中,指针需要使用64位来表示;ILP32系统中则只需要32位。在ILP32系统中,堆内存的大小只能支持到4Gb,这对很多应用程序来说是不够的。在LP64系统中,所有应用程序运行时占用的空间都会比ILP32大1.5倍左右,这是因为指针占用的空间增加了。虽然内存是比较廉价的,但网络带宽和缓存容量是紧张的。所以,为了解决4Gb的限制而增加堆内存的占用空间,就有些得不偿失了。

在x86芯片中,ILP32模式可用的寄存器数量是LP64模式的一半。SPARC没有此限制;RISC芯片本来就提供了很多寄存器,LP64模式下会提供更多。

压缩后的一般对象指针在使用时需要将32位整型按因数8进行扩展,并加到一个64位的基础地址上,从而找到所指向的对象。这种方法可以表示四十亿个对象,相当于32Gb的堆内存。同时,使用此法压缩数据结构也能达到和ILP32系统相近的效果。

我们使用解码来表示从32位对象指针转换成64位地址的过程,其反过程则称为编码

阅读全文

Apache HBase 的适用场景

原文:http://blog.cloudera.com/blog/2011/04/hbase-dos-and-donts/

最近我在洛杉矶Hadoop用户组做了一次关于HBase适用场景的分享。在场的听众水平都很高,给到了我很多值得深思的反馈。主办方是来自Shopzilla的Jody,我非常感谢他能给我一个在60多位Hadoop使用者面前演讲的机会。可能一些朋友没有机会来洛杉矶参加这次会议,我将分享中的主要内容做了一个整理。如果你没有时间阅读全文,以下是一些摘要:

  • HBase很棒,但不是关系型数据库或HDFS的替代者;
  • 配置得当才能运行良好;
  • 监控,监控,监控,重要的事情要说三遍。

Cloudera是HBase的铁杆粉丝。我们热爱这项技术,热爱这个社区,发现它能适用于非常多的应用场景。HBase如今已经有很多成功案例,所以很多公司也在考虑如何将其应用到自己的架构中。我做这次分享以及写这篇文章的动因就是希望能列举出HBase的适用场景,并提醒各位哪些场景是不适用的,以及如何做好HBase的部署。

阅读全文

深入理解 Reduce-side Join

在《MapReduce Design Patterns》一书中,作者给出了Reduce-side Join的实现方法,大致步骤如下:

  1. 使用MultipleInputs指定不同的来源表和相应的Mapper类;
  2. Mapper输出的Key为Join的字段内容,Value为打了来源表标签的记录;
  3. Reducer在接收到同一个Key的记录后,执行以下两步:
    1. 遍历Values,根据标签将来源表的记录分别放到两个List中;
    2. 遍历两个List,输出Join结果。

具体实现可以参考这段代码。但是这种实现方法有一个问题:如果同一个Key的记录数过多,存放在List中就会占用很多内存,严重的会造成内存溢出(Out of Memory, OOM)。这种方法在一对一的情况下没有问题,而一对多、多对多的情况就会有隐患。那么,Hive在做Reduce-side Join时是如何避免OOM的呢?两个关键点:

  1. Reducer在遍历Values时,会将前面的表缓存在内存中,对于最后一张表则边扫描边输出;
  2. 如果前面几张表内存中放不下,就写入磁盘。

阅读全文