技术为需求服务,通用需求由开源软件提供功能,一些特殊的需求,需要基于场景定制化开发功能。而对于自定义开发功能,Flink则提供了这样的SDK接口能力。
本文将从定制化功能需求分析和如何基于Flink构建定制化功能两个方面讲述。
一些常规需求的应用能力已经被包装得很好,只需要关注包装在功能之上的交互逻辑,就能满足业务需求。但有些需求依靠现成的技术无法完成,只能自定义任务逻辑,完成特定场景需求的功能包装;或者部分功能性能和可用性不佳,需要重构功能满足可用性和高性能需求。
大数据场景,对数据集成、加工与分析、写结果这三个过程,都可以做定制化开发:
从集成角度:公司采集各种数据源的数据:使用集成工具,如fileBeat、dataX、canal、sqoop、Flume等从各种源端获取数据,这属于对功能的应用;
如果定制化开发任务:需要对SourceFunction函数的包装,实现对各种数据源的采集,这属于定制化需求开发;
如果定制化开发SDK:开发一个工具包,然后通过更改数据源配置驱动任务,这就属于定制化功能的开发,如:flink-sql-connector-mysql-cdc;
从加工和分析角度:
如果对数据的加工:实现类似ETL处理,数据扩维,打标,特征聚类,这属于定制化需求开发;
如果重写处理算子函数:对数据操作重写一个ProcessFunction、MapFunction、AggregateFunction函数,然后重载到DataStream对象里,这就是定制化功能开发;
从写结果过程:
如果自定义RichSinkFunction函数:实现对目标端接口的包装,这属于定制化需求开发;
如果包装一个SDK工具:然后将功能打包成SDK服务,嵌入Flink的sink算子内,这属于定制化功能的开发,如doris包装的:flink-doris-connector-1.14_2.12。
以下是基于Flink构建定制化需求和功能的一些思路:
首先,理清楚你的业务需求和所需的计算模型。明确需要处理的数据类型、处理逻辑、计算规则和数据流动方向等。
利用 Flink 的 DataStream API 或 Table API,根据业务需求编写你的计算逻辑。这些 API 提供了丰富的操作符和方法,用于对数据进行转换、聚合、过滤等处理。你可以根据实际需求自定义操作符和函数,实现特定的计算逻辑。
如果标准操作符无法满足你的需求,可以实现自定义的算子(Operator)或函数(Function)。例如,可以扩展 Flink 的 RichFunction 接口,实现自定义的 MapFunction、FilterFunction、AggregateFunction、KeyedProcessFunction 等。
这些算子的底层是通过processFucetion实现的,可以自定义processFucetion的value与context构建更细粒度的操作;
对于一些有自己客户端和读写API的服务,可以将服务读写API,通过服务客户端接口自定义RichSourceFunction和RichSinkFunction,然后包装成SDK提供服务;
以下是自定义Redis的RichSinkFunction函数例子:
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;
public class RedisSink extends RichSinkFunction> {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisSink.class);
private JedisCluster cluster;
private String key;
private String value;
public RedisSink(String key, String value) {
this.key = key;
this.value = value;
}
@Override
public void open(Configuration parameters) throws Exception {
Set hostAndPorts = new HashSet<>();
hostAndPorts.add(new HostAndPort("ip", 1111));
hostAndPorts.add(new HostAndPort("ip2", 1111));
// Jedis连接池配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲连接数, 默认8个
jedisPoolConfig.setMaxIdle(100);
// 最大连接数, 默认8个
jedisPoolConfig.setMaxTotal(500);
//最小空闲连接数, 默认0
jedisPoolConfig.setMinIdle(0);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
jedisPoolConfig.setMaxWaitMillis(2000); // 设置2秒
cluster = new JedisCluster(hostAndPorts, jedisPoolConfig);
}
@Override
public void invoke(Tuple2 tuple2, Context context) throws Exception {
cluster.set(tuple2.f0, tuple2.f1);
}
@Override
public void close() throws Exception {
super.close();
if (cluster != null) {
cluster.close();
}
}
}
在构建定制化计算引擎的过程中,持续进行优化和调优是很重要的。考虑到数据处理性能、吞吐量和延迟等方面的问题,对代码进行优化和调整。
完成代码编写后,进行测试和验证。确保计算引擎在不同场景和数据量下能够正常运行。之后,根据需求选择合适的部署方式,可以在集群环境中部署你的定制化计算引擎。
一旦部署完成,建立相应的监控机制,监控计算引擎的运行状态和性能指标。持续地进行维护和优化,确保计算引擎的稳定性和性能。
总的来说,构建定制化的计算引擎需要深入了解业务需求,善用 Flink 提供的 API,并根据实际情况进行优化和调整。 Flink 提供了强大的功能和灵活性,可以帮助你构建符合特定业务场景需求的定制化计算引擎,完成定制化功能的开发。