Skip to content

Commit 6bb11e6

Browse files
authored
[improve] optimization redis sink (apache#690)
* [improve] optimization redis sink
1 parent e45d637 commit 6bb11e6

File tree

3 files changed

+100
-78
lines changed
  • streamx-common/src/main/scala/com/streamxhub/streamx/common/conf

3 files changed

+100
-78
lines changed

streamx-common/src/main/scala/com/streamxhub/streamx/common/conf/ConfigConst.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ object ConfigConst {
201201

202202
val REDIS_CONNECT_TYPE = "connectType"
203203

204-
val DEFAULT_REDIS_CONNECT_TYPE = "jedispool"
204+
val DEFAULT_REDIS_CONNECT_TYPE = "jedisPool"
205205

206206
val KEY_ALIAS = "alias"
207207

streamx-flink/streamx-flink-core/src/main/scala/com/streamxhub/streamx/flink/core/scala/sink/RedisSink.scala

+98-76
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ import org.apache.flink.streaming.api.datastream.DataStreamSink
3232
import org.apache.flink.streaming.api.functions.sink.{SinkFunction, TwoPhaseCommitSinkFunction}
3333
import org.apache.flink.streaming.api.scala.DataStream
3434
import org.apache.flink.streaming.connectors.redis.common.config.{FlinkJedisConfigBase, FlinkJedisPoolConfig, FlinkJedisSentinelConfig}
35-
import org.apache.flink.streaming.connectors.redis.common.container.{RedisContainer => RContainer}
35+
import org.apache.flink.streaming.connectors.redis.common.container.{RedisContainer => BahirRedisContainer}
3636
import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand._
37-
import org.apache.flink.streaming.connectors.redis.common.mapper.{RedisCommand, RedisCommandDescription, RedisMapper => RMapper}
38-
import org.apache.flink.streaming.connectors.redis.{RedisSink => RSink}
37+
import org.apache.flink.streaming.connectors.redis.common.mapper.{RedisCommand, RedisCommandDescription, RedisMapper => BahirRedisMapper}
38+
import org.apache.flink.streaming.connectors.redis.{RedisSink => BahirRedisSink}
3939
import redis.clients.jedis.exceptions.JedisException
4040
import redis.clients.jedis.{Jedis, JedisPool, JedisSentinelPool}
4141

4242
import java.io.IOException
43+
import java.lang.reflect.Field
4344
import java.util
4445
import java.util.Properties
4546
import scala.annotation.meta.param
@@ -65,67 +66,90 @@ class RedisSink(@(transient@param) ctx: StreamingContext,
6566

6667
val enableCheckpoint: Boolean = ctx.parameter.toMap.getOrElse(KEY_FLINK_CHECKPOINTS_ENABLE, "false").toBoolean
6768

68-
val cpMode: CheckpointingMode = Try(CheckpointingMode.valueOf(ctx.parameter.toMap.get(KEY_FLINK_CHECKPOINTS_MODE))).getOrElse(CheckpointingMode.AT_LEAST_ONCE)
69+
val cpMode: CheckpointingMode = Try(
70+
CheckpointingMode.valueOf(ctx.parameter.toMap.get(KEY_FLINK_CHECKPOINTS_MODE))
71+
).getOrElse(CheckpointingMode.AT_LEAST_ONCE)
72+
6973

7074
lazy val config: FlinkJedisConfigBase = {
7175
val map: util.Map[String, String] = ctx.parameter.toMap
7276
val redisConf = ConfigUtils.getConf(map, REDIS_PREFIX)
7377
val connectType: String = Try(redisConf.remove(REDIS_CONNECT_TYPE).toString).getOrElse(DEFAULT_REDIS_CONNECT_TYPE)
7478
Utils.copyProperties(property, redisConf)
79+
7580
val host: String = redisConf.remove(KEY_HOST) match {
7681
case null => throw new IllegalArgumentException("redis host must not null")
7782
case hostStr => hostStr.toString
7883
}
84+
7985
val port: Int = redisConf.remove(KEY_PORT) match {
8086
case null => 6379
8187
case portStr => portStr.toString.toInt
8288
}
89+
90+
def setFieldValue(field: Field, targetObject: Any, value: String): Unit = {
91+
field.setAccessible(true)
92+
field.getType.getSimpleName match {
93+
case "String" => field.set(targetObject, value)
94+
case "int" | "Integer" => field.set(targetObject, value.toInt)
95+
case "long" | "Long" => field.set(targetObject, value.toLong)
96+
case "boolean" | "Boolean" => field.set(targetObject, value.toBoolean)
97+
case _ =>
98+
}
99+
}
100+
83101
connectType match {
84-
case "sentinel" => {
102+
103+
case "sentinel" =>
85104
val sentinels: Set[String] = host.split(SIGN_COMMA).map(x => {
86-
if (!x.contains(SIGN_COLON)) {
105+
if (x.contains(SIGN_COLON)) x; else {
87106
throw new IllegalArgumentException(s"redis sentinel host invalid {$x} must match host:port ")
88107
}
89-
x
90108
}).toSet
91-
val builder: FlinkJedisSentinelConfig.Builder = new FlinkJedisSentinelConfig.Builder().setSentinels(sentinels)
109+
val builder = new FlinkJedisSentinelConfig.Builder().setSentinels(sentinels)
92110
redisConf.foreach(x => {
93-
val field = Try(Option(builder.getClass.getDeclaredField(x._1))).getOrElse(None) match {
94-
case Some(x) => x
95-
case None => throw new IllegalArgumentException(s"redis config error,property:${
96-
x._1
97-
} invalid,init FlinkJedisSentinelConfig err")
98-
}
99-
field.setAccessible(true)
100-
field.getType.getSimpleName match {
101-
case "String" => field.set(builder, x._2)
102-
case "int" | "Integer" => field.set(builder, x._2.toInt)
103-
case "long" | "Long" => field.set(builder, x._2.toLong)
104-
case "boolean" | "Boolean" => field.set(builder, x._2.toBoolean)
105-
case _ =>
111+
val field = Try(builder.getClass.getDeclaredField(x._1)).getOrElse {
112+
throw new IllegalArgumentException(
113+
s"""
114+
|redis config error,property:${x._1} invalid,init FlinkJedisSentinelConfig error, property options:
115+
|<String masterName>,
116+
|<Set<String> sentinels>,
117+
|<int connectionTimeout>,
118+
|<int soTimeout>,
119+
|<String password>,
120+
|<int database>,
121+
|<int maxTotal>,
122+
|<int maxIdle>,
123+
|<int minIdle>
124+
|""".stripMargin)
106125
}
126+
setFieldValue(field, builder, x._2)
107127
})
108128
builder.build()
109-
}
110-
case DEFAULT_REDIS_CONNECT_TYPE => {
129+
130+
case DEFAULT_REDIS_CONNECT_TYPE =>
111131
val builder: FlinkJedisPoolConfig.Builder = new FlinkJedisPoolConfig.Builder().setHost(host).setPort(port)
112132
redisConf.foreach(x => {
113-
val field = Try(Option(builder.getClass.getDeclaredField(x._1))).getOrElse(None) match {
114-
case Some(x) => x
115-
case None => throw new IllegalArgumentException(s"redis config error,property:${x._1} invalid,init FlinkJedisPoolConfig err")
116-
}
117-
field.setAccessible(true)
118-
field.getType.getSimpleName match {
119-
case "String" => field.set(builder, x._2)
120-
case "int" | "Integer" => field.set(builder, x._2.toInt)
121-
case "long" | "Long" => field.set(builder, x._2.toLong)
122-
case "boolean" | "Boolean" => field.set(builder, x._2.toBoolean)
123-
case _ =>
133+
val field = Try(builder.getClass.getDeclaredField(x._1)).getOrElse {
134+
throw new IllegalArgumentException(
135+
s"""
136+
|redis config error,property:${x._1} invalid,init FlinkJedisPoolConfig error,property options:
137+
|<String host>,
138+
|<int port>,
139+
|<int timeout>,
140+
|<int database>,
141+
|<String password>,
142+
|<int maxTotal>,
143+
|<int maxIdle>,
144+
|<int minIdle>
145+
|""".stripMargin)
124146
}
147+
setFieldValue(field, builder, x._2)
125148
})
149+
126150
builder.build()
127-
}
128-
case _ => throw throw new IllegalArgumentException(s"redis connectType must be jedispool|sentinel|cluster $connectType")
151+
152+
case _ => throw throw new IllegalArgumentException(s"redis connectType must be jedisPool|sentinel|cluster $connectType")
129153
}
130154
}
131155

@@ -142,7 +166,7 @@ class RedisSink(@(transient@param) ctx: StreamingContext,
142166
}
143167

144168

145-
class RedisSinkFunction[T](jedisConfig: FlinkJedisConfigBase, mapper: RedisMapper[T], ttl: Int) extends RSink[T](jedisConfig, mapper) with Logger {
169+
class RedisSinkFunction[T](jedisConfig: FlinkJedisConfigBase, mapper: RedisMapper[T], ttl: Int) extends BahirRedisSink[T](jedisConfig, mapper) with Logger {
146170

147171
private[this] var redisContainer: RedisContainer = _
148172

@@ -235,31 +259,29 @@ object RedisContainer extends Logger {
235259
genericObjectPoolConfig.setMaxTotal(jedisConfig.getMaxTotal)
236260
genericObjectPoolConfig.setMinIdle(jedisConfig.getMinIdle)
237261
try {
238-
var redisContaineInnerr: RContainer = null
239-
if (jedisConfig.isInstanceOf[FlinkJedisPoolConfig]) {
240-
val jedisPoolConfig = jedisConfig.asInstanceOf[FlinkJedisPoolConfig]
241-
val jedisPool = new JedisPool(
242-
genericObjectPoolConfig,
243-
jedisPoolConfig.getHost,
244-
jedisPoolConfig.getPort,
245-
jedisPoolConfig.getConnectionTimeout,
246-
jedisPoolConfig.getPassword,
247-
jedisPoolConfig.getDatabase
248-
)
249-
redisContaineInnerr = new RContainer(jedisPool)
250-
}
251-
else {
252-
val jedissentinelconfig: FlinkJedisSentinelConfig = jedisConfig.asInstanceOf[FlinkJedisSentinelConfig]
253-
val jedisSentinelPool: JedisSentinelPool = new JedisSentinelPool(jedissentinelconfig.getMasterName(),
254-
jedissentinelconfig.getSentinels(),
255-
genericObjectPoolConfig,
256-
jedissentinelconfig.getSoTimeout(),
257-
jedissentinelconfig.getPassword(),
258-
jedissentinelconfig.getDatabase()
259-
)
260-
redisContaineInnerr = new RContainer(jedisSentinelPool)
262+
val bahirRedisContainer = jedisConfig match {
263+
case jedisPoolConfig: FlinkJedisPoolConfig =>
264+
val jedisPool = new JedisPool(
265+
genericObjectPoolConfig,
266+
jedisPoolConfig.getHost,
267+
jedisPoolConfig.getPort,
268+
jedisPoolConfig.getConnectionTimeout,
269+
jedisPoolConfig.getPassword,
270+
jedisPoolConfig.getDatabase
271+
)
272+
new BahirRedisContainer(jedisPool)
273+
case _ =>
274+
val jedisSentinelConfig = jedisConfig.asInstanceOf[FlinkJedisSentinelConfig]
275+
val jedisSentinelPool = new JedisSentinelPool(jedisSentinelConfig.getMasterName,
276+
jedisSentinelConfig.getSentinels,
277+
genericObjectPoolConfig,
278+
jedisSentinelConfig.getSoTimeout,
279+
jedisSentinelConfig.getPassword,
280+
jedisSentinelConfig.getDatabase
281+
)
282+
new BahirRedisContainer(jedisSentinelPool)
261283
}
262-
val redisContainer = new RedisContainer(redisContaineInnerr)
284+
val redisContainer = new RedisContainer(bahirRedisContainer)
263285
redisContainer.open()
264286
redisContainer
265287
} catch {
@@ -271,16 +293,16 @@ object RedisContainer extends Logger {
271293

272294
}
273295

274-
class RedisContainer(reContainer: RContainer) {
296+
class RedisContainer(container: BahirRedisContainer) {
275297

276298
def open(): Unit = {
277-
reContainer.open()
299+
container.open()
278300
}
279301

280302
lazy val jedis: Jedis = {
281-
val method = reContainer.getClass.getDeclaredMethod("getInstance")
303+
val method = container.getClass.getDeclaredMethod("getInstance")
282304
method.setAccessible(true)
283-
method.invoke(reContainer).asInstanceOf[Jedis]
305+
method.invoke(container).asInstanceOf[Jedis]
284306
}
285307

286308
def invoke[T](mapper: RedisMapper[T], input: T, transaction: Option[redis.clients.jedis.Transaction]): Unit = {
@@ -289,39 +311,39 @@ class RedisContainer(reContainer: RContainer) {
289311
mapper.getCommandDescription.getCommand match {
290312
case RPUSH => transaction match {
291313
case Some(t) => t.rpush(key, value)
292-
case _ => this.reContainer.rpush(key, value)
314+
case _ => this.container.rpush(key, value)
293315
}
294316
case LPUSH => transaction match {
295317
case Some(t) => t.lpush(key, value)
296-
case _ => this.reContainer.lpush(key, value)
318+
case _ => this.container.lpush(key, value)
297319
}
298320
case SADD => transaction match {
299321
case Some(t) => t.sadd(key, value)
300-
case _ => this.reContainer.sadd(key, value)
322+
case _ => this.container.sadd(key, value)
301323
}
302324
case SET => transaction match {
303325
case Some(t) => t.set(key, value)
304-
case _ => this.reContainer.set(key, value)
326+
case _ => this.container.set(key, value)
305327
}
306328
case PFADD => transaction match {
307329
case Some(t) => t.pfadd(key, value)
308-
case _ => this.reContainer.pfadd(key, value)
330+
case _ => this.container.pfadd(key, value)
309331
}
310332
case PUBLISH => transaction match {
311333
case Some(t) => t.publish(key, value)
312-
case _ => this.reContainer.publish(key, value)
334+
case _ => this.container.publish(key, value)
313335
}
314336
case ZADD => transaction match {
315337
case Some(t) => t.zadd(mapper.getCommandDescription.getAdditionalKey, value.toDouble, key)
316-
case _ => this.reContainer.zadd(mapper.getCommandDescription.getAdditionalKey, value, key)
338+
case _ => this.container.zadd(mapper.getCommandDescription.getAdditionalKey, value, key)
317339
}
318340
case ZREM => transaction match {
319341
case Some(t) => t.zrem(mapper.getCommandDescription.getAdditionalKey, key)
320-
case _ => this.reContainer.zrem(mapper.getCommandDescription.getAdditionalKey, key)
342+
case _ => this.container.zrem(mapper.getCommandDescription.getAdditionalKey, key)
321343
}
322344
case HSET => transaction match {
323345
case Some(t) => t.hset(mapper.getCommandDescription.getAdditionalKey, key, value)
324-
case _ => this.reContainer.hset(mapper.getCommandDescription.getAdditionalKey, key, value)
346+
case _ => this.container.hset(mapper.getCommandDescription.getAdditionalKey, key, value)
325347
}
326348
case other => throw new IllegalArgumentException("[StreamX] RedisSink:Cannot process such data type: " + other)
327349
}
@@ -335,13 +357,13 @@ class RedisContainer(reContainer: RContainer) {
335357
}
336358

337359
def close(): Unit = {
338-
reContainer.close()
360+
container.close()
339361
}
340362

341363
}
342364

343365

344-
case class RedisMapper[T](cmd: RedisCommand, additionalKey: String, key: T => String, value: T => String) extends RMapper[T] {
366+
case class RedisMapper[T](cmd: RedisCommand, additionalKey: String, key: T => String, value: T => String) extends BahirRedisMapper[T] {
345367

346368
override def getCommandDescription: RedisCommandDescription = new RedisCommandDescription(cmd, additionalKey)
347369

streamx-flink/streamx-flink-test/streamx-flink-test-datastream/assembly/conf/application.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,4 @@ redis.sink:
206206
host: 127.0.0.1
207207
port: 6379
208208
database: 2
209-
connectType: jedispool #可选参数:jedispool(默认)|sentinel
209+
connectType: jedisPool #可选参数:jedisPool(默认)|sentinel

0 commit comments

Comments
 (0)