-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 8.43 KB
/
Copy pathcontent.json
File metadata and controls
1 lines (1 loc) · 8.43 KB
1
{"meta":{"title":"鸡先生的个人主站","subtitle":"一位愿意为开源共享做出贡献的研发","description":"大数据 开源 Spark Storm Hadoop ElasticSearch MongoDB Kafka RocketMQ","author":"Liu Xi","url":"http://www.farlove.cn"},"pages":[],"posts":[{"title":"Spark Streaming流式实时计算项目","slug":"Spark-Streaming流式实时计算项目","date":"2018-02-19T16:16:40.000Z","updated":"2018-02-19T16:17:56.258Z","comments":true,"path":"2018/02/20/Spark-Streaming流式实时计算项目/","link":"","permalink":"http://www.farlove.cn/2018/02/20/Spark-Streaming流式实时计算项目/","excerpt":"","text":"Spark Streaming 流式实时计算项目0. 写在开头这篇文章主要面向的群体是对流式计算有过了解,特别是Storm和Spark Streaming之类的流式计算引擎有过demo的同学们,下文希望可以结合真实生产过程的实例,来帮助快速变现真实的企业内部需求,对于相关的Api解释和更多的原理阐述并不作为核心,因此阅读Spark Streaming Programming Guide将会对以下内容更快理解中文帮助手册地址 1. 案例需求每秒钟统计过去两小时内的用户操作数 例,每一秒钟,去计算过去1小时59分钟59秒内(再加上当前这1秒,共2小时)的所有用户的点击事件这里的几个参数,1.每秒 2. 过去的2小时 3. 所有用户 分析思路:利用Streaming,滑动时间1秒(批处理时间1秒),窗口时间2小时(7200秒),流式的统计该窗口时间内的数据 这里会遇到几个难点1)每1秒钟,这个频率相对非常高频,对于超大体量的数据,每秒钟让Spark去创建Schedule->stage->task->执行,Spark本身分配任务和潜在的GC将会很大概率成为瓶颈2)过去2小时,这里的窗口时间区间是7200倍的滑动时间,当1秒内的数据体量(rdd占用的内存量稍大时),Spark就会缓存极大体量的数据在缓存内,毕竟7200的系数,非常夸张了,此时,将滑动时间从1秒变为数秒将会是一个非常不错的提升性能的尝试,这里会有人提出,可以将数据缓存至磁盘(StorageLevel.MEMORY_AND_DISK_SER_2,修改StorageLevel),的确是个很好的方式,但是在高频(5~10秒内的批处理时间)内,会发现,磁盘的IO会成为明显的流处理瓶颈,性能会有非常明显的下降3)汇总完的全部数据是需要一个地方做存放,最终提供数据查询接口或者其他应用,那么这里的存放引擎会面临2小时的全量数据的变更处理任何一笔在窗口时间内出现的数据都必须经过计算,那么如何解决全量的统计结果增量的写入结果引擎也会是一个需要开发者去思考的问题 2. 解决方案设计1) 面对比较短的滑动时间,需要更多的启动核数spark.default.parallelism - 数据处理并行度,该参数配置时,需要非常谨慎,Spark官网建议的设置原则是,设置该参数为num-executors executor-cores的2~3倍较为合适,通俗点,就是当你为你的App分配了10个core,那么可以将该参数设置为20~30*spark.streaming.concurrentJobs - Job的并行度,该参数需要谨慎设置,过高的并行数可能会造成很多不可预见的问题,该解决方案中设置为了4。最初设置成了20,造成了checkpoint rdd存在读取时,已经被删除的现象,其实就是由于同时执行的job数过多,当发生job堵塞,就可能会造成rdd读取被删除的场景,这个问题当时也被困扰许久 2) 为了解决每秒都需要计算全部2小时的数据,那么就要考虑常规的reduceByKeyAndWindow(按照key和窗口汇总的算子)是否可以有优化的场景了下面就列举一个简单的说明,来表示全量统计和增量统计的区别 每秒统计过去7200秒的数据 rdd...reduceByKeyAndWindow((a, b) -> a + b, Seconds.apply(7200), Seconds.apply(1)) 每秒统计该秒的数据和过去第-7201秒的数据 rdd...reduceByKeyAndWindow((a, b) -> a + b, (a, b) -> a - b, Seconds.apply(7200), Seconds.apply(1), parallelism, (Function<Tuple2<String, Integer>, Boolean>) f -> f._2 != 0 ); 上面的方式极大的优化了每次的计算所需要扫描的内存数据,窗口时间与滑动时间比例越大,效果越明显下面的图例可以更好的帮助理解 3) 纵使我们提升了每次计算的性能,Spark依然会在reduceByKeyAndWindow之后为我们把所有的发生数据变更的Key(这里是操作用户)都返回给后续的foreach等操作中,当数据体量不大时,并不存在什么问题,但当window窗口和每批次的变更数据体量,或者说是,当你这2小时内,会有几十万几百万(7200*100=720000了,T_T…)甚至更多的不同key结果时,那么问题就来了,每秒都会有如何庞大的数据量需要被记录,什么样的引擎能承载这么庞大变更(请注意,这里是变更数据)的数据集呢。其实,思路与reduce的增量思想如出一辙,那就是只落入变更数据到结果集库,那么变更量其实也就是两秒的数据变更量了Spark streaming提供了有状态的计算方式(updateStateByKey和mapWithState,后者需要在Spark1.6中支持)其实网上已经有很多阐述俩者之间差异的文献了,如果有需要深入了解Spark底层相关实现的,推荐可以看下Spark源生是如何优化有状态计算的,这边简单背个书,大致三点:①. 较大的性能提升②. 可以为Key 设置TTL(Timeout)③. 用户可以对返回值进行控制这边附一个资料链接Spark Streaming 1.6 流式状态管理分析 这里使用mapWithState做变更判断 rdd...mapWithState(StateSpec.function((Function3<String, Optional<Integer>, State<Integer>, Tuple2<String, Integer>>) (s, optional, state) -> { int opt = optional.orElse(0); if (state.isTimingOut()) { // 这里弱不判断,timeout的rdd将会抛出 return new Tuple2<>(s, opt); } if (state.exists()) { // 已经存在的key if (opt == 0) { state.remove(); return null; } if (state.get() == opt) { // 如果值未变,返回null return null; } state.update(opt); // 变更值,并且返回 return new Tuple2<>(s, opt); } if (opt == 0) { // 统计值降为0,可以返回null return null; } state.update(opt); // 不存在的key,直接变更并返回 return new Tuple2<>(s, opt); }).timeout(Seconds.apply(2 * windowDuration))) // 这里可以将超时时间设为两倍的window时间 3. 项目目录结构 trigram-rtft(父级目录) streaming-base-properties(base目录的独立配置文件,通过依赖排除,后续项目可以自定义配置文件) streaming-base(核心项目,包括了streaming上下文的初始化、kafka和turbomq的消费抽象类等工具类) streaming-xxx(业务逻辑子项目,需要依赖base项目) 该设计旨在为解决streaming项目每次构建时,重复的开发消息消费过程、相关工具类、依赖版本管理等的重复性工作。 1)核心类说明 com.ly.trigram.base.core.AbstractStreaming该类提供了所有streaming业务子项目的抽象接口createDStreamDAG() -> init() -> getInputDStream() com.ly.trigram.base.core.AbstractStreamingKafka该类提供了Kafka作为输入DStream的实现com.ly.trigram.base.core.AbstractStreamingTurboMq该类提供了TurboMq作为输入DStream的实现 com.ly.trigram.service.AbstractStreamingKafkaService该类提供了对应的Streaming处理流程","categories":[{"name":"Spark Streaming","slug":"Spark-Streaming","permalink":"http://www.farlove.cn/categories/Spark-Streaming/"}],"tags":[{"name":"大数据","slug":"大数据","permalink":"http://www.farlove.cn/tags/大数据/"},{"name":"Spark Streaming","slug":"Spark-Streaming","permalink":"http://www.farlove.cn/tags/Spark-Streaming/"}]},{"title":"Hello World","slug":"hello-world","date":"2018-01-29T01:52:14.136Z","updated":"2018-01-29T01:52:14.136Z","comments":true,"path":"2018/01/29/hello-world/","link":"","permalink":"http://www.farlove.cn/2018/01/29/hello-world/","excerpt":"","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","categories":[],"tags":[]}]}