上面我为大家引入了执行器端的服务器组件,并且讲解到了最核心的EmbedServer类,该类就是执行器端服务器的启动类,并且是以Netty构建的服务器。请看下面的代码块。
public class EmbedServer {
private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);
// 启动执行器的内嵌服务器,其中address参数就是执行器的IP地址,要封装到RegistryParam对象中发送给调度中心的
// port为Netty构建的服务器要使用的端口号
// appname为执行器配置文件中用户设定的执行器的唯一标识,时也要封装到RegistryParam对象中发送给调度中心的
public void start(final String address, final int port, final String appName) {
// 下面都是netty的知识,学习过netty的应该都清楚,就不再一一解释了。
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
// 心跳检测
.addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))
// http的编解码器,该处理器既是出站处理器,也是入站处理器
.addLast(new HttpServerCodec())
// 这个处理器从名字上就能看出来,是聚合消息的,当喘气的http消息过大时,会被拆分开,这里添加这个处理器
// 就是把拆分的消息再次聚合起来,形成一个整体再向后传递
// 该处理器是个入站处理器
.addLast(new HttpObjectAggregator(5 * 1024 * 1024))
// 添加入站处理器,在该处理器中执行定时任务
// 现在,EmbedHttpServerHandler这个消息处理器,就要实现最核心的功能了
.addLast(new EmbedHttpServerHandler());
}
})
.childOption(ChannelOption.SO_KEEPALIVE,true);
// 绑定端口号
ChannelFuture future = bootstrap.bind(port).sync();
// 注册执行器到调度中心
startRegistry(appName,address);
// 等待关闭
future.channel().closeFuture().sync();
}catch (InterruptedException e){
logger.info(">>>>>>>>>>>>>>>>>>>>> yy-job remoting server stop");
}finally {
try {
// 优雅释放资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}catch (Exception e){
logger.error(e.getMessage(), e);
}
}
}
}
在上面的代码块中,我为大家展示了我自己构建的Netty的服务端,可以看到,这还是个http的服务端。因为在前 几章我就为大家讲解了,调度中心是通过http协议向执行器的服务器发送消息的,因此,执行器端内嵌的应该是一 个http服务器。既然是http服务器,就应该使用http的编解码器,在上面的代码块中,我为Netty服务端添加了四 个消息处理器,第一个处理器的作用是心跳检测,这也是Netty的知识点,就不再细说了。之后的 HttpServerCodec和HttpObjectAggregator服务器都是为http服务的,这里我也就不再详细讲解了。最后添加的那个EmbedHttpServerHandler处理器,才是我的服务端真正需要 的消息处理器,也就是我的业务处理器,当接收到调度中心发来的消息后,定时任务该如何执行,这个核心逻辑就 要在EmbedHttpServerHandler处理器中的channelRead方法中实现了。接下来,我就要为自己的程序具体编写该 处理器的逻辑了。
但是在我开始编写该处理器的逻辑之前,我想请大家稍微思考一下,刚才我跟大家说,在 EmbedHttpServerHandler处理器的channelRead方法中,被调度中心调度的定时任务就要开始执行了,这是不是 就意味着在该方法内定时任务会被执行。如果有很多定时任务,调度中心发送过来的消息都会传递到该处理器内, 被channelRead方法处理,这就意味着该执行器部署的很多定时任务都会在该方法内执行。如果大家对Netty足够 精通的话,肯定知道channelRead方法其实还是归Netty中的单线程执行器来调度的,而单线程执行器所做的工作 非常做,其中最重要的就是处理Selector上接收到的IO事件。本来单线程执行器的任务就比较多,处理完一次IO事 件后,就会紧接着处理下一个IO事件,因为调度中心会一直向执行器发送消息呀。但是现在单线程执行器在接收 到消息后,不仅要把消息传递到EmbedHttpServerHandler处理器的channelRead方法内,还要在该方法内执行对 应的定时任务,这么做对单线程执行器显然是一种拖累,就让单线程执行器迅速处理IO事件就行了。因此,这种 情况下,我们一般会创建一个业务线程池供EmbedHttpServerHandler处理器使用,定时任务也由业务线程池来执 行,以此达到和单线程执行器明确分工的效果。所以,EmbedServer类还应该小小地重构一下,添加一个线程 池,然后将这个线程池交给EmbedHttpServerHandler处理器使用。下面就是我重构好的EmbedServer类。
public class EmbedServer {
private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);
// 启动执行器的内嵌服务器,其中address参数就是执行器的IP地址,要封装到RegistryParam对象中发送给调度中心的
// port为Netty构建的服务器要使用的端口号
// appname为执行器配置文件中用户设定的执行器的唯一标识,时也要封装到RegistryParam对象中发送给调度中心的
public void start(final String address, final int port, final String appName) {
// 下面都是netty的知识,学习过netty的应该都清楚,就不再一一解释了。
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
// 这就是我先创建好的业务线程池
ThreadPoolExecutor bizThreadPool = new ThreadPoolExecutor(
0,
200,
60L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(2000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {

最低0.47元/天 解锁文章

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



