Keepalived实例演示:
利用keepalived流动一个VIP,在提供LVS的高可用以及实现对LVS后端的real server做健康状态检测,最后实现高可用nginx。
 
HA Cluster配置前提:
1、本机的主机名,要与hostname(uname -n)获得的名称保持一致;
CentOS 6: /etc/sysconfig/network
CentOS 7: hostnamectl set-hostname HOSTNAME
各节点要能互相解析主机名;一般建议通过hosts文件进行解析;
2、各节点时间同步;
3、确保iptables及selinux不会成为服务阻碍;

示例演示

这里利用两台主机进行演示192.168.184.141/142

# cat /etc/centos-release  //查看版本

CentOS Linux release 7.4.1708 (Core)

# hostname

node1

# cat /etc/hosts

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.184.141 node1   /此处对应的是node1
192.168.184.142 node2

为了测试两个主机时间是否一致  http://www.zsythink.net/archives/2375

# date; ssh node2 'date'  //这里需要用到两台主机免密码交互

# ssh-keygen  //回车到底

# ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.184.142   //把node1生成的公钥发送至node2上

# ssh root@192.168.184.142  //进行测试

Last login: Sat Dec  1 10:55:23 2018 from 192.168.184.141

# date; ssh node2 'date'

Sat Dec 1 11:01:33 CST 2018   //两台主机差一秒钟
Sat Dec 1 11:01:32 CST 2018

这里使用ntp同步时间

配置前先使用命令:ntpdate -u cn.pool.ntp.org,同步服务器,如果这个命令不生效可使用:#ntpd -u cn.pool.ntp.org

# date; ssh node2 'date'
   Sat Dec 1 11:35:06 CST 2018
   Sat Dec 1 11:35:06 CST 2018

# yum install keepalived -y  //两天主机分别安装上keepalived

下面配置keeplived

在Master节点(192.168.184.141)进行配置

# cp keepalived.conf{,.backup}  //首先对/etc/keepalived下的文件进行备份

# vim /etc/keepalived/keepalived.conf

:.,$s/^/#/g  //现在virtual host是用不到的,所以在第一个virtual host到最后一行的前面全部添加#

 ! Configuration File for keepalived

 global_defs {   //全局定义
notification_email { //警告信息发送的目标邮箱,下面三个邮箱
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
root@localroot //把上面三个修改为此行
}
notification_email_from Alexandre.Cassen@firewall.loc //指明发件人
smtp_server 192.168.200.1 //指明由哪个邮件服务器把警告发出
smtp_connect_timeout
router_id LVS_DEVEL //定义当前物理设备的唯一标识
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0 9-16行修改如下
      notification_email_from kaadmin@localhost   //修改上面的发件人如此行,可以随便修改
smtp_server 127.0.0.1 //每一个主机在安装完成服务器后默认邮件服务127.0.0.1都是开放的
vrrp_mcast_group4 224.0.0.141 //指定多播组,这里要注意会有冲突
smtp_connect_timeout 30
router_id node1
 }

19 vrrp_instance VI_1 {     //虚拟路由实例
20 state MASTER //定义初始状态,如果是master,优先级最高,因为工作在抢占模式下,这个优先级比其他服务器低的话会被会被其他服务器抢走
21 interface eth0 //vrrp主要是流动IP地址,这里指定IP地址配置的网卡,vrrp会自动使用ifconfig或者ip命令在物理网卡上以定义别名的方式或者添加辅助地址的方式配置VIP地址
22 virtual_router_id 51 //虚拟路由器的id号,必须唯一,这个是VRID,0-255,这个VRID也是做VMAC最后一段的地址,虚拟MAC地址的格式为00-00-5E-00-01-{VRID}
23 priority 100 //定义优先级,0-255,数字越大优先级越高
24 advert_int 1 //定义心跳信息发送的时间间隔。通告、广播。主节点需要周期性的向其他备用节点通告自己的优先级和状态信息即心跳。这里默认是1秒
25 authentication { //简单字符认证
26 auth_type PASS
27 auth_pass 1111
28 }
29 virtual_ipaddress { //配置虚拟IP地址,配置在上面eth0的辅助地址或者别名上
30 192.168.184.150/24 (dev eth0 label eth0:0这些内容在centos6可以用) //这里的VIP一定不能和master和backup中的任何一台主机的IP相冲突
33 }

virtual_ipaddress {  //配置虚拟IP地址的格式

<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE> label <LABEL>

IP地址  /掩码    广播地址  dev配置在哪个设备上 scope作用域,默认是全局的  label定义别名,因为IP应该配置在网卡的别名上。

192.168.200.17/24 dev eth1

192.168.200.18/24 dev eth2 label eth2:1

}

nopreempt:非抢占模式;默认为抢占模式;

 }

 # virtual_server 192.168.200.100  {
# ...
# ...

上面配置完成后需要把master配置的keepalived.conf文件复制到node2的/etc/keepalived目录下

# scp keepalived.conf node2:/etc/keepalived/   //注意这里已经使用了免密交互

# vim /etc/keepalived/keepalived.conf    //在node2即192.168.184.142上进行修改

router_id node2   //可以改也可以不改,两台路由器相同也没有问题

state BACKUP      //必须改

priority 99       //这个要改的比master小

virtual_router_id 51  //这个一定要和master保持一致,因为master和backup构建为同一个虚拟路由,这里表示虚拟路由的id

# systemctl start keepalived; ssh node2 'systemctl start keepalived'  //在node1上即master(192.168.184.141)上同时启动两台主机的keepalived

# ps -aux  //查看启动进程

# ip addr list    //在master(192.168.184.141)上查看配置的VIP,但是在BACKUP(192.168.184.142)上查看ip就没有,因为VIP只绑定一下路由设备

: lo: <LOOPBACK,UP,LOWER_UP> mtu  qdisc noqueue state UNKNOWN qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
inet6 ::/ scope host
valid_lft forever preferred_lft forever
: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc pfifo_fast state UP qlen
link/ether :0c::ce:f8: brd ff:ff:ff:ff:ff:ff
inet 192.168.184.141/24 brd 192.168.184.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.184.150/24 scope global secondary eth0 //配置的VIP已经绑定了
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fece:f804/ scope link
valid_lft forever preferred_lft forever

由于keepalived的默认日志是LOG_DAEMON,但是#cat /etc/rsyslog.conf文件中的信息是没有DAEMON的,

所以要修改配置文件/etc/sysconfig/keepalived添加日志,

当然日志并不一定非要打开,此时如果修改master和backup都要做修改

# vim /etc/sysconfig/keepalived

 # Options for keepalived. See `keepalived --help' output and keepalived(8) and
# keepalived.conf() man pages for a list of all options. Here are the most
# common ones :
#
# --vrrp -P Only run with VRRP subsystem.
# --check -C Only run with Health-checker subsystem.
# --dont-release-vrrp -V Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs -I Dont remove IPVS topology on daemon stop.
# --dump-conf -d Dump the configuration data.
# --log-detail -D Detailed log messages.
# --log-facility -S - Set local syslog facility (default=LOG_DAEMON) //修改日志级别
# KEEPALIVED_OPTIONS="-D -S 3" 修改次数,开启日志

# vim /etc/rsyslog.conf

 # Save boot messages also to boot.log
local7.* /var/log/boot.log
local3.* /var/log/keepalived.log //插入此行

# systemctl restart rsyslog.service   //重载日志服务

# systemctl restart keepalived   //因为/etc/sysconfig/keepalived做了修改,所以这里也要重新启动

# tail /var/log/keepalived.log    //此时就有日志了

Dec   :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: VRRP_Instance(VI_1) Sending/queueing gratuitous ARPs on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150
Dec :: node1 Keepalived_vrrp[]: Sending gratuitous ARP on eth0 for 192.168.184.150

以上配置成功了

下面把master节点的keepalived停止,查看VIP是否迁移到backup上

# systemctl stop keepalived

# ip addr list   //这时候再查看IP已经没有VIP即192.168.184.150/24

# ip addr list   //在backup即192.168.184.142节点上查看,VIP已经迁移到此节点了

: lo: <LOOPBACK,UP,LOWER_UP> mtu  qdisc noqueue state UNKNOWN qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
inet6 ::/ scope host
valid_lft forever preferred_lft forever
: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc pfifo_fast state UP qlen
link/ether :0c::::fe brd ff:ff:ff:ff:ff:ff
inet 192.168.184.142/ brd 192.168.184.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.184.150/ scope global secondary eth0
valid_lft forever preferred_lft forever

下面再把之前的master即192.168.184.141启动起来

# systemctl start keepalived   //在master上操作,因为141主机的优先级高且处于抢占模式下,所以当master的keepalived启动后,立刻就把VIP抢回来了

[root@node1 log]# ip addr list
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
inet6 ::/ scope host
valid_lft forever preferred_lft forever
: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc pfifo_fast state UP qlen
link/ether :0c::ce:f8: brd ff:ff:ff:ff:ff:ff
inet 192.168.184.141/ brd 192.168.184.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.184.150/ scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fece:f804/ scope link
valid_lft forever preferred_lft forever

如何在master节点上不停止keepalived服务的情况下,把Master手动调度换成Backup?-->改变master的优先级

# vim /etc/keepalived/keepalived.conf  //无论master还是backup都要修改此文件

 ! Configuration File for keepalived

 global_defs {
notification_email {
root@localhost
}
notification_email_from kaadmin@localhost
smtp_server 127.0.0.1
smtp_connect_timeout
router_id node1
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval
vrrp_gna_interval
} 17 vrrp_script chk_schedown { //vrrp_script是vrrp专用脚本,是vrrp的一个扩展,注意这个脚本要在vrrp_instance之外定义,但是却在vrrp_instance内部调用这个脚本
18 script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0" //执行脚本script,用""引起来的是脚本的内容。返回错误码1就证明脚本执行成功。返回正确码0证明脚本是执行失败,
19 interval 1 //每隔2秒执行一次script这个脚本 //此处的意义是如果存在文件down,则证明管理员想手动减少本主机的优先级,即手动宕掉master换成backup,
20 weight -2 //优先级减少2 //文件down存在,则返回错误码1,执行后面19、20两行,如果文件down不存在,则返回正确码0,不执行后面的操作了
21 } vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id
priority
advert_int
authentication {
auth_type PASS
auth_pass
}
virtual_ipaddress {
192.168.184.150/
}
36 track_script { //定义指明在vrrp虚拟实例中调用脚本
37 chk_schedown
38 }
}

# systemctl restart keepalived.service; ssh node2 'systemctl restart keepalived.service'   //master节点和backup节点配置好后都重启

# touch down  //此时按照正常是应该实现IP漂移的,但是并没有,所以只能另找他法了。

这里把vrrp_script段的脚本内容([[ -f /etc/keepalived/down ]] && exit 1 || exit 0)写到一个脚本中,并把这个脚本的路径写到此处

# vim /etc/keepalived/down.sh   //注意:无论是master还是backup都需要修改

#! /bin/bash

[[ -f /etc/keepalived/down ]] && exit 1 || exit 0

# chmod +x /etc/keepalived/down.sh

# vim /etc/keepalived/keepalived.conf

vrrp_script chk_down {
     script "/etc/keepalived/down.sh"
     interval 1
     weight -10
}

#systemctl restart keepalived; ssh node2 'systemctl restart keepalived'

# touch /etc/keepalived/down   //此时就实现了IP漂移

# ip addr list

NAT模型的LVS,后端是两个real server(web服务器集群),如何做高可用?高可用LVS
基于NAT模型做高可用,后端的real server的网关应该指向路由设备的DIP,为了把路由做高可用,应该为路由设备提供一个VIP,以方便互联网上的用户可以访问,
外部接口有自己的地址,同时在外部接口上配置一个别名地址当互联网上请求的地址,一旦路由设备A宕机,别名地址就流转到路由设备B,路由设备B同样有自己的外部接口
VIP,所以把别名地址就附加在外部接口上。同时后端的real server指向路由设备的网关同样要迁移到路由设备B,但是地址写死在接口上不可能迁移,所以仿照外部接口
的别名地址的方法,在内网接口上添加别名地址,把别名地址当DIP即内部real server的网关。外部接口的别名地址VIP在那个路由设备上内部接口的别名地址DIP就在
那个路由设备上,路由设备A和路由设备B此时各为一个实例,这两个实例上的两个别名地址要同步进退。
就把上述定义为vrrp的实例同步组:vrrp_sync_group,但很少使用LVS做负载均衡集群。

# man keepalived.conf  //配置方法

VRRP synchronization group(s)
#string, name of group of IPs that failover together
vrrp_sync_group VG_1 {
group {
inside_network # name of the vrrp_instance (see below)
outside_network # One for each movable IP
...
}

VIP和DIP无论必须同时迁移到同一个主机上

vrrp_sync_group VG_1 {   //定义把哪些实例定义为一个组

group {  //表示把VI_1和VI_2定义为一个组

VI_1   # name of vrrp_instance (below)

VI_2   # One for each moveable IP.

}

}

vrrp_instance VI_1 {  //实例1

eth0  //外网网卡

vip   //外网网卡定义的别名

}

vrrp_instance VI_2 {

eth1   //内网网卡

dip    //内网网卡定义的别名

}

以上只有在LVS的NAT模型下采用到此功能,因为NAT模型下后端的real server的网关需要指向dip

另一种情形:双主模型,两个路由设备都工作起来,各承担一部分的工作(这里做LVS集群,但不考虑DIP做网关的场景)

作为一个路由/负载均衡器来讲必须有一个外网接口的流动地址接收客户端的请求,这个地址流动的,它在那个主机上那个主机就是主节点,上述情景总有一个路由器是空闲的。为了充分利用,可以把域名解析为两个A记录(VIP1和VIP2),而且这两个VIP都配置在外网接口上,即两个外网辅助地址,但是不在同一路由设备上,这是为了实现双主都活动的目的。为了让两个流动IP不同步进退,要把两个路由设备做成两个实例,对于第一个实例来讲router1优先级高,router2优先级低,流动IP在router1上;对于第二个实例router2来讲,router2优先级高,router1优先级低,流动IP配置在router2上的外网接口上。一旦router1出现故障,就把router1的流动IP漂移到router2的外网网卡接口上,这样两个流动IP全在router2上,他们使用不同的别名或者向网卡配置两个不同的辅助地址,一旦router1上线,流动IP就重新迁回router1的外网网卡上。

以上就可以实现均衡的效果,上述是两个虚拟实例,但是这两个实例不是同进退。

或理解为

有三个虚拟路由器存在:

虚拟路由器1:Device A作为Master路由器,Device B和Device C作为Backup路由器。

虚拟路由器2:Device B作为Master路由器,Device A和Device C作为Backup路由器。

虚拟路由器3:Device C作为Master路由器,Device A和Device B作为Backup路由器。

为了实现业务流量在Device A、Device B和Device C之间进行负载分担,需要将局域网内的主机的默认网关分别设置为虚拟路由器1、2和3。在配置优先级时,需要确保三个虚拟路由器中各路由器的VRRP优先级形成一定的交叉,使得一台路由器尽可能不同时充当2个Master路由器。

示例演示

# vim /etc/keepalived/keepalived.conf  //现在master即192.168.184.141上修改

:.,40y   //从当前行复制到第40行

 ! Configuration File for keepalived

 global_defs {
notification_email {
root@localhost
}
notification_email_from kaadmin@localhost
smtp_server 127.0.0.1
smtp_connect_timeout
router_id node1
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval
vrrp_gna_interval
} vrrp_script chk_down {
script "/etc/keepalived/down.sh"
interval
weight -
} vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id
priority
advert_int
authentication {
auth_type PASS
auth_pass
}
virtual_ipaddress {
192.168.184.150/
} track_script {
chk_down
}
} 42 vrrp_instance VI_2 { //vrrp虚拟实例的名字不能相同
43 state BACKUP //修改
interface eth0
virtual_router_id 51 //router ID能一样
46 priority 99 //修改
advert_int
authentication {
auth_type PASS
auth_pass 2222 //修改
}
virtual_ipaddress {
192.168.184.151/24 //这里代表router2的流动IP
} track_script { //这里最好修改,如果不修改可能同步掉线
chk_down
}
}

修改完141主机的下面把修改好的keepalived.conf复制到142上

# scp keepalived.conf root@node2:/etc/keepalived/  //这里两台主机是免密的,另外/etc/hosts可以解析node2

# vim keepalived.conf   //在192.168.184.142修改如下

 ! Configuration File for keepalived

 global_defs {
notification_email {
root@localhost
}
notification_email_from kaadmin@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id node2 //修改如下
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval
vrrp_gna_interval
} vrrp_script chk_down {
script "/etc/keepalived/down.sh"
interval
weight -
} vrrp_instance VI_1 {
state BACKUP //修改如下
interface eth0
virtual_router_id
priority 99 //修改如下
advert_int
authentication {
auth_type PASS
auth_pass
}
virtual_ipaddress {
192.168.184.150/
} track_script {
chk_down
}
} vrrp_instance VI_2 {
state MASTER //修改如下
interface eth0
virtual_router_id
priority 100 //修改如下
advert_int
authentication {
auth_type PASS
auth_pass
}
virtual_ipaddress {
192.168.184.151/
} track_script {
chk_down
}
}

# systemctl restart keepalived.service; ssh node2 'systemctl restart keepalived.service'

# ip addr list  //在router1上

# touch down  //在141上创建down文件

故障总结:

1、日志?

2、每个vrrp_instance需要专用的组播地址;

2、Keepalived提供日志与双主模型演示的更多相关文章

  1. keepalived + haproxy 实现web 双主模型的高可用负载均衡--转

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://xz159065974.blog.51cto.com/8618592/140581 ...

  2. 【 Linux 】Keepalived实现双主模型高可用集群

    要求:    1. 两台web服务器安装wordpress,数据库通过nfs共享    2. 使用keepalived实现双主模型 环境:    主机:        系统:CentOS6.7 x64 ...

  3. Apache+lvs高可用+keepalive(主从+双主模型)

    Apache+lvs高可用+keepalive(主从+双主模型)     keepalive实验准备环境: httpd-2.2.15-39.el6.centos.x86_64 keepalived-1 ...

  4. Linux-实现双主模型的nginx的高可用

    实现双主模型的ngnix高可用(一) 准备:主机7台 client: 172.18.x.x 调度器:keepalived+nginx 带172.18.x.x/16 网卡 192.168.234.27 ...

  5. ssdb主从及双主模型配置和简单管理

    ssdb主从及双主模型配置和简单管理 levelDB是一个key->value 的数据存储库,其只能在本地保存数据,支持持久化,并且支持保存非常大的数据,单机redis在保存较大数据的时候数十G ...

  6. nginx+keepalived高可用及双主模式

    高可用有2中方式. 1.Nginx+keepalived 主从配置 这种方案,使用一个vip地址,前端使用2台机器,一台做主,一台做备,但同时只有一台机器工作,另一台备份机器在主机器不出现故障的时候, ...

  7. nginx+keepalived高可用及双主模式【h】

    高可用有2中方式. 1.Nginx+keepalived 主从配置 这种方案,使用一个vip地址,前端使用2台机器,一台做主,一台做备,但同时只有一台机器工作,另一台备份机器在主机器不出现故障的时候, ...

  8. Centos7+nginx+keepalived集群及双主架构案例

    目录简介 一.简介 二.部署nginx+keepalived 集群 三.部署nginx+keepalived双主架构 四.高可用之调用辅助脚本进行资源监控,并根据监控的结果状态实现动态调整 一.简介 ...

  9. keepalived健康检查及双主MySQL健康检查脚本

    一.http检查 HTTP_GET:工作在第5层,向指定的URL执行http请求,将得到的结果用md5加密并与指定的md5值比较看是否匹配,不匹配则从服务器池中移除:此外还可以指定http返回码来判断 ...

随机推荐

  1. window下nodejs用nodemon启动koa2项目(用cmd启动不了,要用Git Bash Here 启动才可以)

    window下nodejs用nodemon启动koa2项目(用cmd启动不了,要用Git Bash Here 启动才可以)nodemon --watch 'app/**/*' -e ts --exec ...

  2. 自制TFT-Usart通信小项目资料打包

    2010-05-08 15:05:00 用orcad画的原理图如下.

  3. es6基本语法

    //let和const申明变量和常量 //作用域只限于当前代码块 //使用let申明的变量作用域不会提升 //在相同的作用域下不能申明相同的变量 //for循环体现let的父子作用域 二.es6的解构 ...

  4. [C#基础]说说lock到底锁谁?(补充与修改)

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  5. [转载]FileStream读写文件

    FileStream读写文件 FileStream类:操作字节的,可以操作任何的文件 StreamReader类和StreamWriter类:操作字符的,只能操作文本文件. 1.FileStream类 ...

  6. ARM的栈指令(转)

    ARM的指令系统中关于栈指令的内容比较容易引起迷惑,这是因为准确描述一个栈的特点需要两个参数: 栈地址的增长方向:ARM将向高地址增长的栈称为递增栈(Descendent Stack),将向低地址增长 ...

  7. CentOS7的安装以及redis的下载安装和连接redis desktop manager出现的问题

    因为需要在springboot下使用redis,所以打算在linux下使用redis,并且使用redis desktop manage来连接管理,但是一路上出现个种问题现在总结一下. 如何安装Cent ...

  8. CentOS 7 install slurm cluster

    //slurm install //CentOS 7 system //192.168.159.141 node01 //192.168.159.142 node02 systemctl stop f ...

  9. 回归Android之Android基础和小常识

    Activity ,Service,Content Provider,BroadcastReceiver, Intent SQLite,Http,Fragement,Handle 1,Activity ...

  10. 软件调用QML的两种方式

    一.两种方式 二.方式1[对窗口的控制权在QML] 三.方式2[对窗口的控制权在C++]