数据架构及storm机制小结

来源:互联网 发布:程序员的思维方式 编辑:程序博客网 时间:2024/05/18 00:37

数据采集架构:

 

一 storm是什么

Storm是Twitter开源的分布式实时计算系统,Storm通过简单的API使开发者可以可靠地处理无界持续的流数据,进行实时计算,开发语言为Clojure和Java。

Storm的应用场景很多:实时分析、在线机器学习、持续计算、分布式RPC、ETL处理,等等

二 storm  vs  hadoop 对比架构图

 

三 Storm构件机制

客户端提交及分配任务:

(1)客户端向nimbus提交topology任务;

(2)supervisor从nimbus下载topology任务(代码和序列化文件,java需要序列化):根据zookeeper配置然后找到nimbus对应分配目录任务下载;

(3)storm ui从nimbus获取topology运行的统计信息。

备注:nimbus实际上会运行一个thrift服务器,用于接收用户提交的结构,opology实际上是通过thrift定义的一个struct,TopologyBuilder将这个对象建立起来

Zookeeper功能:

(1)存储客户端提供的topology任务信息,nimbus负责将任务分配信息写入Zookeeper,supervisor从Zookeeper上读取任务分配信息;

(2)存储supervisor和worker的心跳(包括它们的状态),使得nimbus可以监控整个集群的状态, 从而重启一些挂掉的worker;

(3)存储整个集群的所有状态信息和配置信息。

目录结构里面, nimbus机器上面只有/nimbus目录,supervisor机器上面只有/supervisor目录和/workers目录

Storm在集群上运行一个Topology时,主要通过以下3个实体来完成Topology的执行工作:

1. Worker(进程)
2. Executor(线程)
3. Task(逻辑概念任务Bolt或spout实例,Storm0.8后多个task由一个excutor执行) 

4.Spout 发送节点 bolt处理节点
// builder.setBolt("uvbolt", new UvBolt(),2).setNumTasks(4).fieldsGrouping("pvbolt", new Fields("pid","uid")) ; 

//  UvBolt开启4个task实例(bolt实例),右2个线程执行,如果不设置tasknumber,默认2个线程执行2个task,默认一个线程一个task,每个线程执行task是串行,开启4个task,相同pid,uid进入相同task

下图简要描述了这3者之间的关系:


1个worker进程执行的是1个topology的子集(注:不会出现1个worker为多个topology服务)。1个worker进程会启动1个或多个executor线程来执行1个topology的component(spout或bolt)。因此,1个运行中的topology就是由集群中多台物理机上的多个worker进程组成的。
executor是1个被worker进程启动的单独线程。每个executor只会运行1个topology的1个component(spout或bolt)的task(注:task可以是1个或多个,storm默认是1个component只生成1个task,executor线程里会在每次循环里顺序调用所有task实例)。
task是最终运行spout或bolt中代码的单元(注:1个task即为spout或bolt的1个实例,executor线程在执行期间会调用该task的nextTuple或execute方法)。topology启动后,1个component(spout或bolt)的task数目是固定不变的,但该component使用的executor线程数可以动态调整(例如:1个executor线程可以执行该component的1个或多个task实例)。这意味着,对于1个component存在这样的条件:#threads<=#tasks(即:线程数小于等于task数目,storm rebalance调整但是不能超过tasks数)。默认情况下task的数目等于executor线程数目,即1个executor线程只运行1个task。

 

备注:一个灰格一个线程,绿色task四个,由2个线程同时完成,其它启动多线程默认一线程执行一个task, 

Task,执行具体数据处理的相关实体,也就是用户实现的Spout/Blot实例。Storm中,一个executor可能会对应一个或者多个task,默认由机器配置决定slots槽数控制jvm

Config conf = new Config(); 

conf.setNumWorkers(2); // use two worker processes 

topologyBuilder.setSpout("blue-spout", new BlueSpout(), 2); // parallelism hint

topologyBuilder.setBolt("green-bolt", new GreenBolt(), 2) .setNumTasks(4) .shuffleGrouping("blue-spout"); 

topologyBuilder.setBolt("yellow-bolt", new YellowBolt(), 6) .shuffleGrouping("green-bolt");

StormSubmitter.submitTopology( "mytopology", conf, topologyBuilder.createTopology() );

虚拟机:2  线程数:2+2+6=10 task:2+4+6=12 每个jvm需要开启5个线程

//默认一个excutor一个task.动态调整workprocess和excutors,通过rebalance,无需重启storm 如$ storm rebalance mytopology -n 5 -e blue-spout=3 -e yellow-bolt=10

 

 

 

Intra-worker communication in Storm (inter-thread on the same Storm node): LMAX Disruptor(高并发消息架构)

Inter-worker communication (node-to-node across the network): ZeroMQ or Netty(storm 0.9)

Inter-topology communication: nothing built into Storm, you must take care of this yourself with e.g. a messaging system such as Kafka/RabbitMQ, a database, etc.

四Storm API编程:

 

spout的流的源头。比如一个spout可能从Kestrel队列里面读取消息并且把这些消息发射成一个流。又比如一个spout可以调用twitter的一个api并且把返回的tweets发射成一个流。

bolt可以接收任意多个输入stream, 作一些处理, 有些bolt可能还会发射一些新的stream。一些复杂的流转换, 比如从一些tweet里面计算出热门话题, 需要多个步骤, 从而也就需要多个bolt。 Bolt可以做任何事情: 运行函数, 过滤tuple, 做一些聚合, 做一些合并以及访问数据库等等。

spout和bolt所组成一个网络会被打包成topology, topology是storm里面最高一级的抽象, 你可以把topology提交给storm的集群来运行。topology的结构在Topology那一段已经说过了,这里就不再赘述了。

如下:

TopologyBuilder builder = new TopologyBuilder();

builder.setSpout(1, new RandomSentenceSpout(), 5 );

builder.setBolt(2, new SplitSentence(), 8 ) .shuffleGrouping(1);

builder.setBolt(3, new WordCount(), 12) .fieldsGrouping(2, new Fields("word"));

Stream groupings: 消息分发策略

storm里面有6种类型的stream grouping:

Shuffle Grouping: 随机分组, 随机派发stream里面的tuple, 保证每个bolt接收到的tuple数目相同。

Fields Grouping:按字段分组, 比如按userid来分组, 具有同样userid的tuple会被分到相同的Bolts, 而不同的userid则会被分配到不同的Bolts。

All Grouping: 广播发送, 对于每一个tuple, 所有的Bolts都会收到。

Global Grouping: 全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。

Non Grouping: 不分组, 这个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果, 有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。

Direct Grouping: 直接分组,  这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。 只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。消息处理者可以通过TopologyContext来获取处理它的消息的taskid (OutputCollector.emit方法也会返回taskid)

Storm 编程注意点:

1 日志组件 jcl log4j logback容易冲突,本地可以运行,但集群中跑不起来

2 实例变量序列化问题,如果不可序列化要定义transient

3 线程安全问题


0 0
原创粉丝点击