Hadoop YARN HA 集群安装部署详细图文教程

目录

一、YARN 集群角色、部署规划

1.1 集群角色--概述

1.2 集群角色--ResourceManager(RM) 

1.3 集群角色--NodeManager(NM) 

1.4 HA 集群部署规划

二、YARN RM 重启机制

2.1 概述 

2.2 演示 

2.2.1 不开启 RM 重启机制现象 

2.3 两种实现方案与区别 

2.3.1 Non-work-preserving RM restart

2.3.2 Work-preserving RM restart

2.3.3 RM 状态数据的存储介质 

2.4 ZKRMStateStore 

2.5 配置 

2.5.1 yarn-site.xml 

2.6 演示

2.6.1 开启 RM 重启机制现象

三、YARN HA 集群 

3.1 背景 

​3.2 架构 

3.3 故障转移机制 

3.4 故障转移原理(基于 zk 自动切换) 

3.5 搭建步骤 

3.5.1 修改 yarn-site.xml

3.5.2 集群同步 yarn-site.xml 配置文件 

3.5.3 启动 

3.5.4 状态查看 

3.5.5 Web UI 查看

3.5.6 自动故障切换 


 

一、YARN 集群角色、部署规划

1.1 集群角色--概述

        Apache Hadoop YARN 是一个标准的 Master/Slave 集群(主从架构)其中 ResourceManagerRM) 为 MasterNodeManagerNM) 为 Slave。常见的是一主多从集群,也可以搭建 RM 的 HA 高可用集群。

1.2 集群角色--ResourceManagerRM 

        RM 是 YARN 中的主角色,决定系统中所有应用程序之间资源分配的最终权限,即最终仲裁者。RM 接收用户的作业提交,并通过 NodeManager 分配、管理各个机器上的计算资源。资源以 Container 形式给与。

        此外,RM 还具有个可插拔组件 scheduler,负责为各种正在运行的应用程序分配资源,根据策略进行调度。

1.3 集群角色--NodeManagerNM 

        NM 是 YARN 的从角色,一台机器上一个,负责管理本机器上的计算资源。NM 根据 RM 命令,启动 Container 容器、监视容器的资源使用情况。并且向 RM 主角色汇报资源使用情况。

1.4 HA 集群部署规划

        理论上 YARN 集群可以部署在任意机器上,但是实际中,通常把 NodeManager 和 DataNode 部署在同一台机器上。(有数据的地方就有可能产生计算,移动程序的成本比移动数据的成本低

作为 Apache Hadoop 一部分,通常会把 YARN 集群和 HDFS 集群一起搭建。

IP

服务器

运行角色

192.168.170.136

hadoop01

namenode datanode resourcemanager nodemanager

192.168.170.137

hadoop02

namenode resourcemanager secondarynamenode datanode nodemanager

192.168.170.138

hadoop03

datanode nodemanage

首先安装 Hadoop 集群:HDFS HA 高可用集群搭建详细图文教程_Stars.Sky的博客-CSDN博客

二、YARN RM 重启机制

2.1 概述 

        ResourceManager 负责资源管理和应用的调度,是 YARN 的核心组件,存在单点故障的问题。ResourceManager Restart 重启机制是使 RM 在重启动时能够使 Yarn 集群正常工作的特性,并且使 RM 的出现的失败不被用户知道。重启机制并不是自动帮我们重启的意思(需要手动启动 RM)。所以说不能解决单点故障问题。

2.2 演示 

2.2.1 不开启 RM 重启机制现象 

首先执行一个程序: 

[root@hadoop02 ~]# cd /bigdata/hadoop/server/hadoop-3.2.4/share/hadoop/mapreduce/
[root@hadoop02 /bigdata/hadoop/server/hadoop-3.2.4/share/hadoop/mapreduce]# yarn jar hadoop-mapreduce-examples-3.2.4.jar pi 10 10

然后快速把 RM kill 掉:

[root@hadoop01 ~]# jps
6467 Jps
5975 NodeManager
4744 QuorumPeerMain
5432 JournalNode
6440 JobHistoryServer
5833 ResourceManager
5038 NameNode
5182 DataNode
5631 DFSZKFailoverController
[root@hadoop01 ~]# kill -9 5833

# 再手动重启 RM
[root@hadoop01 ~]# yarn --daemon start resourcemanager

之前的状态数据没有了:
​程序也运行失败:
​总结:如果 RM 出现故障重启之后,之前的信息将会消失。正在执行的作业也会失败。 

2.3 两种实现方案与区别 

  • Non-work-preserving RM restart

不保留工作的 RM 重启,在 Hadoop 2.4.0 版本实现

  • Work-preserving RM restart

保留工作的 RM 重启,在 Hadoop 2.6.0 版本中实现

        不保留工作 RM 启机制保存了 application 提交的信息和最终执行状态,并不保存运行过程中的相关数据,所以 RM 重启后,会先杀死正在执行的任务,再重新提交,从零开始执行任务

        保留工作 RM 重启机制保存了 application 运行中的状态数据,所以在 RM 重启之后,不需要杀死之前的任务,而是接着原来执行到的进度继续执行。

2.3.1 Non-work-preserving RM restart

        当 Client 提交一个 application 给 RM 时,RM 会将该 application 的相关信息存储起来,具体存储的位置是可以在配置文件中指定的,可以存储到本地文件系统上,也可以存储到 HDFS 或者是 Zookeeper 上,此外 RM 也会保存 application 的最终状态信息(failedkilledfinished),如果是在安全环境下运行,RM 还会保存相关证书文件

        当 RM 被关闭后,NodeManager(以下简称 NM)和 Client 由于发现连接不上 RM,会不断的向 RM 发送消息,以便于能及时确认 RM 是否已经恢复正常,当 RM 重新启动后,它会发送一条re-sync (重新同步)的命令给所有的 NM 和 ApplicationMaster(以下简称 AM)NM 收到重新同步的命令后会杀死所有的正在运行的 containers 并重新向 RM 注册,从 RM 的角度来看,每台重新注册的 NM 跟一台新加入到集群中 NM 是一样的

        AM 收到重新同步的命令后会自行将自己杀掉。接下来,RM 会将存储的关于 application 的相关信息读取出来,将在 RM 关闭之前最终状态为正在运行中的 application 重新提交运行。

2.3.2 Work-preserving RM restart

        与不保留工作不同的地方在于,RM 会记录下 container 的整个生命周期的数据,包括 application 运行的相关数据,资源申请状况,队列资源使用状况等数据

        当 RM 重启之后,会读取之前存储的关于 application 的运行状态的数据,同时发送 re-sync 的命令,与第一种方式不同的是,NM 在接受到重新同步的命令后并不会杀死正在运行的 containers,而是继续运行 containers 中的任务,同时将 containers 的运行状态发送给 RM,之后,RM 根据自己所掌握的数据重构 container 实例和相关的 application 运行状态,如此一来,就实现了在 RM 重启之后,紧接着 RM 关闭时任务的执行状态继续执行

2.3.3 RM 状态数据的存储介质 

        如果启用了 RM 的重启机制,升级为 Active 状态的 RM 会初始化 RM 内部状态和恢复先前活动 RM 留下的状态,这依赖于 RM 的重启特性。而之前提交到 RM 托管的作业会发起新的尝试请求。用户提交的应用可以考虑进行周期性的 CheckPoint 来避免任务丢失。

        RM 的重启机制本质上是将 RM 内部的状态信息写入外部存储介质中。在 RM 启动时会初始化状态信息的目录,当 Application 运行时会将相关的状态写入对应的目录下。如果 RM 发生故障切换或者重启,可以通过外部存储进行恢复。RM 状态存储的实现是 RMStateStore 抽象类,YARN 对 RMStateStore 提供了几种实例:

从类继承图可以看出提供 5 种方式存储状态,比对如下:

状态存储方式

说明

Memory

MemoryRMStateStore 是基于内存的状态存储实现,使用 RMState 对象存储 RM 所有的状态。

ZooKeeper

ZKRMStateStore 是基于 ZooKeeper 的状态存储实现,支持 RM 的 HA,只有基于ZooKeeper 的状态存储支持隔离机制,能避免出现裂脑情况发生,允许有多个处于 Active 状态的 RM 同时编辑状态存储。建议在 YARN 的 HA 中使用。

FileSystem

FileSystemRMStateStore 支持 HDFS 和基于本地 FS 的状态存储实现。不支持隔离机制。

LevelDB

LeveldbRMStateStore 是基于 LevelDB 的状态存储实现,它比基于 HDFS 和 ZooKeeper 的状态存储库更轻巧。LevelDB 支持更好的原子操作,每个状态更新的 I/O 操作更少,文件系统上的文件总数也少得多。不支持隔离机制。

Null

NullRMStateStore 是一个空实现。

2.4 ZKRMStateStore 

        RM 的所有状态信息存储在 ZooKeeper 的 /rmstore/ZKRMStateRoot 下;主要保存了 RM 资源预留信息、应用信息,应用的 Token 信息,RM 版本信息

ZNode名称

说明

ReservationSystemRoot

RM 的资源预留系统,对应的实现是 ReservationSystem 接口的子类。

RMAppRoot

Application 信息,对应的实现是 RMApp 接口的子类。

AMRMTokenSecretManagerRoot

ApplicationAttempt 的 Token 信息,RM 会将每个 Token 保存在本地的内存中,直到应用程序运行完成为止,并保存到 ZooKeeper 存储以供重新启动。对应的实现是 AMRMTokenSecretManager 类。

EpochNode

RM 的保存工作重启的时间信息。每次 RM 重新启动时,纪元都会增加。它用于确保 ContainerId 的唯一性。对应的实现是 Epoch 抽象类。

RMDTSecretManagerRoot

一个特定于 RM 的委托令牌保密管理器。保密管理器负责生成和接受每个令牌的密码。

RMVersionNode

RM 的版本信息。

2.5 配置 

2.5.1 yarn-site.xml 

配置启用 RM 重启功能,使用 Zookeeper 进行转态数据存储。 

[root@hadoop01 ~]# cd /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop/
[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# vim yarn-site.xml 
<property>    
    <name>hadoop.zk.address</name>    
    <value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
<property>    
    <name>yarn.resourcemanager.recovery.enabled</name>    
    <value>true</value>
</property>
<property>
    <name>yarn.resourcemanager.store.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>

[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# scp -r yarn-site.xml root@hadoop02:$PWD
yarn-site.xml                                                                                                         100% 2307     1.1MB/s   00:00    
[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# scp -r yarn-site.xml root@hadoop03:$PWD
yarn-site.xml 

[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# stop-yarn.sh 
[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# start-yarn.sh 

2.6 演示

2.6.1 开启 RM 重启机制现象

如果 RM 出现故障重启之后,如果是保留工作的重启,作业继续执行。 

三、YARN HA 集群 

3.1 背景 

        ResourceManager 负责资源管理和应用的调度,是 YARN 的核心组件,集群的主角色。在 Hadoop 2.4 之前,ResourceManager 是 YARN 群集中的 SPOFSingle Point of Failure,单点故障)。为了解决 RM 的单点故障问题,YARN 设计了一套 Active/Standby 模式的 ResourceManager HA 架构。

        在运行期间有多个 ResourceManager 同时存在来增加冗余进而消除这个单点故障,并且只能有一个 ResourceManager 处于 Active 状态,其他的则处于 Standby 状态,当 Active 节点无法正常工作,其余 Standby 状态的几点则会通过竞争选举产生新的 Active 节点。

​3.2 架构 

        Hadoop 官方推荐方案:基于 Zookeeper 集群实现 YARN HA 实现 HA 集群的关键是:主备之间状态数据同步主备之间顺利切换(故障转移机制)针对数据同步问题,可以通过 zk 来存储共享集群的状态数据。因为 zk 本质也是一个小文件存储系统。针对主备顺利切换,可以手动,也可以基于 zk 自动实现。

3.3 故障转移机制 

  • 第一种:手动故障转移

管理员使用命令手动进行状态切换。

  • 第二自动故障转移

RM 可以选择嵌入基于 Zookeeper 的 ActiveStandbyElector 实现自动故障转移。

        YARN 的自动故障转移不需要像 HDFS 那样运行单独的 ZKFC 守护程序,因为 ActiveStandbyElector 是一个嵌入在 RM 中充当故障检测器和 Leader 选举的线程,而不是单独的 ZKFC 守护进程。

3.4 故障转移原理(基于 zk 自动切换) 

  • 创建锁节点在 ZooKeeper 上会创建一个叫做 ActiveStandbyElectorLock 的锁节点,所有的 RM 在启动的时候,都会去竞争写这个临时的 Lock 节点,而 ZooKeeper 能保证只有一个 RM 创建成功。创建成功的 RM 就切换为 Active 状态,没有成功的 RM 则切换为 Standby 状态。
  • 注册Watcher监听Standby 状态的 RM 向 ActiveStandbyElectorLock 节点注册一个节点变更的 Watcher 监听,利用临时节点的特性(会话结束节点自动消失)能够快速感知到 Active 状态的 RM 的运行情况。
  • 准备切换当 Active 状态的 RM 出现故障(如宕机或网络中断),其在 ZooKeeper 上创建的 Lock 节点随之被删除,这时其它各个 Standby 状态的 RM 都会受到 ZooKeeper 服务端的 Watcher 事件通知,然后开始竞争写 Lock 子节点,创建成功的变为 Active 状态,其他的则是 Standby 状态
  • Fencing(隔离)分布式环境中,机器经常出现假死的情况(常见的是 GC 耗时过长、网络中断或 CPU 负载过高)而导致无法正常对外进行及时响应。如果有一个处于 Active 状态的 RM 出现假死,其他的 RM 刚选举出来新的 Active 状态的 RM,这时假死的 RM 又恢复正常,还认为自己是 Active 状态,这就是分布式系统的脑裂现象,即存在多个处于 Active 状态的 RM,可以使用隔离机制来解决此类问题。

        YARN 的 Fencing 机制是借助 ZooKeeper 数据节点的 ACL 权限控制来实现不同 RM 之间的隔离。创建的根 ZNode 必须携带 ZooKeeper 的 ACL 信息,目的是为了独占该节点,以防止其他 RM 对该 ZNode 进行更新。借助这个机制假死之后的 RM 会试图去更新 ZooKeeper 的相关信息,但发现没有权限去更新节点数据,就把自己切换为 Standby 状态。

3.5 搭建步骤 

基于 HDFS HA 高可用集群上进行部署:HDFS HA 高可用集群搭建详细图文教程_Stars.Sky的博客-CSDN博客 

3.5.1 修改 yarn-site.xml

[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# vim yarn-site.xml 
<configuration>
<!-- 启用RM HA -->
<property>
  <name>yarn.resourcemanager.ha.enabled</name>
  <value>true</value>
</property>
<!-- RM HA集群标识ID -->
<property>
  <name>yarn.resourcemanager.cluster-id</name>
  <value>yarn_cluster</value>
</property>
<!-- RM HA集群中各RM的逻辑标识 -->
<property>
  <name>yarn.resourcemanager.ha.rm-ids</name>
  <value>rm1,rm2</value>
</property>
<!-- rm1运行主机 -->
<property>
  <name>yarn.resourcemanager.hostname.rm1</name>
  <value>hadoop01</value>
</property>
<!-- rm2运行主机 -->
<property>
  <name>yarn.resourcemanager.hostname.rm2</name>
  <value>hadoop02</value>
</property>
<!-- rm1 WebUI地址 -->
<property>
  <name>yarn.resourcemanager.webapp.address.rm1</name>
  <value>hadoop01:8088</value>
</property>
<!-- rm2 WebUI地址 -->
<property>
  <name>yarn.resourcemanager.webapp.address.rm2</name>
  <value>hadoop02:8088</value>
</property>
<!-- 开启自动故障转移 -->
<property>
  <name>yarn.resourcemanager.ha.automatic-failover.enabled</name>
  <value>true</value>
</property>
<!-- NodeManager上运行的附属服务。需配置成mapreduce_shuffle,才可运行MR程序。-->
<property>
  <name>yarn.nodemanager.aux-services</name>
  <value>mapreduce_shuffle</value>
</property>
<!-- 每个容器请求的最小内存资源(以MB为单位)。-->
<property>
  <name>yarn.scheduler.minimum-allocation-mb</name>
  <value>512</value>
</property>
<!-- 每个容器请求的最大内存资源(以MB为单位)。-->
<property>
  <name>yarn.scheduler.maximum-allocation-mb</name>
  <value>2048</value>
</property>
<!-- 容器虚拟内存与物理内存之间的比率。-->
<property>
  <name>yarn.nodemanager.vmem-pmem-ratio</name>
  <value>4</value>
</property>
<!-- 开启 yarn 日志聚集功能,收集每个容器的日志集中存储在一个地方 -->
<property>
  <name>yarn.log-aggregation-enable</name>
  <value>true</value>
</property>
<!-- 日志保留时间设置为一天 -->
<property>
  <name>yarn.log-aggregation.retain-seconds</name>
  <value>86400</value>
</property>
<property>
  <name>yarn.log.server.url</name>
  <value>http://hadoop01:19888/jobhistory/logs</value>
</property>
<!-- zk 集群 -->
<property>    
  <name>hadoop.zk.address</name>    
  <value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
<!-- 开启rm状态恢复重启机制 -->
<property>    
  <name>yarn.resourcemanager.recovery.enabled</name>    
  <value>true</value>
</property>
<!-- 使用zk集群存储RM状态数据 -->
<property>
  <name>yarn.resourcemanager.store.class</name>
  <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
</configuration>

3.5.2 集群同步 yarn-site.xml 配置文件 

[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# scp -r yarn-site.xml root@hadoop02:$PWD
yarn-site.xml                                                                                                         100% 3292   716.1KB/s   00:00    
[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# scp -r yarn-site.xml root@hadoop03:$PWD
yarn-site.xml                                                                                                         100% 3292   867.1KB/s   00:00    

3.5.3 启动 

在 hadoop01 上,启动 yarn 集群,可以发现启动了两个 RM 进程:

3.5.4 状态查看 

查看 HA YARN 集群状态 

[root@hadoop01 /bigdata/hadoop/server/hadoop-3.2.4/etc/hadoop]# yarn rmadmin -getAllServiceState
hadoop01:8033                                      standby   
hadoop02:8033                                      active

3.5.5 Web UI 查看

分别登陆两个 RM 所在机器的 Web UI 页面:

        在输入 hadoop01:8088,回车之后会自动跳转到 hadoop02:8088,因为 hadoop02 是 Active 状态,只有 Active 对外提供服务。

3.5.6 自动故障切换 

        强制杀死 hadoop02 节点的 RM,基于 ZooKeeper 的 ActiveStandbyElector 自动故障转移策略将 hadoop01 节点的 RM 选举为 Active 状态,表示故障转移配置正确。 

[root@hadoop02 ~]# yarn rmadmin -getAllServiceState
hadoop01:8033                                      standby   
hadoop02:8033                                      active    
[root@hadoop02 ~]# jps
3120 QuorumPeerMain
3267 NameNode
3348 DataNode
8532 Jps
8005 NodeManager
3451 JournalNode
3548 DFSZKFailoverController
7932 ResourceManager
[root@hadoop02 ~]# kill -9 7932
[root@hadoop02 ~]# yarn rmadmin -getAllServiceState
hadoop01:8033                                      active    
2023-09-05 15:38:30,727 INFO ipc.Client: Retrying connect to server: hadoop02/192.168.170.137:8033. Already tried 0 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=1, sleepTime=1000 MILLISECONDS)
hadoop02:8033                                      Failed to connect: Call From hadoop02/192.168.170.137 to hadoop02:8033 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused

# 重新启动 hadoop02 的 RM
[root@hadoop02 ~]# yarn --daemon start resourcemanager
[root@hadoop02 ~]# yarn rmadmin -getAllServiceState
hadoop01:8033                                      active    
hadoop02:8033                                      standby   

上一篇文章:HDFS HA 高可用集群搭建详细图文教程_Stars.Sky的博客-CSDN博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Hadoop YARN 中,HA 集群是指将多个 YARN ResourceManager 节点组成一个高可用的集群,以提高系统的可靠性和稳定性。在 HA 集群中,多个 ResourceManager 节点可以相互备份,以保证在某个节点故障时,系统仍能正常运行。 在配置 YARN HA 集群时,可以使用环境变量来设置一些参数,以便更好地控制 HA 集群的行为。下面介绍如何使用环境变量配置 YARN HA 集群。 1. 配置 yarn-site.xml 文件 首先,在 yarn-site.xml 文件中配置 HA 相关的参数。以下是一个示例配置: ``` <property> <name>yarn.resourcemanager.ha.enabled</name> <value>true</value> </property> <property> <name>yarn.resourcemanager.cluster-id</name> <value>mycluster</value> </property> <property> <name>yarn.resourcemanager.ha.rm-ids</name> <value>rm1,rm2</value> </property> <property> <name>yarn.resourcemanager.hostname.rm1</name> <value>rm1-hostname</value> </property> <property> <name>yarn.resourcemanager.hostname.rm2</name> <value>rm2-hostname</value> </property> ``` 其中: - yarn.resourcemanager.ha.enabled 表示开启 HA 功能; - yarn.resourcemanager.cluster-id 表示 HA 集群的唯一标识符; - yarn.resourcemanager.ha.rm-ids 表示 HA 集群中每个 ResourceManager 的标识符; - yarn.resourcemanager.hostname.rm1 和 yarn.resourcemanager.hostname.rm2 分别表示每个 ResourceManager 的主机名。 2. 配置环境变量 接下来,需要配置环境变量来指定 HA 集群的一些参数。以下是一个示例配置: ``` export HADOOP_YARN_HOME=/usr/local/hadoop-2.7.3 export YARN_CONF_DIR=$HADOOP_YARN_HOME/etc/hadoop export YARN_RESOURCEMANAGER_HA_RM_IDS=rm1,rm2 export YARN_RESOURCEMANAGER_HA_RM-1_HOSTNAME=rm1-hostname export YARN_RESOURCEMANAGER_HA_RM-2_HOSTNAME=rm2-hostname export YARN_RESOURCEMANAGER_HA_CLUSTER_ID=mycluster ``` 其中: - HADOOP_YARN_HOME 表示 YARN安装路径; - YARN_CONF_DIR 表示 YARN配置文件路径; - YARN_RESOURCEMANAGER_HA_RM_IDS 表示 HA 集群中每个 ResourceManager 的标识符; - YARN_RESOURCEMANAGER_HA_RM-1_HOSTNAME 和 YARN_RESOURCEMANAGER_HA_RM-2_HOSTNAME 分别表示每个 ResourceManager 的主机名; - YARN_RESOURCEMANAGER_HA_CLUSTER_ID 表示 HA 集群的唯一标识符。 3. 启动 YARN 最后,启动 YARN,并检查 HA 集群是否正常工作。可以使用以下命令启动 YARN: ``` $YARN_HOME/sbin/yarn-daemon.sh start resourcemanager ``` 注意,这里的 $YARN_HOME 是指 YARN安装路径。启动成功后,可以通过 Web 界面或命令行工具来检查 HA 集群的状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Stars.Sky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值