All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.streampark.common.util.RedisClient.scala Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.streampark.common.util

import org.apache.streampark.common.conf.ConfigConst

import redis.clients.jedis._
import redis.clients.jedis.exceptions.JedisConnectionException

import java.util.concurrent.ConcurrentHashMap

import scala.annotation.meta.getter
import scala.annotation.tailrec
import scala.collection.JavaConversions._
import scala.util.Random

object RedisClient extends Logger {

  @transient
  @getter
  private lazy val pools: ConcurrentHashMap[RedisEndpoint, JedisPool] =
    new ConcurrentHashMap[RedisEndpoint, JedisPool]()

  @transient
  @getter
  private lazy val clusters: ConcurrentHashMap[RedisEndpoint, JedisCluster] =
    new ConcurrentHashMap[RedisEndpoint, JedisCluster]()

  /**
   * Select a random RedisEndpoint to create or get a Redis connection pool
   *
   * @param res
   * @return
   */
  @tailrec
  def connect(endpoints: Array[RedisEndpoint]): Jedis = {
    require(endpoints.length > 0, "[StreamPark] The RedisEndpoint array is empty!!!")
    val index = Random.nextInt().abs % endpoints.length
    try {
      connect(endpoints(index))
    } catch {
      case e: Exception =>
        logger.error(e.getMessage)
        connect(endpoints.drop(index))
    }
  }

  /**
   * Create or get a Redis connection pool
   *
   * @param re
   * @return
   */
  def connect(re: RedisEndpoint): Jedis = {
    val pool = pools.getOrElseUpdate(re, createJedisPool(re))
    var sleepTime: Int = 4
    var conn: Jedis = null
    while (conn == null) {
      try {
        conn = pool.getResource
      } catch {
        case e: JedisConnectionException
            if e.getCause.toString.contains("ERR max number of clients reached") => {
          if (sleepTime < 500) sleepTime *= 2
          Thread.sleep(sleepTime)
        }
        case e: Exception => throw e
      }
    }
    conn
  }

  /**
   * Create a connection pool
   *
   * @param endpoint
   * @return
   */
  def createJedisPool(endpoint: RedisEndpoint): JedisPool = {
    val endpointEn: RedisEndpoint = endpoint.copy(auth = ConfigConst.DEFAULT_DATAMASK_STRING)
    logInfo(s"[StreamPark] RedisClient: createJedisPool with $endpointEn ")
    new JedisPool(
      poolConfig,
      endpoint.host,
      endpoint.port,
      endpoint.timeout,
      endpoint.auth,
      endpoint.db)
  }

  private lazy val poolConfig = {
    val poolConfig: JedisPoolConfig = new JedisPoolConfig()
    // maximum number of connections
    poolConfig.setMaxTotal(1000)
    // maximum number of connections
    poolConfig.setMaxIdle(64)
    // check validity when getting connection, default false
    poolConfig.setTestOnBorrow(true)
    poolConfig.setTestOnReturn(false)
    // check validity at idle, default false
    poolConfig.setTestWhileIdle(false)
    // minimum idle time for eviction connections, default 1800000 milliseconds (30 minutes)
    poolConfig.setMinEvictableIdleTimeMillis(1800000)
    // evicting scan interval (ms), default -1, if negative, do not run the eviction thread
    poolConfig.setTimeBetweenEvictionRunsMillis(30000)
    poolConfig.setNumTestsPerEvictionRun(-1)
    poolConfig
  }

  def connectCluster(res: RedisEndpoint*): JedisCluster = {
    require(res.nonEmpty, "[StreamPark] The RedisEndpoint array is empty!!!")
    val head = res.head
    val cluster = clusters.getOrElseUpdate(
      head, {
        val hostPorts = res.map(r => new HostAndPort(r.host, r.port)).toSet
        new JedisCluster(hostPorts, head.timeout, 1000, 1, head.auth, poolConfig)
      })
    cluster
  }

  def close(): Unit = pools.foreach { case (_, v) => v.close() }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy