0
0
2
0
专栏/.../

TiDB 如何在 LVS FULL NAT 模式下显示客户端真实 IP

 mydb  发表于  2022-01-24

【是否原创】是
【首发渠道】TiDB 社区
【正文】

作者:
靳献旗 汽车之家 DBA,TUG 2021 MVA

1.背景

公司 TiDB 集群前端负载均衡器使用的是 LVS,FULL NAT 模式, 这种模式最大的一个问题是:RealServer 无法获得用户 IP ,即在 TiDB 数据库中无法显示客户端真实 IP,显示的是 LVS 服务器上的一个 IP。很多时候,在排查 TiDB 问题时,需要获取客户端真实 IP,这给我们带来了一定困难。本文简单讲述下如何在 TiDB-Server 端显示客户端真实 IP 的方法和工作原理。

2.FULL NAT 概述

本文主要针对 LVS FULL NAT 场景,所以本节简单介绍下其工作原理、优缺点及解决办法。本文中使用到的 IP 均已脱敏处理。

2.1工作原理

image


如图所示,FULLNAT 模式是 NAT 的一种扩展,不仅仅将目的 IP 地址进行替换,同时还将源 IP 地址进行了替换,这样做的好处是将 real server 从 virtual server 的后端网络中解放出来,不再要求与 virtual server 位于同一子网内。工作过程如下:

(1) 当客户端发出一个请求的数据包到达负载均衡器后,负载均衡器会对请求数据包同时做 SNAT 和 DNAT,将请求数据包修改为:{ LVS 出口 IP 地址 192.168.2.101、LVS 端口号、LVS 的 MAC 地址 } -> { 某台 Tidb-Server 的 IP 地址、某台 Tidb-Server 的端口号、某台 Tidb-Server 的 MAC 地址 }。

(2) 这样负载均衡器就可以独立的和真实服务器进行数据包的传送。

(3) 真实服务器收到请求的数据包,返回响应的数据包:{ 某台 Tidb-Server 的 IP 地址、某台 Tidb-Server 的端口号、某台 Tidb-Server 的 MAC 地址 } -> { LVS 的入口 IP 地址、LVS 端口号、LVS 的 MAC 地址 } 。此时在真实服务器上查看 TCP 连接为:DIP -> RIP。

(4) 当返回的数据包到达负载均衡器后,负载均衡器将返回数据包再次同时做 DNAT 和 SNAT。

(5) 负载均衡器返回数据包给客户端。

FULL NAT 模式下报文变化:

发送端 接收端 备注
192.168.1.1 (CIP) 192.168.2.100 (VIP)
192.168.2.101 (DIP) 192.168.3.1 (RIP) SNAT+DNAT
192.168.3.1 (RIP) 192.168.2.101 (DIP)
192.168.2.100 (VIP) 192.168.1.1 (CIP) DNAT+SNAT

说明:

缩写 说明
CIP 客户端的地址
VIP LVS虚拟地址
RIP 真实服务器,即TiDB Server节点的地址
DIP LVS出口地址
SNAT 来源地址转换
DNAT 目的地址转换

2.2优缺点

  • 优点
    扩展性好,负载均衡器和真实服务器可以跨 VLAN 部署
  • 缺点
    真实服务器无法获取客户端真实 IP

2.3解决办法

针对上一小节中提到的 FULL NAT 模式无法获取客户端真实 IP 的问题有没有解决办法?答案是有。

TOA 名字全称是 tcp option address,是 FULL NAT 模式下能够让后端服务器获取 ClientIP 的一种实现方式,它的基本原理比较简单:

(1) 客户端用户请求数据包到达 LVS 时,LVS 在数据包的 tcp option 中插入 src ip 和 src port 信息

(2) 数据包到达后端服务器(装有 toa 模块)后,应用程序正常调用 getpeername 系统函数来获取连接的源端 IP 地址

(3) 由于在 toa 代码中 hook(修改)了 inet_getname 函数(getpeername 系统调用对应的内核处理函数),该函数会从 tcp option 中获取 LVS 填充的 src 信息

(4) 这样后端服务器应用程序就获取到了真实客户端的 ClientIP,而且对应用程序来说是透明的。

3.实战

3.1测试环境

组件名 版本
CentOS CentOS Linux release 7.4.1708 (Core)
TiDB 5.1.3

3.2部署步骤

(1) 升级 TiDB 到 5.0 版本

因为参数 enable-tcp4-only 是从 5.0 开始引入的,因此,如果集群版本低于 5.0 ,需要先升级集群,本文测试使用的版本是 5.1.3。

(2) 开启 enable-tcp4-only

所有 TiDB Server 节点需要开启 enable-tcp4-only,参考步骤如下

a) 编辑集群拓扑文件

tiup cluster edit-config stale_read_test

server_configs:

tidb:

enable-tcp4-only: true     # 添加或者修改这一行配置为 true

b) 重新加载配置

tiup cluster reload stale_read_test -R tidb

c) 检查配置是否生效

select * from information_schema.cluster_config where TYPE=‘tidb’ and key=‘enable-tcp4-only’;

参数说明

enable-tcp4-only 从 v5.0 版本开始引入
控制是否只监听 TCP4。
默认值:false
当使用 LVS 为 TiDB 做负载均衡时,可开启此配置项。这是因为 LVS 的 TOA 模块可以通过 TCP4 协议从 TCP 头部信息中解析出客户端的真实 IP。

(3) 安装 ip_vs_ca 模块
需要在所有 TiDB Server 服务器上安装 ip_vs_ca 模块

从 git 上(https://github.com/yubo/ip_vs_ca)下载安装包 ip_vs_ca-master.zip

yum -y install cmake

unzip ip_vs_ca-master.zip

cd ip_vs_ca-master

cmake .

cd src/

make

insmod ./ip_vs_ca.ko

cp -fr /root/ip_vs_ca-master /usr/local/src/

echo insmod /usr/local/src/ip_vs_ca*/src/ip_vs_ca.ko >> /etc/rc.local

查看计数器和版本信息

cat /proc/net/ip_vs_ca_stats

(4) 测试

客户端通过 LVS VIP 连接到 TiDB 集群后,在 TiDB 端通过 show processlist 查看客户端 IP。

3.3实际效果

未开启 enable-tcp4-only 的效果

dba@192.168.2.100:4000 : (none) > select * FROM information_schema.cluster_processlist\"G
*************************** 1. row ***************************
INSTANCE: 192.168.3.1:10080
      ID: 15
    USER: dba
    HOST: 192.168.2.101:5394 #LVS DIP
      DB: NULL
 COMMAND: Query
    TIME: 0
   STATE: autocommit
    INFO: select * FROM information_schema.cluster_processlist
  DIGEST: b1e38e59fbbc3e2b35546db5c8053040db989a497ac6cd71ff8dd4394395701a
     MEM: 4
    DISK: 0
TxnStart: 01-19 11:25:30.423(430587964404006913)
1 row in set (0.00 sec)

开启 enable-tcp4-only 的效果
show processlist;

dba@192.168.2.100:4000 : (none) > select * FROM information_schema.cluster_processlist\"G
*************************** 1. row ***************************
INSTANCE: 192.168.3.1:10080
      ID: 190927
    USER: dba
    HOST: 192.168.1.1:13557   #客户端真实IP 
      DB: NULL
 COMMAND: Query
    TIME: 0
   STATE: autocommit
    INFO: select * FROM information_schema.cluster_processlist
  DIGEST: b1e38e59fbbc3e2b35546db5c8053040db989a497ac6cd71ff8dd4394395701a
     MEM: 0
    DISK: 0
TxnStart: 01-19 08:53:36.472(430585575236435969)
1 row in set (0.00 sec)

慢日志

# Time: 2022-01-19T09:04:18.429228693+08:00
# Txn_start_ts: 0
# User@Host: dba[dba] @ 192.168.1.1 [192.168.1.1] #客户端真实IP
# Conn_ID: 190927
# Query_time: 10.00093258
# Parse_time: 0.000098847
# Compile_time: 0.000132781
# Rewrite_time: 0.000073525
# Optimize_time: 0.00001867
# Wait_TS: 0.000006643
# Is_internal: false
# Digest: a0adeeb79b71315ac13a77f3f11162106b5ec7b48212cf17c20c754263ab9228
# Num_cop_tasks: 0
# Prepared: false
# Plan_from_cache: false
# Plan_from_binding: false
# Has_more_results: false
# KV_total: 0
# PD_total: 0.000004254
# Backoff_total: 0
# Write_sql_response_total: 0.000003211
# Succ: true
# Plan: tidb_decode_plan('gQHwVTAJM18zCTAJMQlzbGVlcCgxMCktPkNvbHVtbiMxCTEJdGltZToxMHMsIGxvb3BzOjIsIENvbmN1cnJlbmN5Ok9GRgkwIEJ5dGVzCU4vQQoxCTI1XzQJAVAQcm93czoZQxAuMDTCtRlHIAlOL0EJTi9BCg==')
# Plan_digest: a55eaee1d30304ad05500afbbfff1409ce22376e0f062c0d06ff34b8ed9c2b47
select sleep(10);

general log

[2022/01/19 11:04:42.863 +08:00] [INFO] [session.go:2796] [GENERAL_LOG] [conn=219317] [user=dba@192.168.1.1] [schemaVersion=1007] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [current_db=db23] [txn_mode=PESSIMISTIC] [sql="select * from t1"]

从以上信息可以看到,无论是 show processlist,还是慢日志,还是 general log ,都可以看到客户端真实 IP 地址,为排查问题提供了很大便利。

4.总结

公司私有云提供统一的 LVS 服务,为了减少维护成本,TiDB 集群统一使用之家云 LVS 作为负载均衡器。由于 LVS FULL NAT 模式的工作原理决定了在 TiDB 端无法看到客户端真实 IP,本文主要讲解了 TiDB 在这种工作模式下如何查看客户端真实 IP 的解决方法,希望能够帮助需要的同学。

参考资料

https://docs.pingcap.com/zh/tidb/v5.1/tidb-configuration-file/

https://github.com/pingcap/tidb/pull/21552

https://www.jianshu.com/p/e770a11481e9

https://github.com/yubo/ip_vs_ca

https://zhuanlan.zhihu.com/p/364703954

https://github.com/alibaba/LVS/tree/master/docs

0
0
2
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论