We use Redis on Spark to cache our key-value pairs.This is the code:

import com.redis.RedisClient
val r = new RedisClient("192.168.1.101", 6379)
val perhit = perhitFile.map(x => {
val arr = x.split(" ")
val readId = arr(0).toInt
val refId = arr(1).toInt
val start = arr(2).toInt
val end = arr(3).toInt
val refStr = r.hmget("refStr", refId).get(refId).split(",")(1)
val readStr = r.hmget("readStr", readId).get(readId)
val realend = if(end > refStr.length - 1) refStr.length - 1 else end
val refOneStr = refStr.substring(start, realend)
(readStr, refOneStr, refId, start, realend, readId)
})

But compiler gave me feedback like this:

Exception in thread "main" org.apache.spark.SparkException: Task not serializable
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:166)
at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:158)
at org.apache.spark.SparkContext.clean(SparkContext.scala:1242)
at org.apache.spark.rdd.RDD.map(RDD.scala:270)
at com.ynu.App$.main(App.scala:511)
at com.ynu.App.main(App.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.spark.deploy.SparkSubmit$.launch(SparkSubmit.scala:328)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:75)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.io.NotSerializableException: com.redis.RedisClient
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
at org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:42)
at org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:73)
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:164)
... 12 more

Could somebody tell me how to serialize the data get from Redis.Thanks a lot.

asked Jan 18 '15 at 2:18
fanhk

173211
 

2 Answers

In Spark, the functions on RDDs (like map here) are serialized and send to the executors for processing. This implies that all elements contained within those operations should be serializable.

The Redis connection here is not serializable as it opens TCP connections to the target DB that are bound to the machine where it's created.

The solution is to create those connections on the executors, in the local execution context. There're few ways to do that. Two that pop to mind are:

  • rdd.mapPartitions: lets you process a whole partition at once, and therefore amortize the cost of creating connections)
  • Singleton connection managers: Create the connection once per executor

mapPartitions is easier as all it requires is a small change to the program structure:

val perhit = perhitFile.mapPartitions{partition =>
val r = new RedisClient("192.168.1.101", 6379) // create the connection in the context of the mapPartition operation
val res = partition.map{ x =>
...
val refStr = r.hmget(...) // use r to process the local data
}
r.close // take care of resources
res
}

A singleton connection manager can be modeled with an object that holds a lazy reference to a connection (note: a mutable ref will also work).

object RedisConnection extends Serializable {
lazy val conn: RedisClient = new RedisClient("192.168.1.101", 6379)
}

This object can then be used to instantiate 1 connection per worker JVM and is used as a Serializable object in an operation closure.

val perhit = perhitFile.map{x =>
val param = f(x)
val refStr = RedisConnection.conn.hmget(...) // use RedisConnection to get a connection to the local data
}
}

The advantage of using the singleton object is less overhead as connections are created only once by JVM (as opposed to 1 per RDD partition)

There're also some disadvantages:

  • cleanup of connections is tricky (shutdown hook/timers)
  • one must ensure thread-safety of shared resources

(*) code provided for illustration purposes. Not compiled or tested.

answered Jan 19 '15 at 12:00
maasg

17.3k34166
 
    
Thank you for answering! I use this library github.com/debasishg/scala-redis. It haven't a method named "close", instead, it is "disconnect".I've no idea if it works. Could you tell me which library you are using now to deal with Redis data? – fanhk Jan 20 '15 at 4:33
    
Plus 1 for the Singleton solution. Can you give an example on how to manage the closing of the connection?– Sohaib Dec 4 '15 at 11:11
    
@Sohaib given this is a VM-bound object, you'll need to register a shutdown hook to cleanly close connections. – maasg Dec 11 '15 at 9:06
 

You're trying to serialize the client. You have one RedisClientr, that you're trying to use inside themap that will be run across different cluster nodes. Either get the data you want out of redis separately before doing a cluster task, or create the client individually for each cluster task inside yourmap block (perhaps by using mapPartitions rather than map, as creating a new redis client for each individual row is probably a bad idea).

answered Jan 18 '15 at 8:42
lmm

10.6k11225
 
    
Thank you for answering, but could you tell me how to use mapPartitions in this situation? – fanhk Jan 18 '15 at 11:49
    
Call mapPartitions passing a block that accepts an iterable (as you can see from the signature ofmapPartitions), creates the RedisClient inside the block, and then uses it to map the Iterable as you were doing. The point is that the RedisClient gets created inside the processing for a single partition. What did you try and where did you get stuck? – lmm Jan 19 '15 at 14:57
    
Problem solved,thank you! – fanhk Jan 20 '15 at 4:42

Redis on Spark:Task not serializable的更多相关文章

  1. spark2.1注册内部函数spark.udf.register("xx", xxx _),运行时抛出异常:Task not serializable

    函数代码: class MySparkJob{ def entry(spark:SparkSession):Unit={ def getInnerRsrp(outer_rsrp: Double, we ...

  2. spark出现task不能序列化错误的解决方法 org.apache.spark.SparkException: Task not serializable

    import org.elasticsearch.cluster.routing.Murmur3HashFunction; import org.elasticsearch.common.math.M ...

  3. Spark运行程序异常信息: org.apache.spark.SparkException: Task not serializable 解决办法

    错误信息: 17/05/20 18:51:39 ERROR JobScheduler: Error running job streaming job 1495277499000 ms.0 org.a ...

  4. 【原创】大叔问题定位分享(19)spark task在executors上分布不均

    最近提交一个spark应用之后发现执行非常慢,点开spark web ui之后发现卡在一个job的一个stage上,这个stage有100000个task,但是绝大部分task都分配到两个execut ...

  5. Hadoop MapReduce Task的进程模型与Spark Task的线程模型

    Hadoop的MapReduce的Map Task和Reduce Task都是进程级别的:而Spark Task则是基于线程模型的. 多进程模型和多线程模型 所谓的多进程模型和多线程模型,指的是同一个 ...

  6. Kafka Topic ISR不全,个别Spark task处理时间长

    现象 Spark streaming读kafka数据做业务处理时,同一个stage的task,有个别task的运行时间比多数task时间都长,造成业务延迟增大. 查看业务对应的topic发现当topi ...

  7. Spark Task 概述

    Task的执行流程: 1. Driver端中的 CoarseGrainSchedulerBackend 给 CoarseGrainExecutorBacken 发送 LaunchTask 消息 2. ...

  8. 大数据学习day34---spark14------1 redis的事务(pipeline)测试 ,2. 利用redis的pipeline实现数据统计的exactlyonce ,3 SparkStreaming中数据写入Hbase实现ExactlyOnce, 4.Spark StandAlone的执行模式,5 spark on yarn

    1 redis的事务(pipeline)测试 Redis本身对数据进行操作,单条命令是原子性的,但事务不保证原子性,且没有回滚.事务中任何命令执行失败,其余的命令仍会被执行,将Redis的多个操作放到 ...

  9. 【原】 Spark中Task的提交源码解读

    版权声明:本文为原创文章,未经允许不得转载. 复习内容: Spark中Stage的提交 http://www.cnblogs.com/yourarebest/p/5356769.html Spark中 ...

随机推荐

  1. java指令备忘

    javap  查看class文件用 指令码 助记符 说明 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 ...

  2. java各种框架的比较,分析

    Spring 框架 优点 1.提供了一种管理对象的方法,可以把中间层的对象有效地组织起来 2.采用了分层结构,可以增量引入到项目中. 3.代码测试较容易 4.非侵入性,应用程序对Spring API的 ...

  3. Oracle查询备注信息

    查询表的备注信息: SELECT TABLE_NAME, TABLE_TYPE, COMMENTS FROM USER_TAB_COMMENTS WHERE TABLE_NAME = 'MR_DEPT ...

  4. 好用的eclipse properties插件

    eclipse默认编辑器: 在有汉字的情况,特别是注释是汉字的情况,你会非常蛋疼的 JP的properties插件:http://propedit.sourceforge.jp/eclipse/upd ...

  5. div最小高度的2种写法

    1.第一种写法: 原理:在IE6中,使用CSS定义div的高度的时候经常遇到这个问题,就是当div的最小高度小于一定的值以后,就会发现,无论你怎么设置最小高度,div的高度会固定在一个值不再发生变动, ...

  6. php替换str_replace的使用方法,支持多个替换

    废话不多说,直接上代码: str_replace(['a','b','c'],'a',$str);//a或b或c都替换成a str_replace(['a','b','c'],['d','e','f' ...

  7. Python 各种库的安装

    在Win7 系统安装的Python 各种库,如:pandas.numpy.scipy等 因为平时使用的是IDE-PyCharm,这里可以直接 [File-Setting-Project:XXX-“+” ...

  8. iOS设计模式:简单工厂模式

    1.简述 首先需要说明一下,简单工厂模式不属于23种GOF设计模式之一.它也称作静态工作方法模式,是工厂方法模式的特殊实现(也就是说工厂模式包含简单工厂模式).这里对简单工厂模式进行介绍,是为后面的工 ...

  9. 什么是IIS应用程序池

    IIS应用程序池是将一个或多个应用程序链接到一个或多个工作进程集合的配置.因为应用程序池中的应用程序与其他应用程序被工作进程边界分隔,所以某个应用程序池中的应用程序不会受到其他应用程序池中应用程序所产 ...

  10. oc 目录结构

    最顶级的oc2是一个项目名,下级的oc2下面的文件是一些程序文件(.m或者.h的文件)和一些界面文件(.xib或者storyboard文件),supporting files文件下面的是资源文件,可以 ...