Storm介绍与原理详解

来源:互联网 发布:java md5加密后的长度 编辑:程序博客网 时间:2024/06/06 06:42

伴随着信息科技日新月异的发展,信息呈现出爆发式的膨胀,人们获取信息的途径也更加多样、更加便捷,同时对于信息的时效性要求也越来越高。举个搜索场景中的例子,当一个卖家发布了一条宝贝信息时,他希望的当然是这个宝贝马上就可以被卖家搜索出来、点击、购买啦,相反,如果这个宝贝要等到第二天或者更久才可以被搜出来,估计这个大哥就要骂娘了。再举一个推荐的例子,如果用户昨天在淘宝上买了一双袜子,今天想买一副泳镜去游泳,但是却发现系统在不遗余力地给他推荐袜子、鞋子,根本对他今天寻找泳镜的行为视而不见,估计这哥们心里就会想推荐你妹呀。其实稍微了解点背景知识的码农们都知道,这是因为后台系统做的是每天一次的全量处理,而且大多是在夜深人静之时做的,那么你今天白天做的事情当然要明天才能反映出来啦。

  • 实现一个实时计算系统

全量数据处理使用的大多是鼎鼎大名的hadoop或者hive,作为一个批处理系统,hadoop以其吞吐量大、自动容错等优点,在海量数据处理上得到了广泛的使用。但是,hadoop不擅长实时计算,因为它天然就是为批处理而生的,这也是业界一致的共识。否则最近这两年也不会有s4,storm,puma这些实时计算系统如雨后春笋般冒出来啦。先抛开s4,storm,puma这些系统不谈,我们首先来看一下,如果让我们自己设计一个实时计算系统,我们要解决哪些问题。

  1. 低延迟。都说了是实时计算系统了,延迟是一定要低的。
  2. 高性能。性能不高就是浪费机器,浪费机器是要受批评的哦。
  3. 分布式。系统都是为应用场景而生的,如果你的应用场景、你的数据和计算单机就能搞定,那么不用考虑这些复杂的问题了。我们所说的是单机搞不定的情况。
  4. 可扩展。伴随着业务的发展,我们的数据量、计算量可能会越来越大,所以希望这个系统是可扩展的。
  5. 容错。这是分布式系统中通用问题。一个节点挂了不能影响我的应用。

好,如果仅仅需要解决这5个问题,可能会有无数种方案,而且各有千秋,随便举一种方案,使用消息队列+分布在各个机器上的工作进程就ok啦。我们再继续往下看。

  1. 容易在上面开发应用程序。亲,你设计的系统需要应用程序开发人员考虑各个处理组件的分布、消息的传递吗?如果是,那有点麻烦啊,开发人员可能会用不好,也不会想去用。




  2. 消息不丢失。用户发布的一个宝贝消息不能在实时处理的时候给丢了,对吧?更严格一点,如果是一个精确数据统计的应用,那么它处理的消息要不多不少才行。这个要求有点高哦。

    诞 生

     在2011年Storm开源之前,由于Hadoop的火红,整个业界都在喋喋不休地谈论大数据。Hadoop的高吞吐,海量数据处理的能力使得人们可以方便地处理海量数据。但是,Hadoop的缺点也和它的优点同样鲜明——延迟大,响应缓慢,运维复杂。

    有需求也就有创造,在Hadoop基本奠定了大数据霸主地位的时候,很多的开源项目都是以弥补Hadoop的实时性为目标而被创造出来。而在这个节骨眼上Storm横空出世了。

    Storm带着流式计算的标签华丽丽滴出场了,看看它的一些卖点:

    • 分布式系统:可横向拓展,现在的项目不带个分布式特性都不好意思开源。
    • 运维简单:Storm的部署的确简单。虽然没有Mongodb的解压即用那么简单,但是它也就是多安装两个依赖库而已。
    • 高度容错:模块都是无状态的,随时宕机重启。
    • 无数据丢失:Storm创新性提出的ack消息追踪框架和复杂的事务性处理,能够满足很多级别的数据处理需求。不过,越高的数据处理需求,性能下降越严重。
    • 多语言:实际上,Storm的多语言更像是临时添加上去似的。因为,你的提交部分还是要使用Java实现。

    下面,我们简单地认识一下Storm这个产品。

    认 识

        Storm是一个免费开源、分布式、高容错的实时计算系统。Storm令持续不断的流计算变得容易,弥补了Hadoop批处理所不能满足的实时要求。Storm经常用于在实时分析、在线机器学习、持续计算、分布式远程调用和ETL等领域。Storm的部署管理非常简单,而且,在同类的流式计算工具,Storm的性能也是非常出众的。

        Storm主要分为两种组件Nimbus和Supervisor。这两种组件都是快速失败的,没有状态。任务状态和心跳信息等都保存在Zookeeper上的,提交的代码资源都在本地机器的硬盘上。

    • Nimbus负责在集群里面发送代码,分配工作给机器,并且监控状态。全局只有一个。
    • Supervisor会监听分配给它那台机器的工作,根据需要启动/关闭工作进程Worker。每一个要运行Storm的机器上都要部署一个,并且,按照机器的配置设定上面分配的槽位数。
    • Zookeeper是Storm重点依赖的外部资源。Nimbus和Supervisor甚至实际运行的Worker都是把心跳保存在Zookeeper上的。Nimbus也是根据Zookeerper上的心跳和任务运行状况,进行调度和任务分配的。
    • Storm提交运行的程序称为Topology。
    • Topology处理的最小的消息单位是一个Tuple,也就是一个任意对象的数组。
    • Topology由Spout和Bolt构成。Spout是发出Tuple的结点。Bolt可以随意订阅某个Spout或者Bolt发出的Tuple。Spout和Bolt都统称为component。

    下图是一个Topology设计的逻辑图的例子。

    下图是Topology的提交流程图。

    下图是Storm的数据交互图。可以看出两个模块Nimbus和Supervisor之间没有直接交互。状态都是保存在Zookeeper上。Worker之间通过ZeroMQ传送数据。

    虽然,有些地方做得还是不太好,例如,底层使用的ZeroMQ不能控制内存使用(下个release版本,引入了新的消息机制使用netty代替ZeroMQ),多语言支持更多是噱头,Nimbus还不支持HA。但是,就像当年的Hadoop那样,很多公司选择它是因为它是唯一的选择。而这些先期使用者,反过来促进了Storm的发展。

    发 展

    Storm已经发展到0.8.2版本了,看一下两年多来,它取得的成就:

    • 有50个大大小小的公司在使用Storm,相信更多的不留名的公司也在使用。这些公司中不乏淘宝,百度,Twitter,Groupon,雅虎等重量级公司。
    • 从开源时候的0.5.0版本,到现在的0.8.0+,和即将到来的0.9.0+。先后添加了以下重大的新特性:
      • 使用kryo作为Tuple序列化的框架(0.6.0)
      • 添加了Transactional topologies(事务性拓扑)的支持(0.7.0)
      • 添加了Trident的支持(0.8.0)
      • 引入netty作为底层消息机制(0.9.0)

    Transactional topologies和Trident都是针对实际应用中遇到的重复计数问题和应用性问题的解决方案。可以看出,实际的商用给予了Storm很多良好的反馈。

    • 在GitHub上超过4000个项目负责人。Storm集成了许多库,支持包括Kestrel、Kafka、JMS、Cassandra、Memcached以及更多系统。随着支持的库越来越多,Storm更容易与现有的系统协作。Storm的拥有一个活跃的社区和一群热心的贡献者。过去两年,Storm的发展是成功的。

    当 前

    Storm被广泛应用于实时分析,在线机器学习,持续计算、分布式远程调用等领域。来看一些实际的应用:

    • 一淘-实时分析系统pora:实时分析用户的属性,并反馈给搜索引擎。最初,用户属性分析是通过每天在云梯上定时运行的MR job来完成的。为了满足实时性的要求,希望能够实时分析用户的行为日志,将最新的用户属性反馈给搜索引擎,能够为用户展现最贴近其当前需求的结果。
    • 携程-网站性能监控:实时分析系统监控携程网的网站性能。利用HTML5提供的performance标准获得可用的指标,并记录日志。Storm集群实时分析日志和入库。使用DRPC聚合成报表,通过历史数据对比等判断规则,触发预警事件。

      如果,业务场景中需要低延迟的响应,希望在秒级或者毫秒级完成分析、并得到响应,而且希望能够随着数据量的增大而拓展。那就可以考虑下,使用Storm了。

    • 试想下,如果,一个游戏新版本上线,有一个实时分析系统,收集游戏中的数据,运营或者开发者可以在上线后几秒钟得到持续不断更新的游戏监控报告和分析结果,然后马上针对游戏的参数和平衡性进行调整。这样就能够大大缩短游戏迭代周期,加强游戏的生命力(实际上,zynga就是这么干的!虽然使用的不是Storm……Zynga研发之道探秘:用数据说话)。
    • 除了低延迟,Storm的Topology灵活的编程方式分布式协调也会给我们带来方便。用户属性分析的项目,需要处理大量的数据。使用传统的MapReduce处理是个不错的选择。但是,处理过程中有个步骤需要根据分析结果,采集网页上的数据进行下一步的处理。这对于MapReduce来说就不太适用了。但是,Storm的Topology就能完美解决这个问题。基于这个问题,我们可以画出这样一个Storm的Topology的处理图。

     

    我们只需要实现每个分析的过程,而Storm帮我们把消息的传送和接受都完成了。更加激动人心的是,你只需要增加某个Bolt的并行度就能够解决掉某个结点上的性能瓶颈。

    未 来

    在流式处理领域里,Storm的直接对手是S4。不过,S4冷淡的社区、半成品的代码,在实际商用方面输给Storm不止一条街。

    如果把范围扩大到实时处理,Storm就一点都不寂寞了。

    • Puma:Facebook使用puma和Hbase相结合来处理实时数据,使批处理 计算平台具备一定实时能力。 不过这不算是一个开源的产品。只是内部使用。
    • HStreaming:尝试为Hadoop环境添加一个实时的组件HStreaming能让一个Hadoop平台在几天内转为一个实时系统。分商业版和免费版。也许HStreaming可以借Hadoop的东风,撼动Storm。
    • Spark Streaming:作为UC Berkeley云计算software stack的一部分,Spark Streaming是建立在Spark上的应用框架,利用Spark的底层框架作为其执行基础,并在其上构建了DStream的行为抽象。利用DStream所提供的api,用户可以在数据流上实时进行count,join,aggregate等操作。

    当然,Storm也有Yarn-Storm项目,能让Storm运行在Hadoop2.0的Yarn框架上,可以让Hadoop的MapReduce和Storm共享资源。

    总 结

    知乎上有一个挺好的问答: 问:实时处理系统(类似s4, storm)对比直接用MQ来做好处在哪里?  答:好处是它帮你做了: 1) 集群控制。2) 任务分配。3) 任务分发 4) 监控 等等。

    需要知道Storm不是一个完整的解决方案。使用Storm你需要加入消息队列做数据入口,考虑如何在流中保存状态,考虑怎样将大问题用分布式去解决。解决这些问题的成本可能比增加一个服务器的成本还高。但是,一旦下定决定使用了Storm并解决了那些恼人的细节,你就能享受到Storm给你带来的简单,可拓展等优势了。

    技术的发展日新月异,数据处理领域越来越多优秀的开源产品。Storm的过去是成功的,将来会如何发展,我们拭目以待吧。

    Storm概念讲解和工作原理介绍


    您的评价:
         
    5.0
    收藏     6收藏

    Strom的结构

    Storm概念讲解和工作原理介绍 

    Storm与传统关系型数据库 
        传统关系型数据库是先存后计算,而storm则是先算后存,甚至不存 
        传统关系型数据库很难部署实时计算,只能部署定时任务统计分析窗口数据 
        关系型数据库重视事务,并发控制,相对来说Storm比较简陋 
        Storm不Hadoop,Spark等是流行的大数据方案 

    与Storm关系密切的语言:核心代码用clojure书写,实用程序用python开发,使用java开发拓扑 

    topology

        Storm集群中有两种节点,一种是控制节点(Nimbus节点),另一种是工作节点(Supervisor节点)。所有Topology任务的 提交必须在Storm客户端节点上进行(需要配置 storm.yaml文件),由Nimbus节点分配给其他Supervisor节点进行处理。 Nimbus节点首先将提交的Topology进行分片,分成一个个的Task,并将Task和Supervisor相关的信息提交到 zookeeper集群上,Supervisor会去zookeeper集群上认领自己的Task,通知自己的Worker进程进行Task的处理。 

        和同样是计算框架的MapReduce相比,MapReduce集群上运行的是Job,而Storm集群上运行的是Topology。但是Job在运行结束之后会自行结束,Topology却只能被手动的kill掉,否则会一直运行下去 

        Storm不处理计算结果的保存,这是应用代码需要负责的事情,如果数据不大,你可以简单地保存在内存里,也可以每次都更新数据库,也可以采用NoSQL存储。这部分事情完全交给用户。 

        数据存储之后的展现,也是你需要自己处理的,storm UI 只提供对topology的监控和统计。 

        总体的Topology处理流程图为: 
    Storm概念讲解和工作原理介绍 

    zookeeper集群

        storm使用zookeeper来协调整个集群, 但是要注意的是storm并不用zookeeper来传递消息。所以zookeeper上的负载是非常低的,单个节点的zookeeper在大多数情况下 都已经足够了, 但是如果你要部署大一点的storm集群, 那么你需要的zookeeper也要大一点。关于如何部署zookeeper,可以看http://zookeeper.apache.org/doc /r3.3.3/zookeeperAdmin.html 

        部署zookeeper有些需要注意的地方: 
        1、对zookeeper做好监控非常重要, zookeeper是fail-fast的系统,只要出现什么错误就会退出, 所以实际场景中要监控,更多细节看http://zookeeper.apache.org/doc/r3.3.3 /zookeeperAdmin.html#sc_supervision 
        2、实际场景中要配置一个cron job来压缩zookeeper的数据和业务日志。zookeeper自己是不会去压缩这些的,所以你如果不设置一个cron job, 那么你很快就会发现磁盘不够用了,更多细节可以查看http://zookeeper.apache.org/doc/r3.3.3 /zookeeperAdmin.html#sc_maintenance 

    Component

        Storm中,Spout和Bolt都是Component。所以,Storm定义了一个名叫IComponent的总接口 
        全家普如下:绿色部分是我们最常用、比较简单的部分。红色部分是与事务相关的 
    Storm概念讲解和工作原理介绍

    Spout

        Spout是Stream的消息产生源, Spout组件的实现可以通过继承BaseRichSpout类或者其他Spout类来完成,也可以通过实现IRichSpout接口来实现 
    public interface ISpout extends Serializable { 
      void open(Map conf, TopologyContext context, SpoutOutputCollector collector); 
      void close(); 
      void nextTuple(); 
      void ack(Object msgId); 
      void fail(Object msgId); 

        open()方法 -- 初始化方法 
        close() -- 在该spout将要关闭时调用。但是不保证其一定被调用,因为在集群中supervisor节点,可以使用kill -9来杀死worker进程。只有当Storm是在本地模式下运行,如果是发送停止命令,可以保证close的执行 
        ack(Object msgId) -- 成功处理tuple时回调的方法,通常情况下,此方法的实现是将消息队列中的消息移除,防止消息重放 
        fail(Object msgId) -- 处理tuple失败时回调的方法,通常情况下,此方法的实现是将消息放回消息队列中然后在稍后时间里重放 
        nextTuple() -- 这是Spout类中最重要的一个方法。发射一个Tuple到Topology都是通过这个方法来实现的。调用此方法时,storm向spout发出请求, 让spout发出元组(tuple)到输出器(ouput collector)。这种方法应该是非阻塞的,所以spout如果没有元组发出,这个方法应该返回。nextTuple、ack 和fail 都在spout任务的同一个线程中被循环调用。 当没有元组的发射时,应该让nextTuple睡眠一个很短的时间(如一毫秒),以免浪费太多的CPU。 
    继承了BaseRichSpout后,不用实现close、 activate、 deactivate、 ack、 fail 和 getComponentConfiguration 方法,只关心最基本核心的部分。 
    通常情况下(Shell和事务型的除外),实现一个Spout,可以直接实现接口IRichSpout,如果不想写多余的代码,可以直接继承BaseRichSpout 

    Bolt

        Bolt类接收由Spout或者其他上游Bolt类发来的Tuple,对其进行处理。Bolt组件的实现可以通过继承BasicRichBolt类或者IRichBolt接口等来完成 
        prepare方法 -- 此方法和Spout中的open方法类似,在集群中一个worker中的task初始化时调用。 它提供了bolt执行的环境 
        declareOutputFields方法 -- 用于声明当前Bolt发送的Tuple中包含的字段(field),和Spout中类似 
        cleanup方法 -- 同ISpout的close方法,在关闭前调用。同样不保证其一定执行。 
        execute方法 -- 这是Bolt中最关键的一个方法,对于Tuple的处理都可以放到此方法中进行。具体的发送是通过emit方法来完成的。execute接受一个 tuple进行处理,并用prepare方法传入的OutputCollector的ack方法(表示成功)或fail(表示失败)来反馈处理结果。 
        Storm提供了IBasicBolt接口,其目的就是实现该接口的Bolt不用在代码中提供反馈结果了,Storm内部会自动反馈成功。如果你确实要反馈失败,可以抛出FailedException 
        通常情况下,实现一个Bolt,可以实现IRichBolt接口或继承BaseRichBolt,如果不想自己处理结果反馈,可以实现 IBasicBolt接口或继承BaseBasicBolt,它实际上相当于自动实现了collector.emit.ack(inputTuple) 

    Topology运行流程

        (1)Storm提交后,会把代码首先存放到Nimbus节点的inbox目录下,之后,会把当前Storm运行的配置生成一个 stormconf.ser文件放到Nimbus节点的stormdist目录中,在此目录中同时还有序列化之后的Topology代码文件 
        (2) 在设定Topology所关联的Spouts和Bolts时,可以同时设置当前Spout和Bolt的executor数目和task数目,默认情况下, 一个Topology的task的总和是和executor的总和一致的。之后,系统根据worker的数目,尽量平均的分配这些task的执行。 worker在哪个supervisor节点上运行是由storm本身决定的 
        (3)任务分配好之后,Nimbus节点会将任务的信息提交到zookeeper集群,同时在zookeeper集群中会有workerbeats节点,这里存储了当前Topology的所有worker进程的心跳信息 
        (4)Supervisor 节点会不断的轮询zookeeper集群,在zookeeper的assignments节点中保存了所有Topology的任务分配信息、代码存储目 录、任务之间的关联关系等,Supervisor通过轮询此节点的内容,来领取自己的任务,启动worker进程运行 
        (5)一个Topology运行之后,就会不断的通过Spouts来发送Stream流,通过Bolts来不断的处理接收到的Stream流,Stream流是无界的。 
        最后一步会不间断的执行,除非手动结束Topology。 

    Topology运行方式

        在开始创建项目之前,了解Storm的操作模式(operation modes)是很重要的。 Storm有两种运行方式 
        本地运行的提交方式,例: 
    LocalCluster cluster = new LocalCluster(); 
    cluster.submitTopology(TOPOLOGY_NAME, conf, builder.createTopology()); 
    Thread.sleep(2000); 
    cluster.shutdown(); 
        分布式提交方式,例: 
    StormSubmitter.submitTopology(TOPOLOGY_NAME, conf, builder.createTopology()); 
      
        需要注意的是,在Storm代码编写完成之后,需要打包成jar包放到Nimbus中运行,打包的时候,不需要把依赖的jar都打迚去,否则如果把依赖的 storm.jar包打进去的话,运行时会出现重复的配置文件错误导致Topology无法运行。因为Topology运行之前,会加载本地的 storm.yaml 配置文件。 

        运行的命令如下: storm jar StormTopology.jar mainclass [args] 

    storm守护进程的命令

        Nimbus: storm nimbus 启动nimbus守护进程 
        Supervisor: storm supervisor 启动supervisor守护迚程 
        UI:storm ui 这将启动stormUI的守护进程,为监测storm集群提供一个基于web的用户界面。 
        DRPC: storm drpc 启动DRPC的守护进程 

    storm管理命令

        JAR:storm jar topology_jar topology_class [arguments...] 
        jar命令是用于提交一个集群拓扑.它运行指定参数的topology_class中的main()方法,上传topology_jar到nimbus, 由nimbus发布到集群中。一旦提交,storm将激活拓扑并开始处理topology_class 中的main()方法,main()方法负责调用StormSubmitter.submitTopology()方法,并提供一个唯一的拓扑(集群)的 名。如果一个拥有该名称的拓扑已经存在于集群中,jar命令将会失败。常见的做法是在使用命令行参数来指定拓扑名称,以便拓扑在提交的时候被命名。 

        KILL:storm kill topology_name [-w wait_time] 
        杀死一个拓扑,可以使用kill命令。它会以一种安全的方式销毁一个拓扑,首先停用拓扑,在等待拓扑消息的时间段内允许拓扑完成当前的数据流。执行 kill命令时可以通过-w [等待秒数]指定拓扑停用以后的等待时间。也可以在Storm UI 界面上实现同样的功能 

        Deactivate:storm deactivate topology_name 
        停用拓扑时,所有已分发的元组都会得到处理,spouts的nextTuple方法将不会被调用。也可以在Storm UI 界面上实现同样的功能 

        Activate:storm activate topology_name 
        启动一个停用的拓扑。也可以在Storm UI 界面上实现同样的功能 

        Rebalance:storm rebalance topology_name [-w wait_time] [-n worker_count] [-e component_name=executer_count]... 
        rebalance使你重新分配集群任务。这是个很强大的命令。比如,你向一个运行中的集群增加了节点。rebalance命令将会停用拓扑,然后在相应超时时间之后重分配worker,并重启拓扑 
    例:storm rebalance wordcount-topology -w 15 -n 5 -e sentence-spout=4 -e split-bolt=8 

        还有其他管理命令,如:Remoteconfvalue、REPL、Classpath等 

    新建storm项目注意事项

        为了开发storm项目,你的classpath里面需要有storm的jar包。最推荐的方式是使用Maven,不使用maven的话你可以手动把storm发行版里面的所有的jar包添加到classpath 

        storm-starter项目使用Leiningen作为build和依赖管理工具,你可以下载这个脚本 (https://raw.githubusercontent.com/technomancy/leiningen/stable/bin /lein)来安装Leiningen, 把它加入到你的PATH, 使它可执行。要拉取storm的所有依赖包,简单地在项目的根目录执行 lein deps 就可以了