redis中的哨兵

redis中的哨兵

    • 一、哨兵机制的概念
    • 二、redis哨兵的部署
      • 2.1 docker的安装
      • 2.2 编排redis主从节点
      • 2.3 配置哨兵节点
    • 三、redis哨兵的选举机制
      • 3.1 redis-master宕机之后的情况
      • 3.2 重启redis-master后的情况
    • 四、redis哨兵机制的原理
      • 4.1主观下线
      • 4.2客观下线
      • 4.3选举leader节点
      • 4.4选出合适的从节点
      • 4.5哨兵机制小结

Redis 的主从复制模式下,⼀旦主节点由于故障不能提供服务,需要⼈⼯进⾏主从切换,同时⼤量的客⼾端需要被通知切换到新的主节点上,对于上了⼀定规模的应⽤来说,这种⽅案是⽆法接受的,于是 Redis 从 2.8 开始提供了 Redis Sentinel(哨兵)来解决这个问题

一、哨兵机制的概念

Redis Sentinel 相关名词解释 :

名词逻辑结构物理结构
主节点redis主服务一个独立的redis-server进程
从节点redis从服务一个独立的redis-server进程
redis数据节点主从节点主节点和从节点的进程
哨兵节点监控redis数据节点的节点一个独立的redis-sentinel进程
哨兵节点集合若干哨兵节点的抽象组合若干redis-server进程
redis哨兵(sentinel)redis提供的高可用方案哨兵节点集合和redis主从节点
应用方泛指一个或多个客户端一个或多个连接redis的进程

Redis Sentinel 是 Redis 的⾼可⽤实现⽅案,在实际的⽣产环境中,对提⾼整个系统的⾼可⽤是⾮常有帮助的,本节⾸先整体梳理主从复制模式下故障处理可能产⽣的问题,⽽后引出⾼可⽤的概念,最后重点分析 Redis Sentinel 的基本架构、优势,以及是如何实现⾼可⽤的

哨兵⾃动恢复主节点故障

提供多个sentinel哨兵进程监控现有的redis master和slave。这些进程之间会建立tcp长连接,通过这样的长连接,定期发送心跳包。然后就可发现监控的节点是否挂了。

  • 如果从节点挂了,那么哨兵节点不予理会,认为对服务没有什么影响。

  • 如果一个哨兵发现主节点挂了,那么其它哨兵也会进行判断主节点是否挂了,如果超过法定票数个哨兵都认为主节点挂了,那么此时就会在这些从节点中,挑选一个节点作为新的主节点,挑选出的新节点,哨兵会自动控制该节点执行slaveof no one让其成为主节点,并且控制其他从节点,修改slaveof到新的主节点上。

  • 最后哨兵会自动通知客户端程序,告知新的主节点是谁,让客户端后续在进行写操作时,能够在新的主节点上操作,当原来的主节点恢复,执⾏ slaveof {newMasterIp} {newMasterPort}让其成为⼀个从节点

在这里插入图片描述

补充:一般哨兵节点会弄奇数个。

二、redis哨兵的部署

2.1 docker的安装

部署多个节点在一台主机上是非常麻烦的,所以这里使用docker来进行演示。

在Linux上安装docker可看这篇博客

2.2 编排redis主从节点

上述操作必须保证⼯作⽬录在yml的同级⽬录中, 才能⼯作

1.配置文件

在配置redis主从节点之前,先创建一个redis-slave文件夹,然后进入该文件夹,写一下配置文件docker-compose.yml:

version: '3.7' #版本号
services:   #表示启动的服务器master:   #服务名image: 'redis:5.0.9' #容器镜像名称container_name: redis-master  #自定义名称(也可以理解为ip地址)restart: always   #表示总是自动重启command: redis-server --appendonly yes #启动redis时启动的选项ports:- 6379:6379  #端口映射  前面是宿主机端口号  后面是虚拟机的端口号slave1:    #服务名image: 'redis:5.0.9'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6380:6379slave2:    #服务名image: 'redis:5.0.9'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379

补充:端口映射

docker容器,可以理解为一个轻量的虚拟机,在这个容器里,端口号和外面的宿主机的端口号是两个体系。如果容器外面使用了5000端口,在容器内部也可以使用5000端口,有时候希望在容器外面能够访问到容器内部的端口号,所以就把容器内部的端口和容器外面的端口进行映射。

容器使用相同的端口号不会冲突吗?

每个容器内部的端口号是不会互相影响的,可以把每个容器理解为一个独立的主机

2.执行指令,启动该配置文件中的docker容器

sudo docker-compose up -d

如果启动后发现前⾯的配置有误, 需要重新操作, 使⽤ docker-compose down 即可停⽌并删除刚才创建好的容器.

sudo docker-compose down

3.查看一下是否成功启动:

sudo docker ps -a

在这里插入图片描述

netstat -anp | grep -E '6379|6380|6381'

在这里插入图片描述

4.查看运⾏⽇志

sudo docker-compose logs

现在客户端就可以连接redis服务器了。

redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381

补充:

也可以把 redis-sentinel 放到和上⾯的 redis 的同⼀个 yml 中进⾏容器编排. 此处分成两组, 主要是为了两⽅⾯:

  • 观察⽇志⽅便

  • 确保 redis 主从节点启动之后才启动 redis-sentinel. 如果先启动 redis-sentinel 的话, 可能触发额外的选举过程, 混淆视听. (不是说先启动哨兵不⾏, ⽽是观察的结果可能存在⼀定随机性)

2.3 配置哨兵节点

1.回到上级目录,新创一个文件夹sentinel,然后进到该文件夹,创建docker-compose.yml文件,然后配置:

version: '3.7'
services:sentinel1:image: 'redis:5.0.9'container_name: redis-sentinel-1restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel1.conf:/etc/redis/sentinel.confports:- 26379:26379sentinel2:image: 'redis:5.0.9'container_name: redis-sentinel-2restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel2.conf:/etc/redis/sentinel.confports:- 26380:26379sentinel3:image: 'redis:5.0.9'container_name: redis-sentinel-3restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel3.conf:/etc/redis/sentinel.confports:- 26381:26379
networks:default:external:name: redis-slave_default  #加入到的局域网名,后面解释

2.创建 sentinel1.conf sentinel2.conf sentinel3.conf . 三份⽂件的内容是完全相同的

bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000

理解 sentinel monitor:

sentinel monitor 主节点名 主节点ip 主节点端⼝ 法定票数
  • 主节点名:这个是哨兵内部⾃⼰起的名字
  • 主节点 ip:部署 redis-master 的设备 ip. 此处由于是使⽤ docker, 可以直接写 docker 的容器名, 会被⾃动 DNS 成对应的容器 ip
  • 主节点端⼝:主节点的端口号
  • 法定票数:哨兵需要判定主节点是否挂了. 但是有的时候可能因为特殊情况, ⽐如主节点仍然⼯作正常, 但是哨兵节点⾃⼰⽹络出问题了, ⽆法访问到主节点了. 此时就可能会使该哨兵节点认为主节点下线, 出现误判. 使⽤投票的⽅式来确定主节点是否真的挂了是更稳妥的做法. 需要多个哨兵都认为主节点挂了, 票数 >= 法定票数 之后, 才会真的认为主节点是挂了

理解 sentinel down-after-milliseconds

主节点和哨兵之间通过⼼跳包来进⾏沟通. 如果⼼跳包在指定的时间内还没回来, 就视为是节点出现故障

既然内容相同, 为啥要创建多份配置⽂件?

redis-sentinel 在运⾏中可能会对配置进⾏ rewrite, 修改⽂件内容. 如果⽤⼀份⽂件, 就可能出现修改混乱的情况

3.启动该配置文件中的docker容器

sudo docker-compose up -d

如果启动后发现前⾯的配置有误, 需要重新操作, 使⽤ docker-compose down 即可停⽌并删除刚才创建好的容器

4.查看运⾏⽇志

docker-compose logs

在这里插入图片描述

出现“WARNING: Sentinel was not able to save the new configuration on disk!!!: Is a directory”错误的原因通常是因为文件权限问题。‌ 在Docker中部署Redis Sentinel时,如果配置文件没有正确的读写权限,Sentinel就无法保存新的配置到磁盘上

修改配置文件的权限‌:确保配置文件有适当的读写权限。可以通过以下命令修改权限:

sudo chmod 777 ./sentinel1.conf ./sentinel2.conf ./sentinel3.conf

这会将配置文件的权限设置为可读、可写、可执行,确保Sentinel能够正常保存配置

出现Reading the configuration file, at line 3 redis-sentinel-2 | >>> ‘sentinel monitor redis-master redis-master 6379 2’
redis-sentinel-2 | Can’t resolve master instance hostname.错误时,表示无法正确解析到主节点的ip地址

在这里插入图片描述

主要原因docker启动容器的时候,会把容器分配在不同的虚拟局域网中,此时主从节点和哨兵节点不在同一个虚拟局域网中,所以也就解析不了主节点的ip地址了。

可通过如下指令查看当前docker容器有哪些虚拟局域网:

docker network ls

主从节点与哨兵节点不在同一个局域网中,此时需要修改用于启动哨兵节点的配置文件docker-compose.yml文件。将虚拟局域网部分改为

networks:default:external:name: redis-slave_default

然后执行docker-compose down 命令将对应的哨兵节点关闭移除掉,然后在调用docker-compose up -d创建启动哨兵节点:

#关闭移除哨兵节点
sudo docker-compose down
#创建启动哨兵节点
sudo docker-compose up -d

哨兵节点启动成功后的日志

在这里插入图片描述

也可以通过如下指令,查看单个哨兵的日志:

#查看docker容器中启动的容器,可以得到哨兵节点的名称,ID
sudo docker ps -a
#得到sentinel名称,ID以后
sudo docker logs 容器的名称(或ID)

在这里插入图片描述

5.观察 redis-sentinel 的配置 rewrite

再次打开哨兵的配置⽂件, 发现⽂件内容已经被⾃动修改了

#配置文件信息
bind 0.0.0.0
port 26379
sentinel myid ccdae87d81bf00f23ca6d4ab869571ef046be71f
sentinel deny-scripts-reconfig yes
# Generated by CONFIG REWRITE
dir "/data"
sentinel monitor redis-master 172.18.0.3 6379 2
sentinel down-after-milliseconds redis-master 1000
sentinel config-epoch redis-master 0
sentinel leader-epoch redis-master 0
sentinel known-replica redis-master 172.18.0.4 6379
sentinel known-replica redis-master 172.18.0.2 6379
sentinel known-sentinel redis-master 172.18.0.6 26379 3b77e18de5fb4ce0bc214f6aa2665b77429a80f2
sentinel known-sentinel redis-master 172.18.0.5 26379 0ccfa9143d636099702b86b36daee36275818d1b
sentinel current-epoch 0

三、redis哨兵的选举机制

3.1 redis-master宕机之后的情况

为了让主节点宕机,我们可以手动把它关掉:

sudo docker stop redis-master

观察哨兵的⽇志:

在这里插入图片描述

可以看到哨兵发现了主节点 sdown, 进⼀步的由于主节点宕机得票达到 3/2 , 达到法定得票, 于是 master 被判定为 odown

  • 主观下线 (Subjectively Down, sdown): 哨兵感知到主节点没⼼跳了. 判定为主观下线

  • 客观下线 (Objectively Down, odown): 多个哨兵达成⼀致意⻅, 才能认为 master 确实下线了

接下来, 哨兵们挑选出了⼀个新的 master. 在上图中, 是 172.18.0.2:6379 这个节点

在这里插入图片描述

此时, 对于 Redis 来说仍然是可以正常使⽤的

3.2 重启redis-master后的情况

⼿动把 redis-master 启动起来:

sudo docker start redis-master

观察哨兵⽇志,可以看到刚才新启动的redis-master 被当成了 slave

在这里插入图片描述

可以登录该客户端执行验证:

redis-cli -p 6379

然后执行写的命令:

set key 'hello'

在这里插入图片描述

此时的redis-master(从节点)已经没有了写的权限。

总结:

  • Redis 主节点如果宕机, 哨兵会主观的认为主节点下线了,当主观认为主节点下线的票数超过一半以后,哨兵节点就会客观认为主节点下线了。

  • 然后哨兵节点会进行投票选举出一个leader哨兵节点(票数需要大于等于二分之一),来让从节点变成主节点。

  • 当之前的 Redis 主节点重启之后, 这个主节点被加⼊到哨兵的监控中, 但是只会被作为从节点使⽤.

四、redis哨兵机制的原理

假定当前环境如上⽅介绍, 三个哨兵(sentinel1, sentinel2, sentinel3), ⼀个主节点(redis-master), 两个从节点(redis-slave1, redis-slave2),当主节点出现故障, 就会触发⼀系列过程

在这里插入图片描述

4.1主观下线

当 redis-master 宕机, 此时 redis-master 和三个哨兵之间的⼼跳包就没有了,此时,站在三个哨兵的⻆度来看,redis-master 出现严重故障,因此三个哨兵均会把 redis-master 判定为主观下线 (sdown)

4.2客观下线

此时, 哨兵 sentinel1, sentinel2, sentinel3 均会对主节点故障这件事情进⾏投票. 当认为主节点下线的票数 >= 配置的法定票数之后,此时意味着 redis-master 故障这个事情被做实了,此时触发客观下线 (odown)

配置的法定票数

sentinel monitor redis-master 172.22.0.4 6379 2

在我们写哨兵节点的三个配置文件的时候,此处所写的2就是法定票数

4.3选举leader节点

接下来需要哨兵把剩余的 slave 中挑选出⼀个新的 master. 这个⼯作不需要所有的哨兵都参与. 只需要选出个代表 (称为 leader), 由 leader 负责进⾏ slave 升级到 master 的提拔过程,这个选举的过程涉及到 Raft 算法

假定⼀共三个哨兵节点, S1, S2, S3,选举过程如下:

  1. 每个哨兵节点都给其他所有哨兵节点, 发起⼀个 “拉票请求”. (S1 -> S2, S1 -> S3, S2 -> S1, S2 -> S3, S3 -> S1, S3 -> S2)
  2. 收到拉票请求的节点, 会回复⼀个 “投票响应”. 响应的结果有两种可能, 投 or 不投,每个节点只有一次投票机会,投了就不能再投了
  3. ⼀轮投票完成之后, 发现得票超过法定票数的节点, ⾃动成为 leader。如果出现平票的情况 (S1 投 S2, S2 投 S3, S3 投 S1, 每⼈⼀票), 就重新再投⼀次即可,这也是为啥建议哨兵节点设置成奇数个的原因. 如果是偶数个, 则增⼤了平票的概率, 带来不必要的开销.
  4. leader 节点负责挑选⼀个 slave 成为新的 master. 当其他的 sentenal 发现新的 master 出现了, 就说明选举结束了

简⽽⾔之, Raft 算法的核⼼就是 “先下⼿为强”. 谁率先发出了拉票请求, 谁就有更⼤的概率成为 leader,这⾥的决定因素成了 “⽹络延时”. ⽹络延时本⾝就带有⼀定随机性,所以哪个节点成为leader是不确定的,当然这也是无关紧要的,成为leader的目的就是为了提拔一个从节点让其成为主节点。

4.4选出合适的从节点

从节点变成主节点的选举规则:

  1. ⽐较优先级. 优先级⾼(数值⼩的)的上位,优先级是配置⽂件中的配置项( slave-priority 或者 replica-priority )
  2. ⽐较 replication offset 谁复制的数据多,⾼的上位
  3. ⽐较 run id , 谁的 id ⼩, 谁上位

当某个 slave 节点被指定为 master 之后,

  1. leader 指定该节点执⾏ slave no one , 成为 master
  2. leader 指定剩余的 slave 节点, 都依附于这个新 master

4.5哨兵机制小结

上述过程, 都是 “⽆⼈值守” , Redis ⾃动完成的. 这样做就解决了主节点宕机之后需要⼈⼯⼲预的问题, 提⾼了系统的稳定性和可⽤性

⼀些注意事项:

  • 哨兵节点不能只有⼀个,否则哨兵节点挂了也会影响系统可⽤性

  • 哨兵节点最好是奇数个,⽅便选举 leader,得票更容易超过半数

  • 哨兵节点不负责存储数据,仍然是 redis 主从节点负责存储

  • 哨兵 + 主从复制解决的问题是 “提⾼可⽤性”, 不能解决 “数据极端情况下写丢失” 的问题

  • 哨兵 + 主从复制不能提⾼数据的存储容量,当我们需要存的数据接近或者超过机器的物理内存,这样的结构就难以胜任了,此时就需要引入集群结构了。

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

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

相关文章

如何在 IIS 上部署 .NET Core 应用程序 ?

在 Internet 信息服务 (IIS) 上部署 .NET Core 应用程序起初可能看起来令人生畏,但只要步骤正确,它就是一个简单的过程。本指南将引导您在 IIS 上部署 .NET Core 应用程序。 Step 1: 安装 .NET Core Hosting Bundle (1) 前往官方下载页面 .NET downloa…

蓝桥杯每日真题 - 第24天

题目:(货物摆放) 题目描述(12届 C&C B组D题) 解题思路: 这道题的核心是求因数以及枚举验证。具体步骤如下: 因数分解: 通过逐一尝试小于等于的数,找到 n 的所有因数…

【前端】Next.js 服务器端渲染(SSR)与客户端渲染(CSR)的最佳实践

关于Next.js 服务器端渲染(SSR)与客户端渲染(CSR)的实践内容方面,我们按下面几点进行阐述。 1. 原理 服务器端渲染 (SSR): 在服务器上生成完整的HTML页面,然后发送给客户端。这使得用户在首次访问时能够…

【机器学习】机器学习的基本分类-监督学习-逻辑回归-对数似然损失函数(Log-Likelihood Loss Function)

对数似然损失函数(Log-Likelihood Loss Function) 对数似然损失函数是机器学习和统计学中广泛使用的一种损失函数,特别是在分类问题(例如逻辑回归、神经网络)中应用最为广泛。它基于最大似然估计原理,通过…

基于BERT的语义分析实现

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

HarmonyOS NEXT应用开发,关于useNormalizedOHMUrl选项的坑

起因是这样的:我这库打包发布出问题了,这个有遇到的吗? 源码里面就没有 request .d.ts,这打包后哪来个这文件?且漏掉了其他文件。 猫哥csdn.yyz_1987 为啥我打包的har里面,只有接口,没有具体实现呢&#x…

单点登录原理

允许跨域–>单点登录。 例如https://www.jd.com/ 同一个浏览器下:通过登录页面产生的cookie里的一个随机字符串的标识,在其他子域名下访问共享cookie获取标识进行单点登录,如果没有该标识则返回登录页进行登录。 在hosts文件下面做的域名…

基于Java的小程序电商商城开源设计源码

近年来电商模式的发展越来越成熟,基于 Java 开发的小程序电商商城开源源码,为众多开发者和企业提供了构建个性化电商平台的有力工具。 基于Java的电子商城购物平台小程序的设计在手机上运行,可以实现管理员;首页、个人中心、用户…

Linux查看网络基础命令

文章目录 Linux网络基础命令1. ifconfig 和 ip一、ifconfig命令二、ip命令 2. ss命令一、基本用法二、常用选项三、输出信息四、使用示例 3. sar 命令一、使用sar查看网络使用情况 4. ping 命令一、基本用法二、常用选项三、输出结果四、使用示例 Linux网络基础命令 1. ifconf…

SpringMVC工作原理【流程图+文字详解SpringMVC工作原理】

SpringMVC工作原理 前端控制器:DispactherServlet处理器映射器:HandlerMapping处理器适配器:HandlerAdapter处理器:Handler,视图解析器:ViewResolver视图:View 首先用户通过浏览器发起HTTP请求…

12寸先进封装设备之-晶圆减薄一体机

晶圆减薄一体机在先进封装厂中的主要作用是对已完成功能的晶圆(主要是硅晶片)的背面基体材料进行磨削,去掉一定厚度的材料,以满足后续封装工艺的要求以及芯片的物理强度、散热性和尺寸要求。随着3D封装技术的发展,晶圆厚度需要减薄至50-100μm甚至更薄,以实现更好的散热效…

Online Judge——【前端项目初始化】项目通用布局开发及初始化

目录 一、新建layouts二、更新App.vue文件三、选择一个布局(Layout)四、通用菜单Menu的实现菜单路由改为读取路由文件 五、绑定跳转事件六、同步路由到菜单项 一、新建layouts 这里新建一个专门存放布局的布局文件layouts: 然后在该文件夹&…

十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize

1. AJAX介绍及axios基本使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content&q…

53 基于单片机的8路抢答器加记分

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 首先有三个按键 分别为开始 暂停 复位&#xff0c;然后八个选手按键&#xff0c;开机显示四条杠&#xff0c;然后按一号选手按键&#xff0c;数码管显示&#xff13;&#xff10;&#xff0c;这…

【深度学习】各种卷积—卷积、反卷积、空洞卷积、可分离卷积、分组卷积

在全连接神经网络中&#xff0c;每个神经元都和上一层的所有神经元彼此连接&#xff0c;这会导致网络的参数量非常大&#xff0c;难以实现复杂数据的处理。为了改善这种情况&#xff0c;卷积神经网络应运而生。 一、卷积 在信号处理中&#xff0c;卷积被定义为一个函数经过翻转…

前端页面或弹窗在线预览文件的N种方式

需求&#xff1a;后端返回给前端一个地址后&#xff0c;在前端页面上或则在弹框中显示在线的文档、表格、图片、pdf、video等等&#xff0c;嵌入到前端页面 方式一&#xff1a; 使用vue-office 地址&#xff1a;vue-office简介 | vue-office 个人感觉这个插件是最好用的&#x…

Windsurf可以上传图片开发UI了

背景 曾经羡慕Cursor的“画图”开发功能&#xff0c;这不Windsurf安排上了。 Upload Images to Cascade Cascade now supports uploading images on premium models Ask Cascade to build or tweak UI from on image upload New keybindings Keybindings to navigate betwe…

ArraList和LinkedList区别

文章目录 一、结构不同二、访问速度三、插入和删除操作的不同1、决定效率有两个因素&#xff1a;数据量和位置。2、普遍说法是“LinkedList添加删除快”&#xff0c;这里是有前提条件的 四、内存占用情况五、使用场景六、总结 一、结构不同 LinkedList&#xff1a;它基于双向链…

【模型剪枝】YOLOv8 模型剪枝实战 | 稀疏化-剪枝-微调

文章目录 0. 前言1. 模型剪枝概念2. 模型剪枝实操2.1 稀疏化训练2.2 模型剪枝2.3 模型微调总结0. 前言 无奈之下,我还是写了【模型剪枝】教程🤦‍♂️。回想当年,在写《YOLOv5/v7进阶实战专栏》 时,我经历了许多挫折,才最终完成了【模型剪枝】和【模型蒸馏】的内容。当时…

关于函数式接口和编程的解析和案例实战

文章目录 匿名内部类“匿名”在哪里 函数式编程lambda表达式的条件Supplier使用示例 ConsumeracceptandThen使用场景 FunctionalBiFunctionalTriFunctional 匿名内部类 匿名内部类的学习和使用是实现lambda表达式和函数式编程的基础。是想一下&#xff0c;我们在使用接口中的方…