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. LogUtils.java

    package com.xdsjs.save.utils; /** * 日志相关管理类 * Created by xdsjs on 2015/10/13. */ import android.util ...

  2. yml 配置文件注入

    配置文件 JavaBean 自动提示 测试

  3. This Handler class should be static or leaks might occur,Handler和Context使用的注意事项!

    Android中.在使用到Handler的时候,假设按例如以下代码编写: private Handler handler; @Override public void onCreate(Bundle ...

  4. SettingsJDK

      迁移时间:2017年5月20日23:38:40 Author:Marydon 1.双击安装,更改安装路径为D:\ProgramFiles\Java\jdk1.7.0_55: 注意事项: 1.1 将 ...

  5. CSS3制作Freebie标签

    <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...

  6. 【php】实现多个一维数组转换成二维循环数组

    1.目的:将下面类型数组转换成模板循环打印二维数组 数组库一维数组: 模板要求循环二维数组: 2.代码: header("Content-type: text/html; charset=u ...

  7. Appirater激励用户为你的app评分

    如果你此前开发过app,那么你会知道获得用户积极的评分并不是一件简单的事情.不幸的是,用户往往给他们不喜欢的东西负面评价,而不怎么倾向于给喜欢的内容留下积极评价.   所以,你作为一个开发者如何激励用 ...

  8. ubuntu(14.04) remote access(远程连接数据库)

    1.修改mysql的配置文件.   /etc/mysql/my.cnf 把 bind-address 的那行代码注释掉,保存退出,重启mysql

  9. Hadoop Archives

    原文地址:http://hadoop.apache.org/docs/r1.0.4/cn/hadoop_archives.html 什么是Hadoop archives? 如何创建archive? 如 ...

  10. jQuery on() 方法问题

    <!DOCTYPE html><html><head><script src="https://cdn.bootcss.com/jquery/1.1 ...