Spark结构化流Redis接收器性能不理想

时间:2020-01-13 03:05:33

标签: apache-spark redis spark-structured-streaming sink

我使用了Spark结构化的流式消费kafka消息,并将数据保存到Redis。通过扩展ForeachWriter [org.apache.spark.sql.Row],我使用了redis接收器来保存数据。该代码运行良好,但是每秒仅将100多个数据保存到redis。有没有更好的方法来加快此过程?虽然下面的代码将在每个mico批次中连接和断开与Redis服务器的连接,但是有什么方法可以只连接一次并保持连接以最小化连接成本,我认为这是浪费时间的主要原因? 我尝试播放jedis广播,但是jedis和jedispool都无法序列化,因此无法正常工作。

我的接收器代码如下:

class StreamDataSink extends ForeachWriter[org.apache.spark.sql.Row]{

  var jedis:Jedis = _

  override def open(partitionId:Long,version:Long):Boolean={
    if(null == jedis){
      jedis = FPCRedisUtils.getPool.getResource
    }
    true
  }

  override def process(record: Row): Unit = {

    if(0 == record(3)){
      jedis.select(Constants.REDIS_DATABASE_INDEX)
      if(jedis.exists("counter")){
        jedis.incr("counter")
      }else{
        jedis.set("counter",1.toString)
      }
    }
  }

  override def close(errorOrNull: Throwable): Unit = {
    if(null != jedis){
      jedis.close()
      jedis.disconnect()
    }
  }

任何建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

请勿执行jedis.disconnect()。实际上,这将关闭套接字,并在下一次强制建立新连接。仅使用jedis.close(),它将把连接返回到池中。

在不存在的键上调用INCR时,它会自动创建,默认为零,然后递增,从而产生值为1的新键。

这将if-else简化为jedis.incr("counter")

有了这个,你有:

jedis.select(Constants.REDIS_DATABASE_INDEX)
jedis.incr("counter")

查看您是否确实需要Update UI components with NavigationUI。这是每个连接,所有连接默认为DB0。如果共享同一个Jedis池的所有工作负载都在使用DB 0,则无需调用select。

如果您同时需要select和incr,请SELECT

Pipeline pipelined = jedis.pipelined()
pipelined.select(Constants.REDIS_DATABASE_INDEX)
pipelined.incr("counter")
pipelined.sync()

这将在一条网络消息中发送两个命令,从而进一步提高性能。