*******************************PowerJob学习*********************************************************
服务端启动类:tech.powerjob.server.core.handler.impl.Initializer:
知识点:
@Component
@ConditionalOnExpression("'${execution.env}'!='test'") + @PostConstruct 程序启动后会初始化加载这个注释下的方法
客户端启动类:tech.powerjob.worker.PowerJobWorker :
知识点:实现了InitializingBean类的afterPropertiesSet()方法
初始化包括了【日志上报,健康上报,客户端发送http请求获取appName是否可用】。
上报方式:
workerRuntime.getExecutorManager().getCoreExecutor().scheduleAtFixedRate(new WorkerHealthReporter(workerRuntime), 0, config.getHealthReportInterval(), TimeUnit.SECONDS);
workerRuntime.getExecutorManager().getCoreExecutor().scheduleWithFixedDelay(omsLogHandler.logSubmitter, 0, 5, TimeUnit.SECONDS);
scheduleAtFixedRate:执行任务开始计时,不算是否执行完,间隔一定时间,执行下一次。
scheduleWithFixedDelay:执行完上一次任务,间隔一定时间,执行下一次。
四个参数说明:(
command:执行线程
initialDelay:初始化延时
period:两次开始执行最小间隔时间
unit:计时单位
)
客户端akka服务:
1:[【TaskTrackerActor】worker 上报 task 执行情况,服务端调度任务请求(一次任务处理的入口),WorkerMapTaskRequest
ProcessorTracker 定时向 TaskTracker 上报健康状态,服务器要求任务实例停止执行请求,
服务器查询实例运行状态、需要返回详细的运行数据
.match(ProcessorReportTaskStatusReq.class, this::onReceiveProcessorReportTaskStatusReq)
.match(ServerScheduleJobReq.class, this::onReceiveServerScheduleJobReq)
调度中心分发任务请求 .match(ProcessorMapTaskRequest.class, this::onReceiveProcessorMapTaskRequest)
.match(ProcessorTrackerStatusReportReq.class, this::onReceiveProcessorTrackerStatusReportReq)
.match(ServerStopInstanceReq.class, this::onReceiveServerStopInstanceReq)
.match(ServerQueryInstanceStatusReq.class, this::onReceiveServerQueryInstanceStatusReq)
2:【ProcessorTrackerActor】 TaskTracker 派发 task 进行执行,TaskTracker 停止 ProcessorTracker,释放相关资源
.match(TaskTrackerStartTaskReq.class, this::onReceiveTaskTrackerStartTaskReq)
.match(TaskTrackerStopInstanceReq.class, this::onReceiveTaskTrackerStopInstanceReq)
3:【WorkerActor】Worker部署Container请求,服务器销毁容器请求,服务端调度任务请求(一次任务处理的入口)
服务器要求任务实例停止执行请求,服务器查询实例运行状态、需要返回详细的运行数据
.match(ServerDeployContainerRequest.class, this::onReceiveServerDeployContainerRequest)
.match(ServerDestroyContainerRequest.class, this::onReceiveServerDestroyContainerRequest)
.match(ServerScheduleJobReq.class, this::forward2TaskTracker)
.match(ServerStopInstanceReq.class, this::forward2TaskTracker)
.match(ServerQueryInstanceStatusReq.class, this::forward2TaskTracker)
客户端发送akka请求:
tech.powerjob.server.remote.transport.starter.AkkaStarter.getFriendActor(String):
获取friendAcctor中的服务,对应下面服务端akka服务:1
tech.powerjob.server.remote.transport.starter.AkkaStarter.getWorkerActor(String)
获取WorkerActor中的服务,对应下面服务端akka服务:2
服务端akka服务:
1:ping , 原创执行命令【friendAcctor】
.match(Ping.class, this::onReceivePing)
.match(RemoteProcessReq.class, this::onReceiveRemoteProcessReq)
2:心跳检测,TaskTracker 将状态上报给服务器, 日志上报请求,
Worker需要部署容器、主动向Server请求信息, worker 查询 执行器集群(动态上线需要)
.match(WorkerHeartbeat.class, hb -> fetchWorkerRequestHandler().processWorkerHeartbeat(hb))
.match(TaskTrackerReportInstanceStatusReq.class, this::onReceiveTaskTrackerReportInstanceStatusReq)
.match(WorkerLogReportReq.class, req -> fetchWorkerRequestHandler().processWorkerLogReport(req))
.match(WorkerNeedDeployContainerRequest.class, this::onReceiveWorkerNeedDeployContainerRequest)
.match(WorkerQueryExecutorClusterReq.class, this::onReceiveWorkerQueryExecutorClusterReq)
服务端发送akka请求
【tech.powerjob.server.core.DispatchService.dispatch(JobInfoDO, Long, Optional<InstanceInfoDO>, Optional<Holder<Boolean>>)】
服务器分发任务给客户端请求:【ServerScheduleJobReq】
transportService.tell(Protocol.of(taskTracker.getProtocol()), taskTrackerAddress, req);
【ServerStopInstanceReq】
transportService.tell(Protocol.of(workerInfo.getProtocol()), workerInfo.getAddress(), req);
服务器查询实例运行状态、需要返回详细的运行数据
【服务器查询实例运行状态、需要返回详细的运行数据】
AskResponse askResponse = transportService.ask(Protocol.of(workerInfo.getProtocol()), workerInfo.getAddress(), req);
服务端vert服务:
1:/server/heartbeat
2:/server/statusReport
3:/server/logReport
日志模块分析:
从页面开始分析:
详情:/detail 不是运行状态就查数据库instance_info 【客户端3;ServerQueryInstanceStatusReq】
重试工具类:String resultDTOStr = CommonUtils.executeWithRetry0(() -> HttpUtils.get(realUrl));
private final Lock reportLock = new ReentrantLock();加锁
ArrayBlockingQueue阻塞队列 不支持多线程,单锁
LinkedBlockingQueue 支持多线程,双锁与ArrayBlockingQueue不同的是,LinkedBlockingQueue拥有两把锁,一把读锁,一把写锁,可以在多线程情况下,满足同时出队和入队的操作。
设置原数:
put(E e)是阻塞式插入,如果队列中的元素与链表长度相同,则此线程等待,直到有空余空间时,才执行。
offer(E e)是非阻塞式插入,队列中的元素与链表长度相同时,直接返回false,不会阻塞线程。
获取原数:
take():阻塞式出队,获取队列头部元素,如果队列中没有元素,则此线程的等待,直到队列中有元素才执行。
poll():非阻塞式出队,当队列中没有元素,则返回null.
****************************************************************************************
1、学习AKKa
1,用actorsystem来创建actor,
ActorSystem.actorOf()是用来生成actor,
ActorSystem.actorSelection()用来查找actor(远程调用,只要查找到和调用本地服务使用是一样)
actorOf:创建一个新的Actor。创建的Actor为调用该方法时所属的Context下的直接子Actor;
actorSelection:当消息传递来时,只查找现有的Actor,而不会创建新的Actor;在创建了selection时,也不会验证目标Actors是否存在;
actorFor(已经被actorSelection所deprecated):只会查找现有的Actor,而不会创建新的Actor。
Akka 有 4 种核心的 Actor 消息模式: tell 、ask 、forward 和 pipe。
Ask:向 Actor 发送一条消息,返回一个 Future。当 Actor 返回响应时,会返回 Future。不会向消息发送者的邮箱返回任何消息。
Tell:向 Actor 发送一条消息。所有发送至 sender()的响应都会返回给发送消息的 Actor。
Forward:将接收到的消息再发送给另一个 Actor。所有发送至 sender() 的响应都会返回给原始消息的发送者。
Pipe:用于将 Future 的结果返回给 sender() 或 另外一个 Actor。如果正在使用 Ask 或是处理一个 Future,那么使用 Pipe 可以正确地返回 Future 的结果。
2、学习vertx
CommonUtils.executeWithRetry(4, 100); 错误重试
String str="1=a&2=b&3=c";
Map<String, String> paramsMap = Splitter.on("&").withKeyValueSeparator("=").split(str);
@Component
@ConditionalOnExpression("'${execution.env}'!='test'")
public class Initializer {
@PostConstruct //注解在程序加载完执行,相当于初始化。
*********************************使用InitializingBean三个地方:*****************************************************
package tech.powerjob.server.core.instance;【InstanceMetadataService】使用google 的cache,来缓存JobInfo
package tech.powerjob.server.core.scheduler【CoreScheduleTaskManager】启动一些必要的线程(定时清理,数据清理,状态检查)
package tech.powerjob.server.persistence.mongodb【GridFsManager】动态根据配置文件查询是否开启mongodb来初始化mongodb数据库
package tech.powerjob.worker【PowerJobWorker】客户端启动类
**************************文件下载到本地临时目录*********************************************
FileUtils.forceMkdirParent(tmpFile);
file.transferTo(tmpFile);
***********************************************************************
Google cache 的使用
private Cache<Long, JobInfoDO> instanceId2JobInfoCache;
创建: instanceId2JobInfoCache = CacheBuilder.newBuilder()
.concurrencyLevel(CACHE_CONCURRENCY_LEVEL)
.maximumSize(instanceMetadataCacheSize)
.softValues()
.build();
添加:instanceId2JobInfoCache.put(instanceId, jobInfoDO);
删除: instanceId2JobInfoCache.invalidate(instanceId);
*****************************【lombok】@RequiredArgsConstructor*******************************************
相当于构造器注入了,不需要@Autowired
使用说明:作用于类,用于生成包含 final 和 @NonNull 注解的成员变量的构造方法,构造参数按先后顺序。
#############################步骤@Async使用步骤2步:####################
@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolConfig {
@Bean(PJThreadPool.TIMING_POOL)
public TaskExecutor getTimingPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 4);
// use SynchronousQueue
executor.setQueueCapacity(0);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("PJ-TIMING-");
executor.setRejectedExecutionHandler(new NewThreadRunRejectedExecutionHandler(PJThreadPool.TIMING_POOL));
return executor;
}
}
@Async(value = PJThreadPool.LOCAL_DB_POOL)
public void submitLogs(String workerAddress, List<InstanceLogContent> logs) {
List<LocalInstanceLogDO> logList = logs.stream().map(x -> {
instanceId2LastReportTime.put(x.getInstanceId(), System.currentTimeMillis());
LocalInstanceLogDO y = new LocalInstanceLogDO();
BeanUtils.copyProperties(x, y);
y.setWorkerAddress(workerAddress);
return y;
}).collect(Collectors.toList());
try {
CommonUtils.executeWithRetry0(() -> localInstanceLogRepository.saveAll(logList));
}catch (Exception e) {
log.warn("[InstanceLogService] persistent instance logs failed, these logs will be dropped: {}.", logs, e);
}
}
####################################################################
本文深入分析了PowerJob的服务端启动类Initializer和客户端启动类PowerJobWorker,讲解了其初始化过程,包括日志上报、健康上报等。介绍了scheduleAtFixedRate和scheduleWithFixedDelay的区别,并探讨了客户端与服务端的Akka服务交互,如TaskTrackerActor、ProcessorTrackerActor和WorkerActor的角色与功能。此外,还提到了服务端Vert服务和日志模块的实现细节,如Actor消息模式、重试工具类及Google Cache的使用。
1607

被折叠的 条评论
为什么被折叠?



