【集群】部署LVS-DR群集

news2024/11/25 6:54:13

文章目录

  • 一、LVS-DR工作原理
    • 1. 数据包流向分析
    • 2. DR模式的特点
    • 3. ARP 解析问题
      • 3.1 问题1:ip地址冲突
      • 3.2 问题2:真实服务器的第二次ARP请求
      • 3.3 解决ARP的两个问题的设置方法
  • 二、LVS-DR部署过程
    • 1. 配置环境
    • 2. 部署服务器
      • 2.1 环境配置
      • 2.2 LVS-DR调度器
      • 2.2 Web服务器1(192.168.145.30)配置
      • 2.3 Web服务器2(192.168.145.45)配置
      • 2.4 使用其他机器测试
  • 三、总结
    • 1. LVS 调度算法
    • 2.NAT模式配置注意点
    • 3.DR模式配置注意点


一、LVS-DR工作原理

1. 数据包流向分析

在这里插入图片描述

  (1)客户端发送请求到 Director Server (负载均衡器),请求的数据报文(源IP地址是 CIP,目标IP地址是VIP)到达内核空间。

  (2)Director Server 和 Real Server 在同一个网络中,数据通过二层数据链路层来传输。

  (3)内空间判断数据包的目标IP地址是本机VIP,此时IPVS(IP拟服务器)比对包的务是否是集群服务,是集群服务就重新封装数据包。修改源 MAC 地址为 Directo Sertver 的MAC地址,修改目标 MAC 地址为 Real Server 的 MAC 地址,源IP地址与目标IP地址没有改变,

  (4)到达 Real Server 的请求报文的 MA 地址是自身的 MAC 地址,就接收此报文。数据包重新封装报文(源IP地址为IP地址,目标 IP地址为 VIP)将响应报文通过 lo 接口传送给物理网卡,然后向外发出。

  (5)Real server 直接将响应报文传送到客户端。

2. DR模式的特点

  (1)Director server和 Real server必须在同一个物理网络中。

  (2)Real Server可以使用私有地址,也可以使用公网地址。如果使用公网地址,可以通过互联网对RIP进行直接访问。

  (3)Director server作为群集的访问入口,但不作为网关使用。

  (4)所有的请求报文经由 Director server,但回复响应报文不能经过 Director server。

  (5)Real server的网关不允许指向Director server IP,即Real Server发送的数据包不允许经过 Director Server。

  (6)Real server 上的lo接口配置VIP 的IP地址。

3. ARP 解析问题

3.1 问题1:ip地址冲突

问题描述

  当公网中的用户发起请求发送至路由器中,此时肯定需要走的是负载均衡器这台服务器,而不是走的真实服务器1。

  这里就会出现一个问题,因为内网在转发数据帧的时候即使用ARP(广播)来查询目标MAC地址的时候目标ip地址就是vip地址(即在DR负载均衡服务器那个集群中)。负载均衡服务器与节点服务器都要配置相同的vip地址,所以这里就会出现混乱。

  如果此时ARP解析,解析的是真实服务器1,那么从外网中进来的业务请求就不会经过负载均衡器而是直接交给真实服务器,如此实现不了负载均衡的效果那么我们怎么解决呢?

解决方式

  那么我们只需要让在ARP响应的时候真实服务器1不进行响应即可。使用虚接口lo:0承载VIP地址,设置内核参数arp_ipnore=1,系统请求只响应目的IP地址为本地IP地址的ARP请求。

  RealServer返回报文(源IP地址是VIP地址)经过路由器转发,重新封装报文时,需要先获取路由器的MAC地址。发送ARP请求时,Linux,默认使用IP包的源IP地址(即VIP)作为ARPi请求包中的源IP地址,而不使用发送接口的IP地址(如:ens33接口)。

  路由器收到ARP请求后,将更新ARP表项,原有的VIP对应Director的MACA地址表会被更新为VIP对应RealServer的MAC地址。

3.2 问题2:真实服务器的第二次ARP请求

问题描述

  真实服务器想要将数据帧发送给路由器的时候,源ip地址变成虚拟ip地址,目标ip地址变成用户的ip地址,实际上只是做了一个源目转换。

  根据三层转发原理可以知道通过改变MAC地址来进行数据帧的转发,那么真实服务器想要将返回的信息发送给用户就必须要经过路由器。路由器的ip地址真实服务器是肯定知道的,因为在同一个网段,但是它不知道路由器的MAC地址,那么就会进行第二次ARP请求(广播)。

  而此时的ARP广播的源地址却是lo:0的IP地址(VIP地址),且在进行泛洪的时候会带上真实服务器的源MAC地址因为第一次ARP请求的时候我们好不容易让路由器去识别负载均衡器上的MAC地址,在真实服务器进行第二次ARP请求的时候,路由器这边会发现ip地址已经记录过了,这里又来了一个相同的请求,但MAC地址不一致那么就要更新,会把原来vip地址所对应的MAC地址更新成真实服务器的MAC地址,那么以后再从用户端发送来的请求又会再次的发送给真实服务器,不经过负载均衡器,导致负载均衡失效。

解决方法

  对节点服务器进行处理,修改其内核,让系统不适用ip包的源地址来设置ARP请求的源地址,而选择发送接口的ip地址,即数据帧先从lo:0出去到达ens33后再去到路由器,设置了这条内核信息后,就不会再使用lo:0的虚拟ip地址了而是使用ens33的真实ip地址发送到路由器中如此,就不会和负载均衡的vip冲突,真实服务器又知道如何去到路由器。

3.3 解决ARP的两个问题的设置方法

修改/etc/systctl.conf文件

net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.all.arp_ignore = 1

使服务器只响应目的的地址为物理网卡的ipd地址为ARP请求报文。

net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2

使服务器使用发送报文的网卡的IP地址做ARP请求报文的源IP地址。

二、LVS-DR部署过程

  为了进一步提高公司网站的负载能力,公司决定扩展现有的网站平台,基于LVS构筑负载均衡群集。考虑到群集的访问效率,管理员准备采用LVS群集的DR模式,数据文件存放在tomcat服务器中。

1. 配置环境

在这里插入图片描述

###LVS-DR调度器
	ens32	 	192.168.145.15
	ens32:0 	192.168.145.20
	
###Web节点服务器1
	ens33		192.168.145.30
	lo:0 		192.168.145.20
	
###Web节点服务器2
	ens33		192.168.145.45
	lo:0 		192.168.145.20
	
###tomcat多实例服务器
	ens33		192.168.145.60

2. 部署服务器

2.1 环境配置

  前提是Web服务器1和Web服务器2已经搭建了七层代理服务器,tomcat服务器已经搭建多实例,详细搭建过程见 【集群】LVS负载均衡群集。

2.2 LVS-DR调度器

环境配置

[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]#  setenforce 0
[root@localhost ~]# modprobe ip_vs
[root@localhost ~]# cat /proc/net/ip_vs
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port Forward Weight ActiveConn InActConn
[root@localhost ~]# yum -y install ipvsadm

配置虚拟 IP 地址(VIP:192.168.145.20)

[root@localhost ~]# cd /etc/sysconfig/network-scripts/
###若隧道模式,复制为ifcfg-tunl0
[root@localhost network-scripts]# cp ifcfg-ens33 ifcfg-ens32:0		
[root@localhost network-scripts]# vim ifcfg-ens32:0
DEVICE=ens32:0
ONBOOT=yes
IPADDR=192.168.145.20
NETMASK=255.255.255.255
###开启虚拟字节
[root@localhost network-scripts]# ifup ens32:0
###查看配置是否成功
[root@localhost ~]# ifconfig ens32:0
ens32:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.145.20  netmask 255.255.255.255  broadcast 192.168.145.20
        ether 00:0c:29:33:c5:93  txqueuelen 1000  (Ethernet)

调整 proc 响应参数

由于 LVS 负载调度器和各节点需要共用 VIP 地址,需要关闭 icmp 的重定向,不充当路由器。

[root@localhost ~]# vim /etc/sysctl.conf     	#编辑内核proc参数
net.ipv4.ip_forward = 0      					#关闭ip转发
net.ipv4.conf.all.send_redirects = 0    	 	#关闭所有send重定向
net.ipv4.conf.default.send_redirects = 0    	#关闭默认重定向
net.ipv4.conf.ens32.send_redirects = 0    	#关闭网卡重定向

###查看内核参数
[root@localhost ~]# sysctl -p
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens32.send_redirects = 0

配置负载分配策略

[root@localhost ~]# systemctl start ipvsadm
###清除规则
[root@localhost ~]# ipvsadm -C
###创建虚拟主机,指定ip地址,并指定分流模式为轮询
[root@localhost ~]# ipvsadm -A -t 192.168.145.20:80 -s rr
###添加真实服务器ip地址,并指定负载均衡模式为DR,ip隧道模式为-i,-m为nat模式
[root@localhost ~]# ipvsadm -a -t 192.168.145.20:80 -r 192.168.145.30:80 -g
[root@localhost ~]# ipvsadm -a -t 192.168.145.20:80 -r 192.168.145.45:80 -g
###启动策略
[root@localhost ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  localhost.localdomain:http rr
  -> 192.168.145.30:http          Route   1      0          0         
  -> 192.168.145.45:http          Route   1      0          0  
#查看节点状态信息
[root@localhost ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.145.20:80 rr
  -> 192.168.145.30:80            Route   1      0          0         
  -> 192.168.145.45:80            Route   1      0          0   

Web节点服务器2

###进入网卡配置目录
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
###进入网卡配置目录
[root@localhost network-scripts]# cp -p ifcfg-lo ifcfg-lo:0
[root@localhost network-scripts]# vim ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.145.20
###注意:子网掩码必须全为 1
NETMASK=255.255.255.255
###启动环回网卡
[root@localhost network-scripts]# ifup ifcfg-lo:0
###查看环回网卡
[root@localhost network-scripts]# ifconfig lo:0
lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 192.168.145.20  netmask 255.255.255.255
        loop  txqueuelen 1000  (Local Loopback)

2.2 Web服务器1(192.168.145.30)配置

配置虚拟 VIP 地址(lo:0 192.168.145.20)

[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
###进入网卡配置目录
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
###进入网卡配置目录
[root@localhost network-scripts]# cp -p ifcfg-lo ifcfg-lo:0
[root@localhost network-scripts]# vim ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.145.20
###注意:子网掩码必须全为 1
NETMASK=255.255.255.255
###启动环回网卡
[root@localhost network-scripts]# ifup ifcfg-lo:0
###查看环回网卡
[root@localhost network-scripts]# ifconfig lo:0
lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 192.168.145.20  netmask 255.255.255.255
        loop  txqueuelen 1000  (Local Loopback)

添加vip本地访问路由

[root@localhost ~]# route add -host 192.168.145.20 dev lo:0

###或者下面方式,都可实现路由禁锢,下面的为永久添加
###linux在开启启动时,会加载的内容
[root@localhost ~]# vim /etc/rc.local
/sbin/route add -host 192.168.145.20 dev lo:0

调整内核的 ARP 响应参数以阻止更新 VIP 的 MAC 地址,避免发生冲突

[root@localhost ~]# vim /etc/sysctl.conf
......
net.ipv4.conf.lo.arp_ignore = 1			#系统只响应目的IP为本地IP的ARP请求
net.ipv4.conf.lo.arp_announce = 2		#系统不使用IP包的源地址来设置ARP请求的源地址,而选择发送接口的IP地址
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

###刷新
[root@localhost ~]# sysctl -p
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

2.3 Web服务器2(192.168.145.45)配置

[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# setenforce 0
###进入网卡配置目录
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
###进入网卡配置目录
[root@localhost network-scripts]# cp -p ifcfg-lo ifcfg-lo:0
[root@localhost network-scripts]# vim ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.145.20
###注意:子网掩码必须全为 1
NETMASK=255.255.255.255
###启动环回网卡
[root@localhost network-scripts]# ifup ifcfg-lo:0
###查看环回网卡
[root@localhost network-scripts]# ifconfig lo:0
lo:0: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 192.168.145.20  netmask 255.255.255.255
        loop  txqueuelen 1000  (Local Loopback)

添加vip本地访问路由

[root@localhost ~]# route add -host 192.168.145.20 dev lo:0

###或者下面方式,都可实现路由禁锢,下面的为永久添加
###linux在开启启动时,会加载的内容
[root@localhost ~]# vim /etc/rc.local
/sbin/route add -host 192.168.145.20 dev lo:0

调整内核的 ARP 响应参数以阻止更新 VIP 的 MAC 地址,避免发生冲突

[root@localhost ~]# vim /etc/sysctl.conf
......
net.ipv4.conf.lo.arp_ignore = 1			#系统只响应目的IP为本地IP的ARP请求
net.ipv4.conf.lo.arp_announce = 2		#系统不使用IP包的源地址来设置ARP请求的源地址,而选择发送接口的IP地址
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

###刷新
[root@localhost ~]# sysctl -p
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

2.4 使用其他机器测试

在客户端使用浏览器访问 http://192.168.145.20/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iRt0Cjw3-1686212789644)(C:\Users\86138\AppData\Roaming\Typora\typora-user-images\image-20230608162602257.png)]

三、总结

1. LVS 调度算法

rr  wrr  sh  dh  lc  wlc  lblc

2.NAT模式配置注意点

客户端和节点服务器 的默认网关要指向 调度器的IP。

调度器要设置 IP路由转发 和 SNAT 等 iptables 规则。

调度器安装 ipvsadm 配置 虚拟服务器 和 真实节点服务器。

3.DR模式配置注意点

节点服务器要在 lo:0 上配置VIP , 修改内核参数 arp_ignore = 1 arp_announce = 2 , 添加路由。

调度器要在 ens33:0 上配置VIP , 修改内核参数关闭ip路由转发和重定向功能 。

调度器安装 ipvsadm 配置 虚拟服务器 和 真实节点服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【基础知识】一文看懂深度优先算法和广度优先算法

概览 先上个图 现在我们要访问图中的每个节点&#xff0c;即图的遍历。 图的遍历是指&#xff0c;从给定图中任意指定的顶点&#xff08;称为初始点&#xff09;出发&#xff0c;按照某种搜索方法沿着图的边访问图中的所有顶点&#xff0c;使每个顶点仅被访问一次&#xff…

三、django-vue-admin开源项目二次开发——后端快速实现curd及接口

上一章&#xff1a; 二、django-vue-admin开源项目二次开发——修改默认菜单_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、背景 我想实现接口自动化用例的管理功能。一共涉及到两张表&#xff0c;一张项目表&#xff0c;是所有的项目列表。 一张是case列表&#…

Postgresql关于JSON、JSONB的操作符、处理函数(持续更新)

一、postgresql实用函数 &#xff08;只列举本次用到的函数&#xff0c;其他函数在文章后面有详解&#xff09; 1.1、将jsonb格式的数组中的值展开/分解成单独的数据/对象&#xff1f; SELECT answer_id, jsonb_array_elements(option_ids)::INTEGER AS option_id FROM db_l…

Java HashMap初始化大小设置多少合适

修改公司老代码的时候&#xff0c;发现阿里编码规约插件提示HashMap初始化时尽量指定初始值大小&#xff0c;因为设置合理的初始值可以提升性能&#xff1a; HashMap继承自AbstractMap类&#xff0c;实现了Map、Cloneable、java.io.Serializable接口&#xff0c;是基于散列表实…

Prompt 工程指南(三)—— 高级技术篇之零样本和少样本提示

到目前为止&#xff0c;显而易见的是&#xff0c;改进提示有助于在不同任务上获得更好的结果。这就是提示工程背后的理念和目标。 虽然上篇教程介绍的基本示例已经很有趣&#xff0c;但在接下来的几篇教程中&#xff0c;我们将介绍更高级的 Prompt 提示工程技巧&#xff0c;使…

LabVIEW编程开发PCB测试仪

LabVIEW编程开发PCB测试仪 使用PXI和LabVIEW的PCB钉床测试仪 用于PCB&#xff08;印刷电路板&#xff09;的钉床测试仪&#xff0c;使用PXI和LabVIEW。一家电子制造公司需要测试仪来测试他们的PCB产品。钉床测试仪是一种具有连接到电路板上各个测试点的引脚的测试。电路板需要…

【大数据学习篇12】在linux上安装jupyter

下面介绍在liunx怎么安装jupyter&#xff0c;一步到位介绍。 1、安装Anaconda3 1.1 自己选择一个位置下载 wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh1.2 进入自己的安装目录&#xff0c;安装anaconda bash Anaconda3-5.2.0-Linux-x86_64.sh一…

小程序模板语法样式与页面配置

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/front-end-tutorial 】或者公众号【AIShareLab】回复 小程序 也可获取。 文章目录 小程序模板与配置WXML 模板语法数据绑定事件绑定小程序中常用的事件事件对象的属性列表target 和 currentTarget 的…

spark入门 高可用部署HA(五)

一、standalone基于修改部署 https://blog.csdn.net/weixin_43205308/article/details/131070277?spm1001.2014.3001.5501 二、安装ZOOKEEPER zookeeper 安装下载与集群 三、修改conf下的spark-env.sh vim conf/spark-env.sh注释以下内容&#xff08;根据自己环境修改&am…

备战金九银十:大厂面试官必问MySQL连环炮全梳理,你扛得住嘛?

最近后台好多小伙伴发私信咨询阿Q&#xff0c;问马上就是金九银十的面试黄金期了&#xff0c;该如何在三个月内突击一下&#xff0c;以便更好地通过面试呢&#xff1f; 阿Q的想法就是需要对自己掌握的知识进行归纳整理&#xff0c;系统的、分类的去复习相关的知识点。这样也能…

公司新来了个00后测开,上来一顿操作给我秀麻了.....

开年公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司实习半年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍!给公司…

提升效率:P4VFS让虚拟文件同步更迅速、更简单

虚拟文件同步&#xff08;Virtual File Sync&#xff09;是一个备受期待的功能集&#xff0c;能够显著缩短Perforce Helix Core用户的同步时间。本篇文件将解释什么是虚拟文件同步&#xff0c;如何设置它以及如何使用它。 什么是虚拟文件同步&#xff1f; 虚拟文件同步是一项…

配置Wildfly的JDBC驱动程序

1、环境 windows10、Wildfly26.1.3、JDK8.0、mysql8.0 2、配置方式 配置Wildfly的JDBC驱动一般有两种方式 1️⃣、以module的方式安装&#xff1b; 2️⃣、以应用deploy的程序包方式安装&#xff1b; 以module方式安装&#xff0c;是把驱动置于应用服务器中&#xff1b;以…

Ubuntu 20.04 Apache2 增加不同端口站点

概述 Apache HTTP Server&#xff08;简称Apache&#xff09;是Apache软件基金会的一个开放源码的网页服务器软件&#xff0c;可以在大多数电脑操作系统中运行。由于其跨平台和安全性[注 1]&#xff0c;被广泛使用&#xff0c;是最流行的Web服务器软件之一。它快速、可靠并且可…

ROS:move_base路径规划介绍、更换全局路径规划算法(A star、Dijkstra、DWA,测试当前是哪种算法,效果展示图)

前提&#xff1a;需要安装navigation包&#xff0c;才可以运行move_base。 一.move_base路径规划包内容 二.更换全局路径规划算法&#xff08;A*、Dijkstra、DWA&#xff09; A*、Dijkstra属于全局路径规划、DWA属于局部路径规划。 1、move_base.launch move_base.launch文…

开源 AI 面临的挑战

译者&#xff1a;明明如月 人工智能的代价 尽管我坚信开源人工智能将继续蓬勃发展&#xff0c;但我也认为未来几年企业和政府将越来越有动机限制对新型神经网络架构和技术的应用。本文旨在预测并概述可能在本十年发生的潜在颠覆性变革&#xff0c;并提出一些想法和解决方案&a…

玩转css逐帧动画,努力成为更优质的Ikun~

&#x1f389; 一、前言 css3的animation想必大家都知道吧&#xff0c;那 steps 逐帧动画你知道吗&#xff1f;对于我来说&#xff0c;实际工作及练习中也很少用到这种跳跃式变化的动画&#xff0c;而它start和end的解释又比较“不说人话”&#xff0c;以前用到steps动画的时候…

FL Studio21水果软件各个版本功能区别对比

作为音乐人&#xff0c;在电脑上进行编曲&#xff0c;混音&#xff0c;合成是家常便饭&#xff0c;而市面上大家常用的音乐编曲制作软件很多&#xff0c;小编在这里就给大家做一个推荐。 大家常听到的音乐编曲制作软件大多是Cubase、Nuendo、Pro Tools、 SONAR等等&#xff0c…

Qt中QFile类读取ansi编码格式txt文件,在QTextEdit控件中显示乱码

系列文章目录 文章目录 系列文章目录前言一、依然无法解决乱码问题二、解决办法1.方法一&#xff1a;使用QString的fromLocal8Bit()函数2.读取utf-8编码格式的文件 总结 前言 使用Qt中的QFile类读取ANSI编码格式的文本文件&#xff0c;并在QTextEdit控件中显示乱码&#xff0c…

适配器模式的运用

文章目录 一、适配器模式的运用1.1 介绍1.2 适配器模式结构1.3 类适配器模式1.3.1 类适配器模式类图1.3.2 代码 1.4 对象适配器模式1.4.1 对象适配器模式类图1.4.2 代码 1.5 应用场景1.6 JDK源码解析1.6.1 字节流到字符流的转换类图1.6.2 部分源码分析1.6.3 总结 一、适配器模式…