阿里云消息队列RabbitMQ版(消息队列 RabbitMQ 版)

admin 100 2022-12-08

阿里云服务器优惠多,折扣错,惊喜多,请咨询:www.wqiis.com

本文目录一览:

简谈阿里云MQ消息队列云服务的计费模式

文章摘要:在阿里云上,就创建了一个消息队列的Topic,其他啥也没干,过了一天就欠阿里云2元了,消息队列这项云服务也太能吸金了吧?

最简单地说,消息队列就是消息在传输过程中用于保存消息的容器,在一次发送接收的通信过程中,其主要充当了“中转站”的角色,内部提供路由并保证消息的可靠传递。如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。

消息队列目前已经逐渐成为企业IT系统内部通信的核心手段之一,可以说当前绝大部分的大型分布式互联网业务系统都基于消息队列来构建的。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列的功能,成为异步通信的主要手段之一。

近几年,随着云计算技术的飞速发展,在IAAS产品已经相对成熟后,其他越来越多的产品也逐步推向了云端(很多中间件产品再用以前liences授权计费的方式已经不再受用)。MQ消息队列是中间件产品中比较重要的产品之一,其云化方案对于云计算平台能力的拓展与丰富有着重要的意义。

MQ(Message Queue)消息队列云服务是构成云计算核心能力不可或缺的一项产品,可以为云端的用户提供一种定义未来云端的应用开发和未来企业的技术架构方案的新方式。对于云端的消息队列服务,如果无法采用传统的liences授权方式计费,那么它又是如何计费的呢?今天我就向大家介绍下消息队列中间件这项云服务在阿里云上是怎么来计费的。

目前,阿里云上主要提供如下两种云化商用版MQ的计费模式:

(1) 预付费(包年包月,MQ 铂金版) :即为业界常说的包周期云服务计费模式,云端客户根据自己的预算以几个月或者一年作为租赁使用周期进行预先付款结算。根据阿里云官方文档的说明:该种计费方式订购的MQ是:“专享实例,独占物理节点”;诸如“专家尊享通道 保价护航”、“SQL 属性过滤”、“数据传输加密”、“多路访问方式”、“VPC SingleTunnel 访问”和“消息轨迹”几个重要的功能特性方面都比(2)中的按量付费版要支持的更加全面和完善一些。其实,从性价比上面来说更加适合一些土豪级的企业级大客户来用了。对于这类用户,可能本身不会去过多的研究MQ的一些关键技术,可以完全依托于阿里云的MQ产品 研发团队核心成员直接为自己的云端系统的构建,提供较为全面的MQ技术支持。

(2) 后付费(按量计费) :即为按量后付费的云服务计费模式,阿里云按照客户端的使用情况(一般,按照“Topic占用时长”+“API的调用次数”来计费的,具体的计费方法后面还会再讲)。各方面的功能都弱于(1)中的预付费版本。这种方式比较适合对MQ关键技术有一定了解的初中级使用者,完全可以按照自己的需求来构建适合云端业务系统的MQ。

解读:从上面这段阿里云官网上的计费项目说明中,可以得出以下几点关键信息:

(1) Topic资源占用费 :这部分费用可能往往会被用户忽略。使用MQ消息队列云服务的费用实际是包含两部分的,也就是说像我一样虽然没有用阿里云的MQ消息队列进行消息的发送和消费,但是因为创建并占用着一个Topic一天( Topic也是MQ消息队列资源的一部分 ),因此也会对我的账户进行扣费。所以,这里也提醒各位使用阿里云MQ消息队列云服务的各位童鞋要注意下,对于自己不用的Topic尽快删除,否则也会产生资费;

(2) API调用次数 :这部分的第一点应该比较好理解,对于MQ消息队列的使用(即为消息的发送和接收),需要按照调用Client端的API发送消息或者消费消息的次数来进行累计产生资费。但是,对于第二点没有实际使用过RocketMQ的童鞋可能不太好理解。在RocketMQ中,在Push的消费模式中有长轮询机制,如果Consumer端第一次发送Pull消息的请求至Broker,此时Broker端尚无可消费的消息时,会先hold住该Pull消息的请求,通过Broker端的两个后台线程服务—PullRequestHoldService和ReputMessageService来重新尝试Pull消息和二次处理。这里,默认长轮询的RPC通信的超时时间为30s,而Broker端挂起Pull消息请求的最长时间即为15s。从这里来看,第一次hold住Pull请求的15s是不计费长轮询次数的(即为不计费的,我认为因为hold住Pull请求是broker端来完成的本身就不会带来PRC远程通信的一次调用),倘若第二次从consumer端再发起长轮询请求则会进行计费,我个人想想觉得也合理的,因为毕竟会耗费一次RPC的远程通信访问。

这里列出下阿里云MQ消息队列云服务两种计费项目的列表展示:

对于上面的计费说明,从中可以看出关键信息有如下几点:

(1)阿里云MQ消息队列云服务是支持ACL权限分配的,可以将主账号创建的Topic分配给子帐号使用,子帐号产生的计费将会算到主账号上;

(2)MQ的后付费产品的结算方式应该是采用了根据出MQ云服务资源计量文件以后次日(T+1日来根据资源计量文件生成账单从账户扣费),这种方式就会存在余额不足的小风险(ps:欠费72小时后阿里云会自动清理该用户下面的Topic及其未消费而积压的存量消息);

(3)计费中比较关键的一点是“每 4 KB 发布或订阅数据以 1 次请求计费”,我认为这一点倒也合乎情理,消息发送或者接收本质上来说是一次RPC通信(基于TCP连接),那么按照消息大小来合理设置请求计费次数,即为对占用TCP带宽大小和吞吐量的计费。这一点在用户使用时候可能会忽略;

(4)事务消息、顺序消息和定时消息均比普通消息的计费价格来得更贵更高,所以使用的童鞋要好好考虑下发送和订阅这三类消息产生的资费问题;

本文主要根据自己在阿里云上使用MQ消息队列云服务的一些经验展开叙述,从技术开发者的视角来看MQ消息队列云服务的产品概念和定义,并对阿里云MQ消息队列云服务的计费模式和方法进行深入分析。限于笔者的才疏学浅,对本文内容可能还有理解不到位的地方,如有阐述不合理之处还望留言一起探讨。

RabbitMQ 进阶- 阿里云服务器部署RabbitMQ集群

如果RabbitMQ集群只有一个broker节点,那么该节点的失效将导致整个服务临时性的不可用,并且可能会导致message的丢失(尤其是在非持久化message存储于非持久化queue中的时候)。可以将所有message都设置为持久化,并且使用持久化的queue,但是这样仍然无法避免由于缓存导致的问题:因为message在发送之后和被写入磁盘并执行fsync之间存在一个虽然短暂但是会产生问题的时间窗。通过publisher的confirm机制能够确保客户端知道哪些message已经存入磁盘,尽管如此,一般不希望遇到因单点故障导致服务不可用。

如果RabbitMQ集群是由多个broker节点构成的,那么从服务的整体可用性上来讲,该集群对于单点失效是有弹性的,但是同时也需要注意:尽管exchange和binding能够在单点失效问题上幸免于难,但是queue和其上持有的message却不行,这是因为queue及其内容仅仅存储于单个节点之上,所以一个节点的失效表现为其对应的queue不可用。

为了提高程序的吞吐量,保持消息的可靠性,一台机器挂了后,RabbitMQ能够正常生产,消费消息。

rabbitmq有三种模式:单机模式,普通集群模式,镜像集群模式

Demo级别的,一般只是本机测试玩玩而已,生产环境下不会用的。

在多台机器上启动多个rabbitmq实例,每个机器启动一个。

但是你创建的queue,只会放在一个rabbtimq实例上,但是每个实例都同步queue的元数据(存放含queue数据的真正实例位置)。消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。

示意图

这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集群。

普通集群的方式,确实达到了消息的高可用,但没办法保证可靠性,没做到分布式,简而言之,只是一个普通的集群。

这种模式,才是所谓的rabbitmq的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。

上图中每个节点有一个queue,生产者生产完毕数据后投递到指定交换机的队列,交换机的队列进行消息同步。

每个节点queue都有一个完整的rabbitmq节点,所以这种方式叫做镜像集群

好处: 任何一个节点宕机后,其它节点不受影响,正常使用

坏处:

确保机器中安装了Docker,若未安装,可看:【云原生】Docker入门 – 阿里云服务器Linux环境下安装Docker

查看拉取的镜像

成功运行

设置节点1

浏览器输入 您的ip地址:15673

再次测试即可成功~

File — New — Project — Maven — 直接Next 进入下一步创建普通的Maven工程即可

创建一个默认的Maven聚合工程,将src文件夹删除,该工程就是一个Maven聚合工程

引入依赖如下:

在项目内,新建一个Moudle,rabbitmq-order-producer 默认Maven工程,下一步即可

在项目内,新建一个Moudle,rabbitmq-order-cousumer 默认Maven工程,下一步即可

Maven聚合工程创建完成图

Maven依赖图

自行手写MainApplication即可

创建完成!

编写完成!

启动消费者

交换机

=

15674

15675

成功消费数据!

已成功同步消息~

消息队列之RabbitMQ-分布式部署

RabbitMQ分布式部署有3种方式:

Federation与Shovel都是以插件的形式来实现,复杂性相对高,而集群是RabbitMQ的自带属性,相对简单。

这三种方式并不是互斥的,可以根据需求选择相互组合来达到目的。

RabbitMQ本身是基于Erlang编写,Erlang语言天生具备分布式特性(通过同步Erlang集群各节点的magic cookie来实现)。

因此,RabbitMQ天然支持Clustering。这使得RabbitMQ本身不需要像ActiveMQ、Kafka那样通过ZooKeeper分别来实现HA方案和保存集群的元数据。集群是保证可靠性的一种方式,同时可以通过水平扩展以达到增加消息吞吐量能力的目的。

我们把部署RabbitMQ的机器称为节点,也就是broker。broker有2种类型节点: 磁盘节点 和 内存节点 。顾名思义,磁盘节点的broker把元数据存储在磁盘中,内存节点把元数据存储在内存中,很明显,磁盘节点的broker在重启后元数据可以通过读取磁盘进行重建,保证了元数据不丢失,内存节点的broker可以获得更高的性能,但在重启后元数据就都丢了。

元数据包含以下内容:

单节点系统必须是磁盘节点 ,否则每次你重启RabbitMQ之后所有的系统配置信息都会丢失。

集群中至少有一个磁盘节点 ,当节点加入和离开集群时,必须通知磁盘 节点。

如果集群中的唯一一个磁盘节点,结果这个磁盘节点还崩溃了,那会发生什么情况?集群依然可以继续路由消息(因为其他节点元数据在还存在),但无法做以下操作:

也就是说,如果唯一磁盘的磁盘节点崩溃, 集群是可以保持运行的,但不能更改任何东西 。为了增加可靠性,一般会在集群中设置两个磁盘节点,只要任何一个处于工作状态,就可以保障集群的正常服务。

RabbitMQ的集群模式分为两种: 普通模式 与 镜像模式 。

普通模式,也是默认的集群模式。

对于Queue来说, 消息实体只存在于其中一个节点 ,A、B两个节点仅有相同的元数据,即队列结构。当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连A或B,出口总在A,会产生瓶颈。

队列所在的节点称为 宿主节点 。

队列创建时,只会在宿主节点创建队列的进程,宿主节点包含完整的队列信息,包括元数据、状态、内容等等。因此, 只有队列的宿主节点才能知道队列的所有信息 。

队列创建后,集群只会同步队列和交换器的元数据到集群中的其他节点,并不会同步队列本身,因此 非宿主节点就只知道队列的元数据和指向该队列宿主节点的指针 。

假如现在一个客户端需要对Queue A进行发布或者订阅,发起与集群的连接,有两种可能的场景:

由于节点之间存在路由转发的情况,对延迟非常敏感,应当只在本地局域网内使用,在广域网中不应该使用集群,而应该用Federation或者Shovel代替。

这样的设计,保证了不论从哪个broker中均可以消费所有队列的数据,并分担了负载,因此,增加broker可以线性提高服务的性能和吞吐量。

但该方案也有显著的缺陷,那就是 不能保证消息不会丢失 。当集群中某一节点崩溃时,崩溃节点所在的队列进程和关联的绑定都会消失,附加在那些队列上的消费者也会丢失其订阅信息,匹配该队列的新消息也会丢失。比如A为宿主节点,当A节点故障后,B节点无法取到A节点中还未消费的消息实体。如果做了消息持久化,那么得等A节点恢复,然后才可被消费;如果没有持久化的话,然后就没有然后了……

肯定有不少同学会问,想要实现HA方案,那将RabbitMQ集群中的所有Queue的完整数据在所有节点上都保存一份不就可以了吗?比如类似MySQL的主主模式,任何一个节点出现故障或者宕机不可用时,那么使用者的客户端只要能连接至其他节点,不就能够照常完成消息的发布和订阅吗?

RabbitMQ这么设计是基于性能和存储空间上来考虑:

引入 镜像队列 (Mirror Queue)的机制,可以将队列镜像到集群中的其他Broker节点之上,如果集群中的一个节点失效了,队列能够自动切换到镜像中的另一个节点上以保证服务的可用性。

一个镜像队列中包含有1个主节点master和若干个从节点slave。其主从节点包含如下几个特点:

该模式和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

一个队列想做成镜像队列,需要先设置policy,然后客户端创建队列的时候,rabbitmq集群根据队列名称自动设置为普通队列还是镜像队列。

镜像队列的配置通过添加policy完成,policy添加的命令为:

例如,对队列名称以hello开头的所有队列进行镜像,并在集群的两个节点上完成镜像,policy的设置命令为:

rabbitmqctl set_policy hello-ha "^hello" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

通常队列由两部分组成:一部分是AMQQueue,负责AMQP协议相关的消息处理,即接收生产者发布的消息、向消费者投递消息、处理消息confirm、acknowledge等等;另一部分是BackingQueue,它提供了相关的接口供AMQQueue调用,完成消息的存储以及可能的持久化工作等。

镜像队列基本上就是一个特殊的BackingQueue,它内部包裹了一个普通的BackingQueue做本地消息持久化处理,在此基础上增加了将消息和ack复制到所有镜像的功能。所有对mirror_queue_master的操作,会通过组播GM(下面会讲到)的方式同步到各slave节点。GM负责消息的广播,mirror_queue_slave负责回调处理,而master上的回调处理是由coordinator负责完成。mirror_queue_slave中包含了普通的BackingQueue进行消息的存储,master节点中BackingQueue包含在mirror_queue_master中由AMQQueue进行调用。

消息的发布(除了Basic.Publish之外)与消费都是通过master节点完成。master节点对消息进行处理的同时将消息的处理动作通过GM广播给所有的slave节点,slave节点的GM收到消息后,通过回调交由mirror_queue_slave进行实际的处理。

GM(Guarenteed Multicast) 是一种可靠的组播通讯协议,该协议能够保证组播消息的原子性,即保证组中活着的节点要么都收到消息要么都收不到。它的实现大致如下:

将所有的节点形成一个循环链表,每个节点都会监控位于自己左右两边的节点,当有节点新增时,相邻的节点保证当前广播的消息会复制到新的节点上;当有节点失效时,相邻的节点会接管保证本次广播的消息会复制到所有的节点。在master节点和slave节点上的这些gm形成一个group,group(gm_group)的信息会记录在mnesia中。不同的镜像队列形成不同的group。消息从master节点对于的gm发出后,顺着链表依次传送到所有的节点,由于所有节点组成一个循环链表,master节点对应的gm最终会收到自己发送的消息,这个时候master节点就知道消息已经复制到所有的slave节点了。

slave节点先从gm_group中获取对应group的所有成员信息,然后随机选择一个节点并向这个节点发送请求,这个节点收到请求后,更新gm_group对应的信息,同时通知左右节点更新邻居信息(调整对左右节点的监控)及当前正在广播的消息,然后回复通知请求节点成功加入group。请求加入group的节点收到回复后再更新rabbit_queue中的相关信息,并根据需要进行消息的同步。

当slave节点失效时,仅仅是相邻节点感知,然后重新调整邻居节点信息、更新rabbit_queue、gm_group的记录等。如果是master节点失效,"资格最老"的slave节点被提升为master节点,slave节点会创建出新的coordinator,并告知gm修改回调处理为coordinator,原来的mirror_queue_slave充当amqqueue_process处理生产者发布的消息,向消费者投递消息等。

上面提到如果是slave节点失效,只有相邻的节点能感知到,那么master节点失效是不是也是只有相邻的节点能感知到?假如是这样的话,如果相邻的节点不是"资格最老"的节点,怎么通知"资格最老"的节点提升为新的master节点呢?

实际上,所有的slave节点在加入group时,mirror_queue_slave进程会对master节点的amqqueue_process进程(也可能是mirror_queue_slave进程)进行监控,如果master节点失效的话,mirror_queue_slave会感知,然后再通过gm进行广播,这样所有的节点最终都会知道master节点失效。当然,只有"资格最老"的节点会提升自己为新的master。

消息从master节点发出,顺着节点链表发送。在这期间,所有的slave节点都会对消息进行缓存,当master节点收到自己发送的消息后,会再次广播ack消息,同样ack消息会顺着节点链表经过所有的slave节点,其作用是通知slave节点可以清除缓存的消息,当ack消息回到master节点时对应广播消息的生命周期结束。

下图为一个简单的示意图,A节点为master节点,广播一条内容为"test"的消息。"1"表示消息为广播的第一条消息;"id=A"表示消息的发送者为节点A。右边是slave节点记录的状态信息。

为什么所有的节点都需要缓存一份发布的消息呢?

master发布的消息是依次经过所有slave节点,在这期间的任何时刻,有可能有节点失效,那么相邻的节点可能需要重新发送给新的节点。例如,A-B-C-D-A形成的循环链表,A为master节点,广播消息发送给节点B,B再发送给C,如果节点C收到B发送的消息还未发送给D时异常结束了,那么节点B感知后节点C失效后需要重新将消息发送给D。同样,如果B节点将消息发送给C后,B,C节点中新增了E节点,那么B节点需要再将消息发送给新增的E节点。

配置镜像队列的时候有个 ha-sync-mode 属性,这个有什么用呢?

新节点加入到group后,最多能从左边节点获取到当前正在广播的消息内容,加入group之前已经广播的消息则无法获取到。如果此时master节点不幸失效,而新节点有恰好成为了新的master,那么加入group之前已经广播的消息则会全部丢失。

注意:这里的消息具体是指新节点加入前已经发布并复制到所有slave节点的消息,并且这些消息还未被消费者消费或者未被消费者确认。如果新节点加入前,所有广播的消息被消费者消费并确认了,master节点删除消息的同时会通知slave节点完成相应动作。这种情况等同于新节点加入前没有发布任何消息。

避免这种问题的解决办法就是对新的slave节点进行消息同步。当 ha-sync-mode 配置为自动同步(automatic)时,新节点加入group时会自动进行消息的同步;如果配置为manually则需要手动操作完成同步。

Federation直译过来是联邦,它的设计目标是使 RabbitMQ 在不同的 Broker 节点之间进行消息传递而无须建

立集群。具有以下特点:

那么它到底有什么用呢?我们可以从一个实际场景入手:

有两个服务分别部署在国内和海外,它们之间需要通过消息队列来通讯。

很明显无论RabbitMQ部署在海外还是国内,另一方一定得忍受连接上的延迟。因此我们可以在海外和国内各部署一个MQ,这样一来海外连接海外的MQ,国内连接国内,就不会有连接上的延迟了。

但这样还会有问题,假设某生产者将消息存入海外MQ中的某个队列 queueB , 在国内的服务想要消费 queueB 消息,消息的流转及确认必然要忍受较大的网络延迟 ,内部编码逻辑也会因这一因素变得更加复杂。

此外,服务可能得维护两个MQ的配置,比如国内服务在生产消息时得使用国内MQ,消费消息时得监听海外MQ的队列,降低了系统的维护性。

可能有人想到可以用集群,但是RabbitMQ的集群对延迟非常敏感,一般部署在局域网内,如果部署在广域网可能会产生网络分区等等问题。

这时候,Federation就派上用场了。它被设计成能够容忍不稳定的网络连接情况,完全能够满足这样的场景。

那使用Federation之后是怎样的业务流程呢?

首先我们在海外MQ上定义exchangeA,它通过路由键“rkA”绑定着queueA。然后用Federation在exchangeA上建立一条 单向 连接到国内RabbitMQ,Federation则自动会在国内RabbitMQ建立一个exchangeA交换器(默认同名)。

这时候,如果部署在国内的client C在国内MQ上publish了一条消息,这条消息会通过 Federation link 转发到海外MQ的交换器exchangeA中,最终消息会存入与 exchangeA 绑定的队列 queueA 中,而client C也能立即得到返回。

实际上,Federation插件还会在国内MQ建立一个内部的交换器:exchangeA→ broker3 B(broker3是集群名),并通过路由键 "rkA"将它和国内MQ的exchangeA绑定起来。接下来还会在国内MQ上建立一个内部队列federation: exchangeA-broker3 B,并与内部exchange绑定。这些操作都是内部的,对客户端来说是透明的。

值得一提的是,Federation的连接是单向的,如果是在海外MQ的exchangeA上发送消息是不会转到国内的。

这种在exchange上建立连接进行联邦的,就叫做 联邦交换器 。一个联邦交换器接收上游(upstream)的信息,这里的上游指的是其他的MQ节点。

对比前面举的例子,国内MQ就是上游,联邦交换器能够将原本发送给上游交换器的消息路由到本地的某个队列中。

有联邦交换器自然也有联播队列,联邦队列则允许一个本地消费者接收到来自上游队列的消息 。

如图,海外MQ有队列A,给其设置一条链接,Federation则自动会在国内RabbitMQ建立一个队列A(默认同名)。

当有消费者 ClinetA连接海外MQ并消费 queueA 中的消息时,如果队列 queueA中本身有若干消息堆积,那么 ClientA直接消费这些消息,此时海外MQ中的queueA并不会拉取国内中的 queueA 的消息;如果队列 queueA中没有消息堆积或者消息被消费完了,那么它会通过 Federation link 拉取上游队列 queueA 中的消息(如果有消息),然后存储到本地,之后再被消费者 ClientA进行消费 。

首先开启Federation 功能:

值得注意的是,当需要在集群中使用 Federation 功能的时候,集群中所有的节点都应该开启 Federation 插件。

接下来我们要配置两个东西:upstreams和Policies。

每个 upstream 用于定义与其他 Broker 建立连接的信息。

通用参数如下:

然后定义一个 Policy, 用于匹配交换器:

^exchange 意思是将匹配所有以exchange名字开头的交换器,为它们在上游创建连接。这样就创建了一个 Federation link。

Shovel是RabbitMQ的一个插件, 能够可靠、持续地从一个Broker 中的队列(作为源端,即source )拉取数据并转发至另一个Broker 中的交换器(作为目的端,即destination )。作为源端的队列和作为目的端的交换器可以同时位于同一个 Broker 上,也可以位于不同的 Broker 上。

使用Shovel有以下优势:

使用Shovel时,通常源为队列,目的为交换器:

但是,也可以源为队列,目的为队列。实际也是由交换器转发,只不过这个交换器是默认交换器。配置交换器做为源也是可行的。实际上会在源端自动新建一个队列,消息先存在这个队列,再被Shovel移走。

使用Shovel插件命令:

Shovel 既可以部署在源端,也可以部署在目的端。有两种方式可以部署 Shovel:

其主要差异如下:

来看一个使用Shovel治理消息堆积的案例。

当某个队列中的消息堆积严重时,比如超过某个设定的阈值,就可以通过 Shovel 将队列中的消息移交给另一个集群。

上一篇:腾讯云实例(腾讯云实例密码)
下一篇:华为云asm(华为云AS是什么)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~