跳至正文

V2Ray 多协议多服务器情况使用 HAProxy 负载均衡

V2Ray 自带的负载均衡策略只有随机选择,对于不稳定的网络而言,显然是不够的

ShadowSocks 可以使用 HAProxy 进行负载均衡,但是 V2Ray 具有多种协议,显然是不可行的

我们可以利用 Docker 的特性完成一个使用 HAProxy 进行负载均衡且可以自动维护可用节点列表(利用 HAProxy 健康检查功能 与 V2Ray 任意门)的网络

NOTE:这篇文章所有代码几乎全部复制即可用,但是我还是强烈建议仔细阅读注释

负载均衡网络概述

HAProxy 可以处理 TCP 数据流,最近也添加了对 Socks 的支持(尽管我不知道怎么配置)

V2Ray 也支持 TCP 协议

所以,我们可以在出口处创建多个独立的 V2Ray Docker 容器用来把 V2Ray 的其他协议都转换为 TCP 协议(或者直接使用 HTTP 代理),然后在使用 HAProxy 对其进行负载均衡。

集群配置

代码中有大量注释(几乎包含每一行参数),请仔细阅读

Docker 集群配置

这里为了方便。我们使用 Docker Compose 进行配置

/home/$USER/.config/v2ray/docker/docker-compose.yml

version: "3"

services:
  v2ray:  # 入口代理,也就是为用户直接提供 HTTP、Socks 等代理协议的客户端
    image: v2ray/official  # 使用 V2Ray 稳定版镜像
    container_name: v2ray  # 为容器命名为 V2Ray
    restart: unless-stopped  # 开机自启
    depends_on:
      - haproxy  # 待 HAProxy 启动后再启动
    ports:
      - "127.0.0.1:1080:1080"  # 为 Docker 容器打开 1080 本地端口的 TCP 协议访问
      - "127.0.0.1:1080:1080/udp"  # 1080本地端口的 UDP 协议访问
      - "8118:8080"  # 为局域网打开 8118 端口的 TCP 访问
      - "8118:8080/udp"  # 为局域网打开 8118 端口的 UDP 访问
    volumes:
      - /home/$USER/.config/v2ray/docker/v2ray/config.json:/etc/v2ray/config.json  # 将宿主机上相对应的配置文件映射到 Docker 容器中
    networks:
      - app-network  # 使用名为app-network 的自定义 Docker 网络

# 解释过的参数请对照理解
  haproxy:
    image: haproxy
    container_name: haproxy
    restart: unless-stopped
    expose:
      - "8388"  # 允许在 app-network 网络中发起的 8338 端口访问 https://docs.docker.com/compose/compose-file/#expose
    ports:
      - "127.0.0.1:8080:8080"  # 为网络管理页面做 8080 端口映射
    volumes:
      - /home/$USER/.config/v2ray/docker/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    networks:
      - app-network

  v2ray_out_0_tcp:  # 处理出口流量,也就是把负载均衡过的 TCP 流量用其他协议发给对应的服务器
    image: v2ray/official
    container_name: v2ray_out_0_tcp
    restart: unless-stopped
    expose:
      - "80"
      - "1080"
    volumes:
      - /home/$UAER/.config/v2ray/docker/v2ray/config_0_tcp.json:/etc/v2ray/config.json
    networks:
      - app-network

  v2ray_out_0_quic:
    image: v2ray/official
    container_name: v2ray_out_0_quic
    restart: unless-stopped
    expose:
      - "80"
      - "1080"
    volumes:
      - /home/$USER/.config/v2ray/docker/v2ray/config_0_quic.json:/etc/v2ray/config.json
    networks:
      - app-network

  v2ray_out_1_tcp:
    image: v2ray/official
    container_name: v2ray_out_1_tcp
    restart: unless-stopped
    expose:
      - "80"
      - "1080"
    volumes:
      - /home/$USER/.config/v2ray/docker/v2ray/config_out_1_tcp.json:/etc/v2ray/config.json
    networks:
      - app-network

  v2ray_out_2_tcp:
    image: v2ray/official
    container_name: v2ray_out_2_tcp
    restart: unless-stopped
    expose:
      - "80"
      - "1080"
    volumes:
      - /home/$USER/.config/v2ray/docker/v2ray/config_2_tcp.json:/etc/v2ray/config.json
    networks:
      - app-network

networks:
  app-network:  # 自定义一个 Docker 网络
    driver: bridge  # 网桥网络
    driver_opts:
      com.docker.network.bridge.name: v2ray_bridge  # 为网桥自定义一个名字(不设置就是一个随机的字符串),方便主机防火墙管理

V2Ray 入口配置

这一部分可以部分参考Docker 部署 V2Ray

我们使用 V2Ray 的 TCP 协议作为中间协议(方便 HAProxy 负载均衡)

/home/$USER/.config/v2ray/docker/v2ray/config.json

{
  "inbounds": [
    {
      "port": 1080,
      "listen": "0.0.0.0",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      },
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "listen": "0.0.0.0",
      "port": 8080,
      "protocol": "http",
      "settings": {
        "timeout": 0,
        "allowTransparent": false,
        "userLevel": 0
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vmess",
      "tag": "proxy",
      "settings": {
        "vnext": [
          {
            "address": "haproxy",  
            "//": "Docker 内部的路由会把 haproxy 解析为正确的 IP 地址",
            "port": 8388,
            "//": "这里的演示用 HAProxy 配置文件用的是 8388 端口",
            "users": [
              {
                "alterId": 64,
                "id": "2279f418-5be1-48db-92e8-c80eae89ee28",  
                "//":  "用于容器集群内部的网络通讯,注释记得删了",
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp"
      },
      "mux": {
        "enabled": false,
        "concurrency": 32,
        "//": " 在这里开 mux 没有用,但是单主机 mux 可以明显提高速度,这种情况下应该在出口端配置 mux"
      }
    },
    {
      "protocol": "freedom",
      "tag": "direct",
      "settings": {}
    }
  ],
  "routing": {
    "//": "路由就按照自己平常的习惯配置,比如全局代理还是绕过大陆网址什么的"
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "outboundTag": "proxy",
        "domain": ["google.cn"]
      },
      {
        "type": "field",
        "outboundTag": "direct",
        "domain": [
          "geosite:cn",
          "baidupan.com",
          "lanzous.com"
        ]
      },
      {
        "type": "field",
        "outboundTag": "direct",
        "ip": ["geoip:private", "geoip:cn", "192.168.0.0/24"]
      }
    ]
  }
}

HAProxy 负载均衡配置

这一部分配置可以参考用 HAProxy 为 ShadowSocks 加速

HAProxy 健康检查参考资料:HAProxy 进阶使用技巧官方文档

/home/$USER/.config/v2ray/docker/haproxy/haproxy.cfg

defaults
    mode                    tcp
    option                  dontlognull
    timeout connect         10s
    timeout client          1m
    timeout server          1m

#---------------------------------------------------------------------

frontend v2ray-in
    bind	0.0.0.0:8388
    default_backend	v2ray-out

#---------------------------------------------------------------------

backend	v2ray-out
    balance	leastconn
    option httpchk GET http://google.com/generate_204 HTTP/1.1\r\nHost:\ google.com\r\n
    server	server1_name	v2ray_out_0_tcp:1080  check port 80 
    # 这里的 v2ray_out_0_tcp,Docker 会自动解析为正确的 IP
    # check 表示启用监控,port 80 表示使用 80 端口进行可用性监控
    server	server2_name	v2ray_out_0_quic:1080  check port 80
    server	server3_name	v2ray_out_1_tcp:1080  check port 80
    server	server4_name	v2ray_out_2_tcp:1080  check port 80

#---------------------------------------------------------------------

listen  admin_stats  # 网页管理页面
    bind 0.0.0.0:8080  # 如果在前面你是跟我相同配置的端口映射,启动容器后访问 http://127.0.0.1:8080/haproxy
    mode http
    log 127.0.0.1 local0 err
    stats refresh 10s
    stats uri /haproxy
    stats realm welcome login\ Haproxy
    stats hide-version
    stats admin if TRUE

V2Ray 出口配置

配置大同小异,以 v2ray_out_0_tcp 为例

/home/$UAER/.config/v2ray/docker/v2ray/config_0_tcp.json

{
  "inbounds": [
    {
      "port": 1080,
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "2279f418-5be1-48db-92e8-c80eae89ee28",
            "//": "这里填你自己的 Docker 网络内部的中间 V2Ray TCP 协议用的 UUID",
            "alterId": 64,
            "security": "none",
            "level": 0
          }
        ]
      }
    },
    {
      "protocol": "dokodemo-door",
      "//": "这里利用任意门将 204 流量转发到 google 实现对节点可用性的监控"
      "port": 80,
      "settings": {
        "address": "google.com",
        "port": 80,
        "network": "tcp,udp",
        "timeout": 300
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vmess",
      "tag": "proxy",
      "settings": {
        "vnext": [
          {
            "address": "example.com",
            "port": 1080,
            "//": "这里填你自己的服务器的 IP 和端口",
            "users": [
              {
                "alterId": 64,
                "id": "8a21a0a7-6392-4f96-a6f4-22a792bd1baf",
                "//": "这里填你自己访问服务器用的 UUID"
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp"
      },
      "mux": {
        "//": "我们可以在出口处聚合一下 TCP 连接,实测在低速网络下效果非常显著,代理网络能够更加稳定 https://guide.v2fly.org/advanced/mux.html"
        "enabled": true,
        "concurrency": 64
      }
    },
    {
      "protocol": "freedom",
      "tag": "direct",
      "settings": {}
    }
  ],
  "routing": {
    "//": "我们已经在 V2Ray 入口配置里配置了路由,这里的路由可以不设置,以提高效率,就好象服务端一样,我这里有只是为了放注释 2333"
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "outboundTag": "direct",
        "ip": ["geoip:private"]
      }
    ]
  }
}

运行集群

以下命令必须要在 docker-compose.yml 文件相对应的目录下才能正常执行

docker-compose up -d  # 运行集群,“-d”是后台运行。如果要调试代码,不加“-d”即可
docker-compose stop  # 停止集群

结语

Docker 配置灵活方便,是不错的应用容器。

这里主要需要注意两点:

  1. Docker Compose 配置里的 expose 参数
  2. Docker Compose 以服务名作为路由,例如 docker-compose.yml 配置文件开头的 “services”(找不到可以搜索一下该网页)

《V2Ray 多协议多服务器情况使用 HAProxy 负载均衡》有8个想法

  1. 我只知道用haproxy负载均衡两个ss或者ssr可以达到一定的网速叠加效果,不知道v2ray有没有办法实现?

    1. 原理是一样的,我这里提出的方案在多线程下可以网速叠加。
      当然单线程下载是不行的(我也没听说过哪个负载均衡工具可以实现)

  2. Pingback: WebSocket+TLS+CDN+Web,Apache2 部署V2Ray - xzOS

  3. 1、HAProxy用在V2Ray链路中间不合适,这样会要求V2Ray ClientServer的所有配置全部相同,否则会报错。
    正确应该是 App HAProxy V2ray Client V2Ray Server。

    2、HAProxy使用的心跳机制,没有验证过,如果只是TCP/UDP check,则没有太多用处。原本的V2Ray banancer作者设计的也不错。

    3、如果可以负载均衡不同链路,比如 HAProxyV2Ray+SSR,还是有价值的。但链路持续稳定性对于负载均衡评估是一个较大的难点。

    4、增加的响应可能会导致UDP包出现更多延时,对游戏不利。需要单独处理。

    1. 1. 赞同,但是由于HAProxy 限制,用来负载均衡 HTTP 代理(不过也可以之后再集中转换)
      2. 使用心跳机制是为了确认线路是否断线
      3. 链路稳定性可以参考 HAProxy 官方文档选择相应的负载均衡模式(有模式可以保证,但是我需要的是减少掉包率与尽快的传输速率(我的线路速率差异较大),所以没有选择那个)
      4. 玩游戏没怎么考虑(我的世界可以玩,但是如果玩的是对延时要求高的,建议使用专业的加速器,网络优化要考虑很多方面,个人可能需要承担较高金钱负担)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

🌍 Language