netty集群,启动方式,SSL、堆外内存溢出

这里有些点只提供一些思路,具体实现可以自行去做。

启动方式

  • 利用注解@PostConstruct,加载启动方法上即可。
	@PostConstruct
    public void start() {
        //创建接收请求和处理请求的实例(默认线程数为 CPU 核心数乘以2也可自定义)
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup(2);
        try {
            //创建服务端启动辅助类(boostrap 用来为 Netty 程序的启动组装配置一些必须要组件,例如上面的创建的两个线程组)
            ServerBootstrap socketBs = new ServerBootstrap();
            //channel 方法用于指定服务器端监听套接字通道
            //socket配置
            socketBs.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(nettyServerChannelInitializer)
                    //ChannelOption.SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数,函数listen(int socketfd,int backlog)用来初始化服务端可连接队列,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接,多个客户端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小
                    .option(ChannelOption.SO_BACKLOG, 1000);
            //默认的心跳间隔是7200s即2小时。Netty默认关闭该功能。
            //.childOption(ChannelOption.SO_KEEPALIVE, true);
            future = socketBs.bind(8688).sync();
            future.addListener(future1 -> log.info("Netty服务端启动成功"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  • 利用ApplicationRunner接口
@Component
public class NettyServerInit implements ApplicationRunner {
    /**
     * 注入NettyServer
     */
    @Autowired
    private NettyServer nettyServer;

    @Autowired
    private AlarmHk alarmHk;

    @Override
    public void run(ApplicationArguments args) throws InterruptedException {
        nettyServer.start();
    }
}
  • 利用SpringContextUtils在启动类中启动
@Slf4j
//导入SpringContextUtils类,防止空指针
@Import(SpringContextUtils.class)
@SpringBootApplication
public class CarComputeApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CarComputeApplication.class);
    }
    public static void main(String[] args) throws UnknownHostException, InterruptedException {
        ConfigurableApplicationContext application = SpringApplication.run(CarComputeApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = env.getProperty("server.servlet.context-path");
        log.info("\n----------------------------------------------------------\n\t" +
                "Application is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port + path + "/\n\t" +
                "External: \thttp://" + ip + ":" + port + path + "/\n\t" +
                "----------------------------------------------------------");
        NettyServer nettyServer = SpringContextUtils.getBean(NettyServer.class);
        nettyServer.start();
    }
}

netty集群

可以利用redis或者zookeeper来实现
这里只讲一下redis的用法,每个服务端都缓存自己的客户端到本地,用通道id做唯一标识,利用redis发布订阅的能力,当服务端发现客户端A要找的客户端B不在本服务的时候,通知redis,redis根据客户端id找到服务端,然后通知服务端,服务端拿到客户端A的信息,发送给客户端B。
具体可参考这里:Netty集群部署实现跨服务端通信的落地方案

SSL

1、如果是websocket可以利用SSL保证单方面验证,将SSL证书配置到nginx即可实现wss连接。
参考链接:这里是原生的websocket,没有用netty集成,做参考即可

2、如果是soket,可以利用SSL保证双方验证,客户端和服务端都配置证书,利用SslContext实现。
核心代码:

@Component
public class NettyServerChannelInitializer extends ChannelInitializer<SocketChannel> {

    @Autowired
    private NettyServerHandler nettyServerHandler;

    @Autowired
    private HeartBeatServerHandler heartBeatServerHandler;

    @Override
    protected void initChannel(SocketChannel ch) throws SSLException {
        ChannelPipeline pipeline = ch.pipeline();
        File certChainFile = new File("E:\\itstack\\GIT\\itstack.org\\itstack-demo-netty\\itstack-demo-netty-2-13\\src\\main\\java\\org\\itstack\\demo\\netty\\ssl\\client\\client.crt");
        File keyFile = new File("E:\\itstack\\GIT\\itstack.org\\itstack-demo-netty\\itstack-demo-netty-2-13\\src\\main\\java\\org\\itstack\\demo\\netty\\ssl\\client\\pkcs8_client.key");
        File rootFile = new File("E:\\itstack\\GIT\\itstack.org\\itstack-demo-netty\\itstack-demo-netty-2-13\\src\\main\\java\\org\\itstack\\demo\\netty\\ssl\\client\\ca.crt");
        SslContext sslCtx = SslContextBuilder.forClient().keyManager(certChainFile, keyFile).trustManager(rootFile).build();
        pipeline.addLast(sslCtx.newHandler(ch.alloc()));
        String delimiter = "@_";
        pipeline.addLast(new DelimiterBasedFrameDecoder(1024*8, Unpooled.wrappedBuffer(delimiter.getBytes())));
        pipeline.addLast(new DelimiterBasedFrameEncoder(delimiter));
        //设置心跳机制 0永不超时
        pipeline.addLast(new IdleStateHandler(10,0,0, TimeUnit.SECONDS));
        pipeline.addLast(new StringDecoder(Charset.forName("UTF-8")));
        pipeline.addLast(new StringEncoder(Charset.forName("UTF-8")));
        pipeline.addLast(heartBeatServerHandler);
        pipeline.addLast(nettyServerHandler);
    }
}

具体可参考:Netty基于SSL实现信息传输过程中双向加密验证

堆外内存溢出

简单介绍一下:主要引起的原因是我们使用了netty的引用计数对象,结果却没有释放造成的,并且这个隐藏的问题不会立刻显现出来,所以如果我们不对项目进行压测,很难会发现这个问题。
举个例子,ByteBuf就使用了引用计数对象,在handler中,如果不主动释放,时间长了就会产生这个问题,还有涉及到http相关的协议通信也会涉及到。
所以,在使用完消息之后,如果你不确定是否需要释放,**可以直接在finally里调用ReferenceCountUtil.release(msg)**方法,这个方法判断如果引用了就释放,如果没引用就跳过。
同时,你还可以进行堆外内存监控——具体描述可参考这里

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值