本节书摘来华章计算机《Storm实时数据处理》一书中的第1章 ,第1.7节,(澳)Quinton Anderson 著 卢誉声 

1.7 获取基本的点击率统计信息

统计点击率Topology用于记录基本的网站使用量统计信息,具体来说它会统计以下信息:

  • 访客数量
  • 独立访客数量
  • 特定国家的访客数量
  • 特定城市的访客数量
  • 特定国家中每个城市访客数量的百分比

该系统假定访客总量一定,而且希望服务端的用户标示与客户端的Cookies是相对应的。该Topology通过IP地址和公用IP解析服务获取地理位置信息。

统计点击率Topology还将使用Redis存储发送到Topology的点击事件,具体来说就是将其作为一个持久化队列;除此以外还要利用Redis记录再次访问网站的访客信息。

关于Redis的更多信息,请访问Redis.io。

1.7.1 准备工作

在我们开始之前,先要安装Redis(2.6或更高版本):

点击量统计 java github 点击率统计_点击量统计 java github

然后启动Redis服务器。

1.7.2 实战

Step01 新建一个名为click-topology的Java项目,然后按照创建“Hello World” Topology项目的方法建立pom.xml文件和目录结构。
Step02 在pom.xml文件中修改对应的项目名称和引用,然后在标签中添加以下依赖项:

点击量统计 java github 点击率统计_java_02


点击量统计 java github 点击率统计_java_03

Step03 要特别注意JUnit和JMock的scope定义,避免将它们包含在用于最终部署的JAR包中。

Step04 在src/main/java目录下的package storm.cookbook包中创建ClickTopology主类。该类定义了Topology,并提供了在集群或者本地模式下运行Topology的机制。按照下面的方式创建这个类:

点击量统计 java github 点击率统计_java_04


点击量统计 java github 点击率统计_java_05

Step05 然后实现main方法,该方法根据运行时传递进来的参数个数来决定使用哪种Topology运行模式:

点击量统计 java github 点击率统计_点击量统计 java github_06

Step06 这个Topology假定由Web服务器向Redis队列推送消息。因此你必须创建一个Spout,才能将这些消息作为一个流添加到Storm集群中。在storm.coobook包中创建ClickSpout类,用于在集群启动时建立与Redis的连接:

点击量统计 java github 点击率统计_点击量统计 java github_07


点击量统计 java github 点击率统计_Redis_08

Step07 集群会通过nextTuple方法从Spout获取新的Tuple:

点击量统计 java github 点击率统计_数据库_09

Step08 接下来,我们需要创建Bolt,其作用是通过数据库或者远程API查询来丰富基本数据。让我们从“处理重复访客信息Bolt”开始创建,该Bolt会比较客户端ID与之前访问记录是否一致,以此判断用户是否第一次访问,然后发送处理后包含这个标记的Tuple。创建RepeatVisitBolt类,提供打开逻辑和Redis连接逻辑:

点击量统计 java github 点击率统计_点击量统计 java github_10

Step09 在execute方法中,Tuple由集群中的ClickSpout类提交。Bolt会基于Tuple里的字段,从Redis查询之前的访问标记,然后发送处理后的Tuple:

点击量统计 java github 点击率统计_点击量统计 java github_11

Step10 接下来就该创建“处理地理位置信息Bolt”了。该Bolt会通过远程API调用查询客户IP地址所对应的国家和城市。GeographyBolt类把实际的调用委托给一个预先添加的IP解析器,以便于提高类的可测试性。在storm.cookbook包中创建GeographyBolt类,并继承BaseRichBolt接口,然后实现execute方法:

点击量统计 java github 点击率统计_点击量统计 java github_12

Step11 为了能够使用这个解析器,我们需要自己实现一个名为HttpIPResolver的解析器,并在设计的时候就将其添加到GeographyBolt类的实现当中:

点击量统计 java github 点击率统计_大数据_13

Step12 接下来,我们还需要获取地理位置统计信息。GeoStatsBolt类的原理很简单,它从GeographicBolt类接收处理完成后的Tuple,与此同时在内存中维护这个数据结构。它还可以发送更新的统计信息给订阅者。GeoStatsBolt类的设计初衷是让我们能够把不同国家的总人口数据分割到不同的Bolt中进行处理。但需要确保一个国家所有城市的数据在同一个Bolt中进行处理。Topology就是根据不同国家这一点将流分割并添加到Bolt中的。

点击量统计 java github 点击率统计_Redis_14

Step13 创建GeoStatsBolt类,并实现execute方法:

点击量统计 java github 点击率统计_数据库_15

Step14 大部分逻辑都包含在内部模型类中,这个类在内存中维护城市和国家信息:

点击量统计 java github 点击率统计_数据库_16


点击量统计 java github 点击率统计_点击量统计 java github_17

Step15 最后,基于RepeatVisitBolt类处理完成后的流,VisitorStatsBolt方法对访客数量和独立访客数量进行最终统计。这个Bolt在内存中维护了访客与独立访客的数量,它需要接收所有的计数信息并进行统计,我们能通过Topology中的定义看出些端倪:

点击量统计 java github 点击率统计_java_18

Step16 现在来实现VisitorStatsBolt类,创建这个类并定义两个整型成员变量,total和uniqueCount,然后实现execute方法:

点击量统计 java github 点击率统计_点击量统计 java github_19

1.7.3 解析

点击量统计 java github 点击率统计_Redis_20

Spout把Web服务器上获得的点击事件发送到Topology中,再通过随机分组转发给“处理地理位置信息Bolt”和“处理重复访客信息Bolt”。这样能保证集群内的负载均衡,对于像这样处理速度慢或高延时的处理过程来说负载均衡尤为重要。
在设计Topology之前,需要充分理解数据模型的交换结合性质、你的流的其他问题和结构的固有模型。
在搭建Topology的时候,要对Storm的并行性有充分的认识。Storm wiki上有一篇文章对这个问题作了很好的总结,网址是https://github.com/nathanmarz/storm/wiki/Understanding-the-parallelism-of-a-Storm-topology。其中有几个要点需要我们注意:

  • Topology中工作进程(Worker)的数量(TOPOLOGY_WORKERS)。
  • Topology中每个组件执行单元(线程)的数量。这个值取决于并行程度。值得注意的是,这组值只是初始值(线程数),运行过程中可通过Topology重新配置(通过UI或CLI)执行单元的数量。还可以通过Config#setMaxTaskParallelism()方法限制执行单元的数量。
  • 每个执行单元的默认任务数都是1。可以在声明新组件的时候通过ComponentConfigurationDeclarer#setNumTasks()方法调整这个值。

这些是调整集群大小时要点。集群会尝试分发任务给工作进程,每个进程包含许多执行单元,而每个执行单元又可能在运行一个或多个任务。每个工作进程的执行单元数量其实是一个执行单元总数量和执行进程总数量之比的函数。关于这个问题,可以在刚才提到的wiki页面上找到一个很好的例子。
可以参考节点的数量和每个节点处理器的核数来调整集群大小。我们推荐为每个线程(执行单元)分配一个核。