sparkSQL中cache的若干问题

摘要

sparkSQL在使用cache缓存的时候,有时候缓存可能不起作用,可能会发出缓存是假的吧的感慨。现在我们就把这个问题说道说道。
问题

场景描述

当我们通过spark进行统计和处理数据时,发现他是延迟计算的,如果一个应用中出现多个action,而这多个action处理同一个数据源数据时,数据源用时间来过滤数据时,由于有多个action操作,遇到每个action就是一个job,每一个action都会执行数据源获取数据的操作,由于两个action之间的操作存在时间差,这两个action获取的数据有可能不一致。
例如下例
test1表中的数据

1,2018-07-01 10:10:03
2,2018-07-01 11:12:04

代码如下操作

val odsData = spark.sql("""
select
from default.test1
where time < "2018-07-02"
""")
val targetData = odsData.map(fun _)
val targetData.createOrReplaceTempView("data1")
//第一个Action操作
val spark.sql("""
insert overwrite table default.test2
*
from data1
""")

val targetData1 = odsData.map(fun2 _) //引用同一个数据源
targetData1.createOrReplaceTempView("data2")
//第二个action操作
val spark.sql("""
insert table default.test2
*
from data2
""")

如果在运行第二个Action操作前,test1表中又增加了一条记录3,2018-07-01 13:12:04
即执行第一个Action时记录还是两条1和2,而再执行完第一个Action后而又执行第二个Action之前,
增加了一个新的单子:3,2018-07-01 13:12:04
那么在test2表中的数据是怎么样的呢?
第一种情况(因为第二个action是insert而不是insert overwrite)

1,2018-07-01 10:10:03
2,2018-07-01 11:12:04
1,2018-07-01 10:10:03
2,2018-07-01 11:12:04

第二种情况

1,2018-07-01 10:10:03
2,2018-07-01 11:12:04
1,2018-07-01 10:10:03
2,2018-07-01 11:12:04
3,2018-07-01 13:12:04

结果分析

结果是第二中情况。如果认为是第一种情况的对spark的执行计划还是不太熟悉。首先spark是lazy计算的,即不触发action操作,其实不提交作业的。而在这个application中存在两个action,而这两个aciton使用了同一个数据源的rdd,应该称为变量odsData,当遇到第一个action,其会把自己这个执行链上的rdd都执行一遍,包括执行odsData,而遇到第二个aciton的时候,其也会把自己的执行链上的数据又执行了一遍包括odsData,并从数据源中重新取数。有人会疑惑,第一个action在执行的时候,已经执行了odsData,这个RDD的结果不应该缓存起来吗?个人认为,spark还没有那么的智能,并且网上经常说的job,stage,rdd,task的划分应该是在同一个job内进行的。而同一个应用中夸job的stage拆分是不存在的。那么出现这个结果应该怎么办呢?
cache的出场

当出现这样的情况时,我的应用每天就会漏几十条数据,很是烦人,最后发现了上面的问题,当时想解决方案时,第一个就是想到了cache,我把第一次执行Action操作时,把odsData给缓存了,这样应该不会有什么问题了吧。从而可以保证两个action操作,同一个数据源的数据一致性。只能说too young to sample了。这样解决不了上面出现的问题。同样以一个例子来看。
test表中的数据:

1 2017-01-01 01:00:00 2016-05-04 9999-12-31
2 2017-01-01 02:00:00 2016-01-01 9999-12-31
代码:

val curentData = spark.sql(
"""
|select
|*
|from default.test
""".stripMargin)

curentData.cache() //缓存我们的结果

curentData.createOrReplaceTempView("dwData")

//第一个Action
spark.sql(
"""
|INSERT OVERWRITE TABLE default.test1
|SELECT
|
|FROM dwData
""".stripMargin)
//改变数据源表test表的数据并且是第二个Action
spark.sql(
"""
|INSERT OVERWRITE TABLE default.test
|SELECT
| 1,
| "2017",
| "2018",
| "2018"
|FROM default.test
""".stripMargin)
//第三个Action和第一个Action同数据源,并且cache第一次运行的结果。
spark.sql(
"""
|INSERT OVERWRITE TABLE default.test1
|SELECT
|

|FROM dwData
""".stripMargin)
那么test1表中的结果
第一种情况:

1 2017-01-01 01:00:00 2016-05-04 9999-12-31
2 2017-01-01 02:00:00 2016-01-01 9999-12-31
第二种情况

1 2017 2018 2018
1 2017 2018 2018
结果分析

结果是第二种情况,也就是说我们cache根本就没有起到效果,或者说第三个Action根本就没有使用我们cache的数据。这次我把日志都打出来了啊。
第一个Action的声明周期:

第三个Action的日志:

从这两个日志可以看出,我们设置cache其只能在同一个job中生效。而夸job的使用这样的数据缓存数据是不存在的。
如果想更加详细的了解cache的原理和作用,可以去网上搜,大把大把的资料,但是一定要记住,网上说的要限定一个条件,在同一个job内的rdd,夸job的cache是不存在的。
解决方案

我们最终希望解决的事,当两个action想要使用同一个数据源的rdd的时候,如何保证其数据的一致性。
方案:
把第一个Action算子用到的数据源给写入到一个临时表中
然后再第二个Action中,直接读取临时表的数据,而不是直接使用odsData
更好的方案还没有想好,可以根据业务的不同来搞。

原文地址:http://blog.51cto.com/9269309/2141043

时间: 2024-10-26 05:27:53

sparkSQL中cache的若干问题的相关文章

[z]计算机架构中Cache的原理、设计及实现

前言 虽然CPU主频的提升会带动系统性能的改善,但系统性能的提高不仅仅取决于CPU,还与系统架构.指令结构.信息在各个部件之间的传送速度及存储部件的存取速度等因素有关,特别是与CPU/内存之间的存取速度有关. 若CPU工作速度较高,但内存存取速度相对较低,则造成CPU等待,降低处理速度,浪费CPU的能力. 如500MHz的PⅢ,一次指令执行时间为2ns,与其相配的内存(SDRAM)存取时间为10ns,比前者慢5倍,CPU和PC的性能怎么发挥出来? 如何减少CPU与内存之间的速度差异?有4种办法:

jfinal-ext shiro插件中cache无用

1.在项目中使用后,发现jfinal-ext shiro插件中cache配置无用 即,不管是否配置 <cache name="myRealm.authorizationCache" maxElementsInMemory="10000" overflowToDisk="true" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="

Oracle Sequence中Cache与NoCache的区别;合适使用

Oracle在创建序列(sequence)时有个参数你可以选择cache或者nocache,下面来讲一下两者的区别: 先来看下创建sequence的语句: create sequence SEQ_ID  minvalue 1  maxvalue 99999999  start with 1  increment by 1  cache n  / nocache  --其中n代表一个整数,默认值为20order; 如果指定CACHE值,Oracle就可以预先在内存里面放置一些Sequence,这样

linux 内存中cache和buffer解析

cache是从磁盘读数据到内存中的缓存,减少读取磁盘的次数, 大家知道的硬盘读取速度过慢. buffer是准备从内存写到硬盘的缓存,缓存中的数据会进行合并 同时,避免频繁操作硬盘. linux 内存中cache和buffer解析

ASP.NET缓存中Cache过期的三种策略

原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. <asp:Button ID="btn_InsertNoExpirationCache" runat="server" Text="插入永不过期缓存"      OnClick="btn_InsertNoExpirationCache_Click" />   

C#中Cache的使用

公共方法Add 将指定项添加到 Cache 对象,该对象具有依赖项.过期和优先级策略以及一个委托(可用于在从 Cache 移除插入项时通知应用程序). Equals(从 Object 继承) 已重载.确定两个 Object 实例是否相等. Get 从 Cache 对象检索指定项. GetEnumerator 检索用于循环访问包含在缓存中的键设置及其值的字典枚举数. GetHashCode(从 Object 继承) 用作特定类型的哈希函数,适合在哈希算法和数据结构(如哈希表)中使用. GetTyp

Xcode 6 beta3 中 Swift 的若干更新(转载)

Xcode 6 beta3 对Swift 自从公布以来的第一次比较大的更新,尤其是对数组的更新,主要体现在几个方面:1.数组被重写,现在声明为 let 的数组为不可变数组,声明为var 的是可变的2.声明数组和字典的语法糖也作了修改, 原来声明数组:Int[] 改为 [Int] ,同样的, 字典声明方式变为  [Key: Value]:3.区间运算符 .. 不再使用,而用  ..< 替代,使语意更明确. Xcode 6 beta3 中 Swift 的若干更新(转载)

工作中常用的若干正则

工作中常用的若干正则 sed过滤日志中一天的日期 sed -n '/03\/Nov\/2017/p'  www.kanfanews.com_access_ssl.log grep过滤时间 cat jie.nginx.log|grep 117.73.151.80|egrep "21/Oct/2017:10:[0-9][0-9]:[0-9][0-9]" sed过滤日志中连续字符中的空格 sed -n '/28\/Oct\/2017/p'  www.kanfanews.com_access_

【缓存】.net中Cache管理操作

隐藏行号 复制代码 ? 这是一段程序代码. using System; using System.Web; using System.Web.Caching; using System.Collections; /// <summary> /// 设置Cache操作类 /// </summary> public class SetCache { #region 用户自定义变量 private static readonly Cache _cache;//缓存实例 private s