首页 文章 精选 留言 我的

精选列表

搜索[官方镜像],共10000篇文章
优秀的个人博客,低调大师

Apache Storm 官方文档 —— Trident API 概述

Trident 的核心数据模型是“流”(Stream),不过与普通的拓扑不同的是,这里的流是作为一连串batch来处理的。流是分布在集群中的不同节点上运行的,并且对流的操作也是在流的各个partition 上并行运行的。 Trident 中有 5 类操作: 针对每个小分区(partition)的本地操作,这类操作不会产生网络数据传输; 针对一个数据流的重新分区操作,这类操作不会改变数据流中的内容,但是会产生一定的网络传输; 通过网络数据传输进行的聚合操作; 针对数据流的分组操作; 融合与联结操作。 本地分区操作 本地分区操作是在每个分区块上独立运行的操作,其中不涉及网络数据传输。 函数 函数负责接收一个输入域的集合并选择输出或者不输出 tuple。输出 tuple 的域会被添加到原始数据流的输入域中。如果一个函数不输出 tuple,那么原始的输入 tuple 就会被直接过滤掉。否则,每个输出 tuple 都会复制一份输入 tuple 。假设你有下面这样的函数: public class MyFunction extends BaseFunction { public void execute(TridentTuple tuple, TridentCollector collector) { for(int i=0; i < tuple.getInteger(0); i++) { collector.emit(new Values(i)); } } } 再假设你有一个名为 “mystream” 的数据流,这个流中包含下面几个 tuple,每个 tuple 中包含有 “a”、“b”、“c” 三个域: [1, 2, 3] [4, 1, 6] [3, 0, 8] 如果你运行这段代码: mystream.each(new Fields("b"), new MyFunction(), new Fields("d"))) 那么最终输出的结果 tuple 就会包含有 “a”、“b”、“c”、“d” 4 个域,就像下面这样: [1, 2, 3, 0] [1, 2, 3, 1] [4, 1, 6, 0] 过滤器 过滤器负责判断输入的 tuple 是否需要保留。以下面的过滤器为例: public class MyFilter extends BaseFilter { public boolean isKeep(TridentTuple tuple) { return tuple.getInteger(0) == 1 && tuple.getInteger(1) == 2; } } 通过使用这段代码: mystream.each(new Fields("b", "a"), new MyFilter()) 就可以将下面这样带有 “a”、“b”、“c” 三个域的 tuple [1, 2, 3] [2, 1, 1] [2, 3, 4] 最终转化成这样的结果 tuple: [2, 1, 1] partitionAggregate partitionAggregate会在一批 tuple 的每个分区上执行一个指定的功能操作。与上面的函数不同,由partitionAggregate发送出的 tuple 会将输入 tuple 的域替换。以下面这段代码为例: mystream.partitionAggregate(new Fields("b"), new Sum(), new Fields("sum")) 假如输入流中包含有 “a”、“b” 两个域并且有以下几个 tuple 块: Partition 0: ["a", 1] ["b", 2] Partition 1: ["a", 3] ["c", 8] Partition 2: ["e", 1] ["d", 9] ["d", 10] 经过上面的代码之后,输出就会变成带有一个名为 “sum” 的域的数据流,其中的 tuple 就是这样的: Partition 0: [3] Partition 1: [11] Partition 2: [20] Storm 有三个用于定义聚合器的接口:CombinerAggregator,ReducerAggregator以及Aggregator。 这是CombinerAggregator接口: public interface CombinerAggregator<T> extends Serializable { T init(TridentTuple tuple); T combine(T val1, T val2); T zero(); } CombinerAggregator会将带有一个域的一个单独的 tuple 返回作为输出。CombinerAggregator会在每个输入 tuple 上运行初始化函数,然后使用组合函数来组合所有输入的值。如果在某个分区中没有 tuple,CombinerAggregator就会输出zero方法的结果。例如,下面是Count的实现代码: public class Count implements CombinerAggregator<Long> { public Long init(TridentTuple tuple) { return 1L; } public Long combine(Long val1, Long val2) { return val1 + val2; } public Long zero() { return 0L; } } 如果你使用 aggregate 方法来代替 partitionAggregate 方法,你就会发现CombinerAggregator的好处了。在这种情况下,Trident 会在发送 tuple 之前通过分区聚合操作来优化计算过程。 ReducerAggregator的接口实现是这样的: public interface ReducerAggregator<T> extends Serializable { T init(); T reduce(T curr, TridentTuple tuple); } ReducerAggregator会使用init方法来产生一个初始化的值,然后使用该值对每个输入 tuple 进行遍历,并最终生成并输出一个单独的 tuple,这个 tuple 中就包含有我们需要的计算结果值。例如,下面是将 Count 定义为ReducerAggregator的代码: public class Count implements ReducerAggregator<Long> { public Long init() { return 0L; } public Long reduce(Long curr, TridentTuple tuple) { return curr + 1; } } ReducerAggregator同样可以用于 persistentAggregate,你会在后面看到这一点。 最常用的聚合器接口还是下面的Aggregator接口: public interface Aggregator<T> extends Operation { T init(Object batchId, TridentCollector collector); void aggregate(T state, TridentTuple tuple, TridentCollector collector); void complete(T state, TridentCollector collector); } Aggregator聚合器可以生成任意数量的 tuple,这些 tuple 也可以带有任意数量的域。聚合器可以在执行过程中的任意一点输出tuple,他们的执行过程是这样的: 在处理一批数据之前先调用 init 方法。init 方法的返回值是一个代表着聚合状态的对象,这个对象接下来会被传入 aggregate 方法和 complete 方法中。 对于一个区块中的每个 tuple 都会调用 aggregate 方法。这个方法能够更新状态并且有选择地输出 tuple。 在区块中的所有 tuple 都被 aggregate 方法处理之后就会调用 complete 方法。 下面是使用 Count 作为聚合器的代码: public class CountAgg extends BaseAggregator<CountState> { static class CountState { long count = 0; } public CountState init(Object batchId, TridentCollector collector) { return new CountState(); } public void aggregate(CountState state, TridentTuple tuple, TridentCollector collector) { state.count+=1; } public void complete(CountState state, TridentCollector collector) { collector.emit(new Values(state.count)); } } 有时你可能会需要同时执行多个聚合操作。这个过程叫做链式处理,可以使用下面这样的代码来实现: mystream.chainedAgg() .partitionAggregate(new Count(), new Fields("count")) .partitionAggregate(new Fields("b"), new Sum(), new Fields("sum")) .chainEnd() 这段代码会在每个分区上分别执行 Count 和 Sum 聚合器,而输出中只会包含一个带有 [“count”, “sum”] 域的单独的 tuple。 stateQuery 与 partitionPersist stateQuery 与 partitionPersist 会分别查询、更新 state 数据源。你可以参考Trident State 文档来了解如何使用它们。 projection projection方法只会保留操作中指定的域。如果你有一个带有 [“a”, “b”, “c”, “d”] 域的数据流,通过执行这段代码: mystream.project(new Fields("b", "d")) 就会使得输出数据流中只包含有 [“b”, “d”] 域。 重分区操作 重分区操作会执行一个用来改变在不同的任务间分配 tuple 的方式的函数。在重分区的过程中分区的数量也可能会发生变化(例如,重分区之后的并行度就有可能会增大)。重分区会产生一定的网络数据传输。下面是重分区操作的几个函数: shuffle:通过随机轮询算法来重新分配目标区块的所有 tuple。 broadcast:每个 tuple 都会被复制到所有的目标区块中。这个函数在 DRPC 中很有用 —— 比如,你可以使用这个函数来获取每个区块数据的查询结果。 partitionBy:该函数会接收一组域作为参数,并根据这些域来进行分区操作。可以通过对这些域进行哈希化,并对目标分区的数量取模的方法来选取目标区块。partitionBy 函数能够保证来自同一组域的结果总会被发送到相同的目标区间。 global:这种方式下所有的 tuple 都会被发送到同一个目标分区中,而且数据流中的所有的块都会由这个分区处理。 batchGlobal:同一个 batch 块中的所有 tuple 会被发送到同一个区块中。当然,在数据流中的不同区块仍然会分配到不同的区块中。 partition:这个函数使用自定义的分区方法,该方法会实现backtype.storm.grouping.CustomStreamGrouping接口。 聚类操作 Trident 使用 aggregate 方法和 persistentAggregate 方法来对数据流进行聚类操作。其中,aggregate 方法会分别对数据流中的每个 batch 进行处理,而 persistentAggregate 方法则会对数据流中的所有 batch 执行聚类处理,并将结果存入某个 state 中。 在数据流上执行 aggregate 方法会执行一个全局的聚类操作。在你使用ReducerAggregator或者Aggregator时,数据流首先会被重新分区成一个单独的分区,然后聚类函数就会在该分区上执行操作。而在你使用CombinerAggregator时,Trident 首先会计算每个分区的部分聚类结果,然后将这些结果重分区到一个单独的分区中,最后在网络数据传输完成之后结束这个聚类过程。CombinerAggregator比其他的聚合器的运行效率更高,在聚类时应该尽可能使用CombinerAggregator。 下面是一个使用 aggregate 来获取一个 batch 的全局计数值的例子: mystream.aggregate(new Count(), new Fields("count")) 与 partitionAggregate 一样,aggregate 的聚合器也可以进行链式处理。然而,如果你在一个处理链中同时使用了CombinerAggregator和非CombinerAggregator,Trident 就不能对部分聚类操作进行优化了。 想要了解更多使用 persistentAggregate 的方法,可以参考Trident State 文档一文。 对分组数据流的操作 通过对指定的域执行 partitionBy 操作,groupBy 操作可以将数据流进行重分区,使得相同的域的 tuple 分组可以聚集在一起。例如,下面是一个 groupBy 操作的示例: 如果你在分组数据流上执行聚合操作,聚合器会在每个分组(而不是整个区块)上运行。persistentAggregate 同样可以在一个分组数据里上运行,这种情况下聚合结果会存储在MapState中,其中的 key 就是分组的域名。 和其他操作一样,对分组数据流的聚合操作也可以以链式的方式执行。 融合(Merge)与联结(join) Trident API 的最后一部分是联结不同的数据流的操作。联结数据流最简单的方式就是将所有的数据流融合到一个流中。你可以使用 TridentTopology 的 merge 方法实现该操作,比如这样: topology.merge(stream1, stream2, stream3); Trident 会将融合后的新数据流的域命名为为第一个数据流的输出域。 联结数据流的另外一种方法是使用 join。像 SQL 那样的标准 join 操作只能用于有限的输入数据集,对于无限的数据集就没有用武之地了。Trident 中的 join 只会应用于每个从 spout 中输出的小 batch。 下面是两个流的 join 操作的示例,其中一个流含有 [“key”, “val1″, “val2″] 域,另外一个流含有 [“x”, “val1″] 域: topology.join(stream1, new Fields("key"), stream2, new Fields("x"), new Fields("key", "a", "b", "c")); 上面的例子会使用 “key” 和 “x” 作为 join 的域来联结 stream1 和 stream2。Trident 要求先定义好新流的输出域,因为输入流的域可能会覆盖新流的域名。从 join 中输出的 tuple 中会包含: join 域的列表。在这个例子里,输出的 “key” 域与 stream1 的 “key” 域以及 stream2 的 “x” 域对应。 来自所有流的非 join 域的列表。这个列表是按照传入 join 方法的流的顺序排列的。在这个例子里,“ a” 和 “b” 域与 stream1 的 “val1” 和 “val2” 域对应;而 “c” 域则与 stream2 的 “val1” 域相对应。 在对不同的 spout 发送出的流进行 join 时,这些 spout 上会按照他们发送 batch 的方式进行同步处理。也就是说,一个处理中的 batch 中含有每个 spout 发送出的 tuple。 到这里你大概仍然会对如何进行窗口 join 操作感到困惑。窗口操作(包括平滑窗口、滚动窗口等 —— 译者注)主要是指将当前的 tuple 与过去若干小时时间段内的 tuple 联结起来的过程。 你可以使用 partitionPersist 和 stateQuery 来实现这个过程。过去一段时间内的 tuple 会以 join 域为关键字被保存到一个 state 源中。然后就可以使用 stateQuery 查询 join 域来实现这个“联结”(join)的过程。 转载自并发编程网 - ifeve.com

优秀的个人博客,低调大师

《Spark 官方文档》Spark安全性

Spark安全性 Spark目前已经支持以共享秘钥的方式进行身份认证。开启身份认证配置参数为 spark.authenticate 。这个配置参数决定了Spark通讯协议是否使用共享秘钥做身份验证。验证过程就是一个基本的握手过程,确保通讯双方都有相同的秘钥并且可以互相通信。如果共享秘钥不同,双方是不允许通信的。共享秘钥可用以下方式创建: 对于以YARN方式部署的Spark,将 spark.authenticate 设为true可以自动生成并分发共享秘钥。每个Spark应用会使用唯一的共享秘钥。 而对于其他部署类型,需要在每个节点上设置 spark.authenticate.secret 参数。这个秘钥将会在由所有 Master/Workers以及各个Spark应用共享。 Web UI Spark UI 也可以通过配置 spark.ui.filters 来使用javax servlet filters确保安全性,因为某些用户可能希望web UI上的某些数据应该保密,并对其他用户不可见。用户可以自定义 javax servlet filter 来对登陆用户进行认证,Spark会根据用户的ACL(访问控制列表)来确保该登陆用户有权限访问某个Spark应用的web UI。Spark ACL的行为可由 spark.acls.enable 和 spark.ui.view.acls共同控制。注意,启动Spark应用的用户总是会有权限访问该应用对应的UI。而在YARN模式下,Spark web UI会使用YARN的web应用代理机制,通过Hadoop过滤器进行认证。 Spark还支持修改运行中的Spark应用对应的ACL以便更改其权限控制,不过这可能会导致杀死应用或者杀死任务的动作。这一特性由 spark.acls.enable 和 spark.modify.acls 共同控制。注意,如果你需要web UI的认证,比如为了能够在web UI上使用杀死应用的按钮,那么就需要将用户同时添加到modify ACL和view ACL中。在YARN上,控制用户修改权限的modify ACL是通过YARN接口传进来的。 Spark可以允许多个管理员共同管理ACL,而且这些管理员总是能够访问和修改所有的Spark应用。而管理员本身是由 spark.admin.acls 配置的。在一个共享的多用户集群中,你可能需要配置多个管理员,另外,该配置也可以用于支持开发人员调试Spark应用。 事件日志 如果你启用了事件日志(event logging),那么这些日志对应的目录(spark.eventLog.dir)需要事先手动创建并设置好权限。如果你要限制这些日志文件的权限,首先还是要将日志目录的权限设为 drwxrwxrwxt,目录owner应该是启动history server的超级用户,对应的组限制为该超级用户所在组。这样其他所有用户就只能往该目录下写日志,但同时又不能删除或改名。事件日志文件只有在用户或者用户组具有读写权限时才能写入。 加密 Spark对Akka和HTTP协议(广播和文件服务器中使用)支持SSL。同时,对数据块传输服务(block transfer service)支持SASL加密。Spark web UI暂时还不支持任何加密。 Spark的临时数据存储,如:混洗中间文件、缓存数据或其他应用相关的临时文件,目前也没有加密。如果需要加密这些数据,只能通过配置集群管理器将数据存储到加密磁盘上。 SSL配置 Spark SSL相关配置是层级式的。用户可以配置SSL的默认配置,以便支持所有的相关通讯协议,当然,如果设置了针对某个具体协议配置值,其值将会覆盖默认配置对应的值。这种方式主要是为了方便用户,用户可以轻松地为所有协议都配置好默认值,同时又不会影响针对某一个具体协议的特殊配置需求。通用的SSL默认配置在 spark.ssl 这一配置命名空间下,对于Akka的SSL配置,在spark.ssl.akka下,而对用于广播和文件服务器中的HTTP协议,其配置在 spark.ssl.fs 下。详细的清单见配置指南(configuration page)。 SSL必须在每个节点上都配置好,并且包括各个使用特定通讯协议的相关模块。 YARN模式 key-store 文件可以由客户端准备好,然后作为Spark应用的一部分分发到各个执行器(executor)上使用。用户也可以在Spark应用启动前,通过配置 spark.yarn.dist.files 或者 spark.yarn.dist.archives 来部署key-store文件。这些文件传输过程的加密是由YARN本身负责的,和Spark就没什么关系了。 对于一些长期运行并且可以写HDFS的Spark应用,如:Spark Streaming 上的应用,可以用 spark-submit 的 –principal 和 –keytab 参数分别设置principal 和 keytab 信息。keytab文件将会通过 Hadoop Distributed Cache(如果YARN配置了 SSL并且HDFS启用了加密,那么分布式缓存的传输也会被加密) 复制到Application Master所在机器上。Kerberos的登陆信息将会被principal和keytab周期性地刷新,同时HDFS所需的代理token也会被周期性的刷新,这样Spark应用就能持续地写入HDFS了。 独立模式 独立模式下,用户需要为master和worker分别提供key-store和相关配置选项。这些配置可以通过在SPARK_MASTER_OPTS 和 SPARK_WORKER_OPTS,或者 SPARK_DEAMON_JAVA_OPTS环境变量中添加相应的java系统属性来设置。独立模式下,用户可以通过worker的SSL设置来改变执行器(executor)的配置,因为这些执行器进程都是worker的子进程。不过需要注意的是,执行器如果需要启用本地SSL配置值(如:从worker进程继承而来的环境变量),而不是用户在客户端设置的值,就需要将 spark.ssl.userNodeLocalConf 设为 true。 准备key-stores key-stores 文件可以由 keytool 程序生成。keytool 相关参考文档见这里:here。独立模式下,配置key-store和trust-store至少有这么几个基本步骤: 为每个节点生成一个秘钥对 导出各节点秘钥对中的公匙(public key)到一个文件 将所有这些公匙导入到一个 trust-store 文件中 将该trust-store文件发布到所有节点 配置SASL加密 启用认证后(spark.authenticate),数据块传输服务(block transfer service)可以支持SASL加密。如需启用SASL加密的话,还需要在 Spark 应用中设置 spark.authenticate.enableSaslEncryption 为 true。 如果是开启了外部混洗服务(external shuffle service),那么只需要将 spark.network.sasl.serverAlwaysEncrypt 设为true即可禁止非加密的网络连接。因为这个配置一旦启用,所有未使用 SASL加密的Spark应用都无法连接到外部混洗服务上。 配置网络安全端口 Spark计算过程中大量使用网络通信,而有些环境中对网络防火墙的设置要求很严格。下表列出来Spark用于通讯的一些主要端口,以及如何配置这些端口。 仅独立部署适用 访问源 访问目标 默认值 用途 配置 注意 Browser Standalone Master 8080 Web UI spark.master.ui.port / SPARK_MASTER_WEBUI_PORT 基于Jetty。仅独立模式有效。 Browser Standalone Worker 8081 Web UI spark.worker.ui.port / SPARK_WORKER_WEBUI_PORT 基于Jetty。仅独立模式有效。 Driver / Standalone Worker Standalone Master 7077 提交作业 / 合并集群 SPARK_MASTER_PORT 基于Akka。设为0表示随机。仅独立模式有效。 Standalone Master Standalone Worker (random) 调度执行器 SPARK_WORKER_PORT 基于Akka。设为0表示随机。仅独立模式有效。 所有集群管理器适用 访问源 访问目标 默认值 用途 配置 注意 Browser Application 4040 Web UI spark.ui.port 基于Jetty Browser History Server 18080 Web UI spark.history.ui.port 基于Jetty Executor / Standalone Master Driver (random) 连接Spark应用 / 执行器状态变化通知 spark.driver.port 基于Akka。设为0表示随机。 Driver Executor (random) 任务调度 spark.executor.port 基于Akka。设为0表示随机。 Executor Driver (random) 传输文件和jar包的文件服务器 spark.fileserver.port 基于Jetty Executor Driver (random) HTTP广播 spark.broadcast.port 基于Jetty。TorrentBroadcast通过block manager发送数据,所以不会用这个端口。 Executor Driver (random) 类文件服务器 spark.replClassServer.port 基于Jetty。仅Spark shell使用。 Executor / Driver Executor / Driver (random) 数据块管理器端口 spark.blockManager.port 基于ServerSocketChannel使用原始socket通信。 转载自并发编程网 - ifeve.com

优秀的个人博客,低调大师

GitHub 官方发布的编程语言趋势

【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 最近,我们统计了各编程语言在Github.com上近些年的活跃度。 下图清晰地展示出,自2008年Github创建以来,各编程语言的排名发生了不少变化。 图中引用的语言包括了在公共和私人的repository中所使用的编程语言(fork过来的除外),而语言的排名则由Linguist检测得出。 须注意,本图表所展现的各语言在GitHub上的活跃度是相对的。例如,Ruby on Rails自2008年出现在GitHub上,因此它在早期阶段具有相对较高的活跃度。 在2008和2015年之间,GitHub上活跃度变化***的是Java,它从第七名一直升到第二名。究其原因,可能是安卓设备兴起和企业对于版本控制平台需求增加。 【责任编辑: chenqingxiang TEL:(010)68476606】

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册