Apache Flink源码系列(1)__线程
线程
创建线程方法
| 继承线程类 | java.lang.Thread |
| 实现接口 | java.lang.Runnable、java.lang.Callable、java.lang.FutureTask |
| 线程池 |
java.util.concurrent.ThreadPoolExecutor
|
线程池实际应用
实时风控系统中的多级线程池设计
1. 业务背景
电商平台在订单处理环节可以使用线程池来提升系统性能。订单系统需要处理用户下单、库存检查、支付处理、物流安排等多个环节,每个环节都涉及不同的IO操作和计算任务。
2. 技术实现
为不同类型的任务设计了专门的线程池。
订单验证使用核心线程数为16、最大线程数为32的线程池,因为验证逻辑相对简单但需要快速响应;
库存扣减操作使用核心线程数为8、最大线程数为16的线程池,配合数据库连接池来控制并发度;
支付回调处理使用核心线程数为4、最大线程数为8的线程池,通常来讲,支付处理对数据一致性要求很高。
3. 队列选择
订单验证使用容量为1000的ArrayBlockingQueue,确保在高峰期能够缓存足够的任务;
库存操作使用容量为500的ArrayBlockingQueue,避免过度积压导致库存数据不准确;
支付回调使用容量为200的ArrayBlockingQueue,配合CallerRunsPolicy拒绝策略,确保重要的支付信息不会丢失。
4. 好处
经生产验证,高峰期能够处理每秒数万笔订单,系统响应时间控制在200毫秒以内,显著提升了用户体验。
金融交易系统风控处理
1. 业务背景
证券公司的实时风控系统采用线程池来处理大量的交易风险评估任务。
系统需要在毫秒级时间内完成风险规则检查、历史交易分析、账户状态验证等操作。
2. 技术实现
分层的线程池架构:
第一层是快速筛选池,使用核心线程数为32、最大线程数为64的配置,配合SynchronousQueue来处理基础风险规则检查,这类任务执行时间短但频率高;
第二层是深度分析池,使用核心线程数为16、最大线程数为24的配置,配合容量为100的ArrayBlockingQueue来处理复杂的历史数据分析任务;
第三层是异常处理池,使用核心线程数为4、最大线程数为8的配置,专门处理需要人工介入的异常交易。
3. 拒绝策略
为了确保交易的实时性,系统可使用自定义的拒绝策略,当快速筛选池满载时,会将任务降级到备用线程池处理,同时发送告警通知运维人员。
深度分析池使用DiscardOldestPolicy策略,确保最新的分析任务能够得到及时处理。
4. 好处
经生产验证,该风控系统能够在毫秒级完成风险评估,日处理交易量超过千万笔,风险识别准确率达到99.8%。
互联网广告投放系统
1. 业务背景
互联网公司广告投放系统使用线程池来处理实时竞价、广告素材渲染、效果统计等任务。系统需要在100毫秒内完成广告竞价和投放决策。
2. 技术实现
分层的线程池架构:
竞价处理池使用核心线程数为64、最大线程数为128的配置,因为竞价请求量大且对延迟敏感;
素材渲染池使用核心线程数为32、最大线程数为48的配置,处理广告图片、视频的实时渲染和压缩;
数据统计池使用核心线程数为16、最大线程数为24的配置,处理点击、展示等效果数据的收集和分析。
3. 队列设计
竞价处理使用SynchronousQueue配合AbortPolicy策略,确保竞价请求要么立即处理要么立即拒绝,避免超时导致的广告投放失败;
素材渲染使用容量为2000的LinkedBlockingQueue,允许一定程度的任务积压;
数据统计使用容量为5000的LinkedBlockingQueue配合DiscardOldestPolicy策略,确保最新的统计数据能够得到处理。
4. 好处
经生产验证,日处理广告请求超过10亿次,平均响应时间控制在50毫秒以内,广告投放成功率达到99.9%。
最佳实践
在实际应用中,线程池的配置需要根据具体业务场景进行调优。建议如下:
1. 为线程池设置有意义的名称便于监控和调试,同时配置JVM参数来优化线程栈大小;
2. 定期分析线程池的运行状况,根据业务负载变化调整配置参数,确保系统在各种情况下都能稳定高效运行。
3. 通过压力测试来确定最优的线程数配置,同时监控线程池的关键指标如队列长度、活跃线程数、任务完成数等。
合理设置队列大小很重要,队列过小可能导致任务被拒绝,队列过大可能导致内存溢出或响应时间过长。
选择合适的拒绝策略,对于重要任务建议使用CallerRunsPolicy,对于可以丢弃的任务可以使用DiscardOldestPolicy。
4. 避免使用Executors提供的默认线程池,而是根据业务需求自定义ThreadPoolExecutor参数。
flink中的线程池
flink源码模块线程池
/**
* Flink版本:release-2.0.0
*
**/
// flink-core模块,ExecutorThreadFactory.java
public class ExecutorThreadFactory implements ThreadFactory {
/** The thread pool name used when no explicit pool name has been specified. */
private static final String DEFAULT_POOL_NAME = "flink-executor-pool";
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final String namePrefix;
private final int threadPriority;
@Nullable private final UncaughtExceptionHandler exceptionHandler;
// ------------------------------------------------------------------------
/**
* Creates a new thread factory using the default thread pool name ('flink-executor-pool') and
* the default uncaught exception handler (log exception and kill process).
*/
public ExecutorThreadFactory() {
this(DEFAULT_POOL_NAME);
}
/**
* Creates a new thread factory using the given thread pool name and the default uncaught
* exception handler (log exception and kill process).
*
* @param poolName The pool name, used as the threads' name prefix
*/
public ExecutorThreadFactory(String poolName) {
this(poolName, FatalExitExceptionHandler.INSTANCE);
}
/**
* Creates a new thread factory using the given thread pool name and the given uncaught
* exception handler.
*
* @param poolName The pool name, used as the threads' name prefix
* @param exceptionHandler The uncaught exception handler for the threads
*/
public ExecutorThreadFactory(String poolName, UncaughtExceptionHandler exceptionHandler) {
this(poolName, Thread.NORM_PRIORITY, exceptionHandler);
}
ExecutorThreadFactory(
final String poolName,
final int threadPriority,
@Nullable final UncaughtExceptionHandler exceptionHandler) {
this.namePrefix = checkNotNull(poolName, "poolName") + "-thread-";
this.threadPriority = threadPriority;
this.exceptionHandler = exceptionHandler;
SecurityManager securityManager = System.getSecurityManager();
this.group =
(securityManager != null)
? securityManager.getThreadGroup()
: Thread.currentThread().getThreadGroup();
}
// ------------------------------------------------------------------------
@Override
public Thread newThread(Runnable runnable) {
Thread t = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(true);
t.setPriority(threadPriority);
// optional handler for uncaught exceptions
if (exceptionHandler != null) {
t.setUncaughtExceptionHandler(exceptionHandler);
}
return t;
}
// --------------------------------------------------------------------------------------------
/** Builder for {@link ExecutorThreadFactory}. */
public static final class Builder {
private String poolName;
private int priority = Thread.NORM_PRIORITY;
private UncaughtExceptionHandler exceptionHandler = FatalExitExceptionHandler.INSTANCE;
public Builder setPoolName(final String poolName) {
this.poolName = poolName;
return this;
}
public Builder setThreadPriority(final int priority) {
this.priority = priority;
return this;
}
public Builder setExceptionHandler(final UncaughtExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
return this;
}
public ExecutorThreadFactory build() {
return new ExecutorThreadFactory(poolName, priority, exceptionHandler);
}
}
}
// flink-runtime模块,TaskExecutor.java
public TaskExecutor(
RpcService rpcService,
TaskManagerConfiguration taskManagerConfiguration,
HighAvailabilityServices haServices,
TaskManagerServices taskExecutorServices,
ExternalResourceInfoProvider externalResourceInfoProvider,
HeartbeatServices heartbeatServices,
TaskManagerMetricGroup taskManagerMetricGroup,
@Nullable String metricQueryServiceAddress,
TaskExecutorBlobService taskExecutorBlobService,
FatalErrorHandler fatalErrorHandler,
TaskExecutorPartitionTracker partitionTracker,
DelegationTokenReceiverRepository delegationTokenReceiverRepository) {
super(rpcService, RpcServiceUtils.createRandomName(TASK_MANAGER_NAME));
checkArgument(
taskManagerConfiguration.getNumberSlots() > 0,
"The number of slots has to be larger than 0.");
this.taskManagerConfiguration = checkNotNull(taskManagerConfiguration);
this.taskExecutorServices = checkNotNull(taskExecutorServices);
this.haServices = checkNotNull(haServices);
this.fatalErrorHandler = checkNotNull(fatalErrorHandler);
this.partitionTracker = partitionTracker;
this.delegationTokenReceiverRepository = checkNotNull(delegationTokenReceiverRepository);
this.taskManagerMetricGroup = checkNotNull(taskManagerMetricGroup);
this.taskExecutorBlobService = checkNotNull(taskExecutorBlobService);
this.metricQueryServiceAddress = metricQueryServiceAddress;
this.externalResourceInfoProvider = checkNotNull(externalResourceInfoProvider);
this.libraryCacheManager = taskExecutorServices.getLibraryCacheManager();
this.taskSlotTable = taskExecutorServices.getTaskSlotTable();
this.jobTable = taskExecutorServices.getJobTable();
this.jobLeaderService = taskExecutorServices.getJobLeaderService();
this.unresolvedTaskManagerLocation =
taskExecutorServices.getUnresolvedTaskManagerLocation();
this.localStateStoresManager = taskExecutorServices.getTaskManagerStateStore();
this.fileMergingManager = taskExecutorServices.getTaskManagerFileMergingManager();
this.changelogStoragesManager = taskExecutorServices.getTaskManagerChangelogManager();
this.channelStateExecutorFactoryManager =
taskExecutorServices.getTaskManagerChannelStateManager();
this.shuffleEnvironment = taskExecutorServices.getShuffleEnvironment();
this.kvStateService = taskExecutorServices.getKvStateService();
this.ioExecutor = taskExecutorServices.getIOExecutor();
this.resourceManagerLeaderRetriever = haServices.getResourceManagerLeaderRetriever();
this.hardwareDescription =
HardwareDescription.extractFromSystem(taskExecutorServices.getManagedMemorySize());
this.memoryConfiguration =
TaskExecutorMemoryConfiguration.create(taskManagerConfiguration.getConfiguration());
this.resourceManagerAddress = null;
this.resourceManagerConnection = null;
this.currentRegistrationTimeoutId = null;
final ResourceID resourceId =
taskExecutorServices.getUnresolvedTaskManagerLocation().getResourceID();
this.jobManagerHeartbeatManager =
createJobManagerHeartbeatManager(heartbeatServices, resourceId);
this.resourceManagerHeartbeatManager =
createResourceManagerHeartbeatManager(heartbeatServices, resourceId);
// 线程池
ExecutorThreadFactory sampleThreadFactory =
new ExecutorThreadFactory.Builder()
.setPoolName("flink-thread-info-sampler")
.build();
ScheduledExecutorService sampleExecutor =
Executors.newSingleThreadScheduledExecutor(sampleThreadFactory);
this.threadInfoSampleService = new ThreadInfoSampleService(sampleExecutor);
this.profilingService =
ProfilingService.getInstance(taskManagerConfiguration.getConfiguration());
this.slotAllocationSnapshotPersistenceService =
taskExecutorServices.getSlotAllocationSnapshotPersistenceService();
this.sharedResources = taskExecutorServices.getSharedResources();
this.jobInformationCache = taskExecutorServices.getJobInformationCache();
this.taskInformationCache = taskExecutorServices.getTaskInformationCache();
this.shuffleDescriptorsCache = taskExecutorServices.getShuffleDescriptorCache();
}

浙公网安备 33010602011771号