Nginx+netty实现tcp负载均衡,获取客户端真实ip

这篇具有很好参考价值的文章主要介绍了Nginx+netty实现tcp负载均衡,获取客户端真实ip。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

nginx配置

在nginx.conf文件中,events,http同级添加配置

stream {

   upstream tcp {
       server 127.0.0.1:8888 weight=1;
       server 127.0.0.1:8889 weight=1;
  }
  server {
    listen 8880;
    proxy_pass tcp;
	proxy_protocol on;        #仅此一句重点,用以判断获取客户端真实ip
  }
}

启动nginx服务

netty代码

package com.alexyang.nettyandthread.netty2;

/**
 * @author yqc
 * @version 1.0
 * @description netty+nginx
 * @date 2023-06-30 9:22
 */

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class ServerNetty implements ApplicationRunner {
    final static Logger log = LogManager.getLogger(ServerNetty.class);

    private int port = 8888;
    private String ip = "127.0.0.1";

    public void start() throws InterruptedException {
        NioEventLoopGroup boss = null;
        NioEventLoopGroup worker = null;
        try {
            ServerBootstrap b = new ServerBootstrap();
            boss = new NioEventLoopGroup();
            worker = new NioEventLoopGroup();
            b.group(boss, worker);
            b.channel(NioServerSocketChannel.class);
            b.localAddress(port);
            b.option(ChannelOption.SO_KEEPALIVE, true);//是否开启TCP心跳机制
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            b.childHandler(new ChannelInitializer() {
                @Override
                protected void initChannel(Channel channel) throws Exception {
                    channel.pipeline().addLast("decoder",new DecodeProxy()); // 增加这个自定义的解码器
                    channel.pipeline().addLast(new ServerHandler());
                }
            });
            log.info("启动 netty 服务端");
            ChannelFuture future = b.bind(ip, port).sync();
            log.info("服务器启动成功,监听端口{}", future.channel().localAddress());
            future.channel().closeFuture().sync();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            //关闭线程组,释放资源
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }

    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("执行.............");
        start();
    }
}

package com.alexyang.nettyandthread.netty2;

/**
 * @author yqc
 * @version 1.0
 * @description nginx代理netty tcp服务端负载均衡,nginx stream要打开 proxy_protocol on; 配置
 * @date 2023-06-30 10:09
 */

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

import java.nio.charset.Charset;
import java.util.List;

/**
 * @Description nginx代理netty tcp服务端负载均衡,nginx stream要打开 proxy_protocol on; 配置
 */
public class DecodeProxy extends ByteToMessageDecoder {

    /**
     * 保存客户端IP
     */
    public static AttributeKey<String> key = AttributeKey.valueOf("IP");

    /**
     * decode() 会根据接收的数据,被调用多次,直到确定没有新的元素添加到list,
     * 或者是 ByteBuf 没有更多的可读字节为止。
     * 如果 list 不为空,就会将 list 的内容传递给下一个 handler
     *
     * @param ctx     上下文对象
     * @param byteBuf 入站后的 ByteBuf
     * @param out     将解码后的数据传递给下一个 handler
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {

        /*消息打印--------------------------*/
        byte[] bytes = printSz(byteBuf);
        String message = new String(bytes, Charset.forName("UTF-8"));
        //logger.info("从客户端收到的字符串:" + message);
        /*消息打印--------------------------*/

        if (bytes.length > 0) {

            //判断是否有代理
            if (message.indexOf("PROXY") != -1) {
                //PROXY MSG: PROXY TCP4 192.168.12.52 192.168.12.52 1096 5680\r\n
                System.out.println("PROXY MSG: " + message.substring(0, message.length() - 2));
                if (message.indexOf("\n") != -1) {
                    String[] str = message.split("\n")[0].split(" ");
                    System.out.println("Real Client IP: " + str[2]);
                    Attribute<String> channelAttr = ctx.channel().attr(key);
                    //基于channel的属性
                    if (null == channelAttr.get()) {
                        channelAttr.set(str[2]);
                    }
                }

                //清空数据,重要不能省略
                byteBuf.clear();
            }

            if (byteBuf.readableBytes() > 0) {
                //logger.info("out add!!!");
                out.add(byteBuf.readBytes(byteBuf.readableBytes()));
            }
        }
    }


    /**
     * 打印byte数组
     *
     * @param newBuf
     */
    public byte[] printSz(ByteBuf newBuf) {
        ByteBuf copy = newBuf.copy();
        byte[] bytes = new byte[copy.readableBytes()];
        copy.readBytes(bytes);
        //logger.info("字节数组打印:" + Arrays.toString(bytes));
        return bytes;
    }
}

package com.alexyang.nettyandthread.netty2;


/**
 * @description ServerHandler
 * @author yqc
 * @date 2023-06-30 9:23
 * @version 1.0
 */

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Attribute;

import java.nio.charset.Charset;

public class ServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelRegistered();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelUnregistered();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("收到链接:" + ctx.channel().remoteAddress());
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelInactive();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Attribute<String> channelAttr = ctx.channel().attr(DecodeProxy.key);
        //基于channel的属性
        if(null != channelAttr.get()){
         System.out.println("IP地址--------------- :" + channelAttr.get());
        }
        ByteBuf in = (ByteBuf) msg;
        System.out.println("收到客户端" + ctx.channel().remoteAddress().toString() + "内容:" + in.toString(Charset.forName("UTF-8")));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelReadComplete();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        ctx.fireUserEventTriggered(evt);
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelWritabilityChanged();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }
}

启动2个服务netty服务设置nginx中8888,8889端口。
使用tcp工具连接并发送数据测试

参考博客
参考链接1
参考链接2文章来源地址https://www.toymoban.com/news/detail-736409.html

到了这里,关于Nginx+netty实现tcp负载均衡,获取客户端真实ip的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 客户端负载均衡工具Ribbon

    Ribbon介绍 目前主流的负载方案分为以下两种: 集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如 Nginx)。 客户端根据自己的请求情况做负载均衡,Ribbon 就属于客户端自己做负载均衡。 Spring Cloud Ribbon是基于

    2024年02月09日
    浏览(34)
  • 原来还可以客户端负载均衡

    欢迎来到我的博客,代码的世界里,每一行都是一个故事 在数字化的舞台上,服务如同优雅的舞者,但如何让它们保持优雅的舞姿面对巨大的观众呢?这就需要一位懂得平衡的舞者——客户端负载均衡。就像是一场数字化的舞蹈,本文将带你进入这个神秘的世界,揭示客户端

    2024年02月21日
    浏览(29)
  • 客户端负载均衡策略:loadBalancer,ribbon

    客户端负载均衡是指在分布式系统中,客户端通过某种策略将请求分发到多个服务提供者实例上,以达到负载均衡和提高系统的可用性和性能。 在 Java 生态系统中,Ribbon 是一个常用的客户端负载均衡框架,它是 Netflix 开源的一部分,被广泛应用于 Spring Cloud 中。Ribbon 提供了

    2024年02月08日
    浏览(37)
  • 基于grpc-java开发的普通工程在k8s内部署多实例,如何实现客户端流量的负载均衡

    本文主要讨论通过grpc-java开发的普通的java grpc工程,以多实例的方式部署在容器编排平台kubernetes(以下简称k8s)上,如何能够实现让同样部署在k8s 集群内的客户端请求流量均衡的分发到多个grpc应用部署实例上去。 grpc服务端程序在k8s内部署的多个实例通过headless service暴露服

    2024年01月17日
    浏览(37)
  • 使用Go语言的HTTP客户端进行负载均衡

    负载均衡是分布式系统中的重要概念,它用于将流量分散到多个服务器或服务上,以实现更好的性能、可靠性和可扩展性。在Go语言中,可以使用HTTP客户端进行负载均衡,确保请求被均匀地分配到多个服务器或服务上。 下面是一个使用Go语言HTTP客户端进行负载均衡的示例:

    2024年01月21日
    浏览(38)
  • netty-发起tcp长连接(包含客户端和服务端)

    Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持。 Netty是对JDK自带的NIO的API进行封装,具有高并发,高性能等优点。 项目中经常用到netty实现服务器与设备的通信,先写服务端代码: 服务端处理类代码: 接下来 模拟 客户端: 客户端处理类代

    2024年02月12日
    浏览(32)
  • SpringBoot搭建Netty+Socket+Tcp服务端和客户端

    yml配置:    完成,启动项目即可自动监听对应端口 这里为了测试,写了Main方法,可以参考服务端,配置启动类 ,实现跟随项目启动   ......想写就参考服务端...... 有测试的,,,但是忘记截图了................

    2024年02月15日
    浏览(43)
  • 使用Netty构建TCP和UDP服务器和客户端

    Netty是一个基于Java NIO实现的网络通信框架,提供了高性能、低延迟的网络通信能力。使用Netty构建TCP和UDP服务器和客户端非常简单,下面是一个简单的示例代码: 构建TCP服务器 构建TCP客户端 构建UDP服务器 构建UDP客户端   上述示例代码中,分别定义了一个TCP服务器、TCP客户

    2024年02月16日
    浏览(37)
  • Spring Cloud(Finchley版本)系列教程(二) 客户端负载均衡Ribbon

    Spring Cloud(Finchley版本)系列教程(二) 客户端负载均衡Ribbon 目前主流的负载均衡方案有两种,一种是集中式均衡负载,在消费者与服务提供者之间使用独立的代理方式进行负载,比如F5、Nginx等。另一种则是客户端自己做负载均衡,根据自己的请求做负载,Ribbon就属于客户端自己

    2024年02月09日
    浏览(38)
  • 【kafka】Java客户端代码demo:自动异步提交、手动同步提交及提交颗粒度、动态负载均衡

    kafka版本为3.6,部署在3台linux上。 maven依赖如下: 生产者、消费者和topic代码如下: 这里先简单解释一下, kafka的topic只是一个逻辑上的概念,实际上的物理存储是依赖分布在broker中的分区partition来完成的 。kafka依赖的zk中有一个 __consumer_offsets [1]话题,存储了所有consumer和g

    2024年01月19日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包