hadoop相关

概述

Hadoop 2.0即第二代Hadoop系统,其框架最核心的设计是HDFS、MapReduce和YARN。其中,HDFS为海量数据提供存储,MapReduce用于分布式计算,YARN用于进行资源管理。

1.Yarn资源调度工作原理和调度策略

前言
1.mapreduce流程和原理
流程:(已经淘汰)hadoop 1.x,新的 Hadoop MapReduce 框架命名为 MapReduceV2 或者叫 Yarn
在MapReduce中,用于执行MapReduce任务的机器有两个角色:JobTracker和TaskTracker。其中JobTracker是用于调度工作的。TaskTracker是用于执行工作的。
一个Hadoop集群中只有一台JobTracker。MapReduce架构图如下:
客户端向JobTracker提交一个作业,JobTracker把这个作业拆分成很多份,然后分配给TaskTracker去执行,TaskTracker会隔一段时间向JobTracker发送心跳信息(Heartbeat),
如果JobTracker在一段时间内没有收到TaskTracker的心跳信息,JobTracker会认为TaskTracker挂掉了,会把TaskTracker的作业任务分配给其他TaskTracker。

原理:
map端分而治之,reduce合并操作
下面介绍一下YARN的机制及与MapReduce相比的优势,
老的MapReduce主要包括Job Tracker和Task Tracker,YARN中主要是三个组件:Resource Manager、Node Manager和Application Master。Resource Manager负责全局资源分配,Application Master每个节点一个,负责当前节点的调度和协调。Node Manager是每台机器的代理,监控应用程序的资源使用情况,并汇报给Resource Manager。因此与老的MapReduce相比,YARN把资源管理与任务调度的工作分离开来,减少了MapReduce中Job Tracker的压力。

mr原理
概述:分而治之
流程:map、shuffle、reduce
map:从hdfs读取文件,生成kv,调用map生成新kv,根据reduce数量,对k哈希散列,得到不同分区,然后对分区内kv进行排序分组
shuffle:将同一分区的kv copy至同一reduce节点
resuce:按k排序,同一k的数据调用reduce计算,结果输出新的kv,最后将kv结果写入hdfs

从以上介绍可以看出,相比于MapReduce,YARN主要优势如下,
1 YARN大大减少了Job Tracker的资源消耗,并且让监测每个Job子任务状态的程序分布式化了。
2 YARN中Application Master是一个可变更部分,用户可以对不同编程模型编写自己的AppMst,让更多类型的编程模型能跑在Hadoop集群中。
3 老的框架中,Job Tracker一个很大的负担就是监控Job下任务的运行状况,现在由Application Master去做,而Resource Manager是监测Application Master的运行状况,如果出问题,会将其在其他机器上重启。

1.1 Yarn组成

由于Yarn良好的兼容性和扩展性,目前可以支持大部分数据引擎,所以了解Yarn的资源调度原理很有必要,Yarn主要由四个重要角色组成:

  • ResourceManager:
    顾名思义资源管理器,主要负责资源管理和调度,ResourceManager主要由两个组件构成:ApplicationManager,主要负责两类工作:1.管理监控各个系统的应用,包括启动Applicaiton Master,监控Applicaiton Master运行状态(为了容错)2.跟踪分配给Application Master的进度和状态。Scheduler,主要负责分配Container给Applicaiton Master,分配算法有多种(如公平调度等等)可以根据需求不同选择适合的调度策略。
  • NodeManager:
    节点管理器,主要负责维护本节点的资源情况和任务管理。首先NodeManager需要定期向ResourceManager汇报本节点资源使用情况,以便ResourceManager,根据资源使用情况,来分配资源给Application Master,其次,需要管理Applicaiton Master提交来的task,比如接收Applicaiton Master 启动或停止task的请求(启动和停止有NodeManager的组件ContainersLanuncher完成)。
  • ApplicaitonMaster:
    用户提交的每个program都会对应一个ApplicationMaster,主要负责监控应用,任务容错(重启失败的task)等。它同时会和ResourceManager和NodeManager有交互,向ResourceManager申请资源,请求NodeManager启动或提示task
  • Container:
    容器是资源调度的单位,它是内存、cpu、磁盘、和IO的集合。Application Master会给task分配Container,task只能只用分配给它的Container的资源。分配流程为Resource Manager ->Application Master -> task

1.2 Yarn调度原理

Yarn调度?主要分为8个步骤如上图所示:

  • 1.有YarnClient提交program信息打拼ResourceManager,包括(应用代码和应用需要的一切参数和环境信息)
  • 2.ResourceManager收到请求之后,调用ApplicationMasterManager向NodeManager发送请求,申请一个资源(Container),并且要求Container启动ApplicationMaster.
  • 3.ApplicationMaster启动之后,首先注册自己到ResourceManager,然后为自己的Task申请Container,这个过程是轮训的,循环申请资源,ResourceManager收到请求之后,会要求NodeManager分配资源
  • 4.资源分配完毕之后,Application Master发送请求到NodeManager,启动任务。
  • 5.NodeManager设置Container的运行时环境(jar包,环境变量,任务启动脚本),NodeManager会通过脚本启动任务
  • 6.启动的过程是由NodeManager的ContainerLauncher负责的,ContainerLauncher完成启动任务的工作
  • 7.这一步是在作业执行过程中持续发生的,我用虚线代表,主要包括两类交互,第一,task和Application Master的交互,task会向AM汇报任务状态和进度信息,比如任务启动,停止,状态更新。Applicaiton Master利用这些信息监控task整个执行过程。第二,是NodeManager和ResourceManager的交互,这个过程和任务没有关系,主要是两者之间保持的心跳信息(状态的变化等等)
  • 8.Application Master在检测到作业运行完毕之后,Application Master想Resource Manager 删除自己,并且停止自己执行。

简要概述:
首先,client向ResourceManager发出任务请求。ResourceManager指定一个NodeManager启动其ApplicationMaster。ApplicationMaster将计算任务反馈给ResourceManager。ApplicationMaster将任务分割分发到不同的NodeManager。NodeManager启动Task执行work。

1.3 Yarn的调度策略

Yarn中有三种调度器可以选择:FIFO Scheduler(先进先出) ,Capacity Scheduler(容器调度),Fair Scheduler(公平调度)。

  • FIFO
    Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
    小任务会被大任务阻塞
  • Capacity
    调度器允许多个组织共享整个集群,每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列,然后再为每个队列分配一定的集群资源,这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外,队列内部又可以垂直划分,这样一个组织内部的多个成员就可以共享这个队列资源了,在一个队列内部,资源的调度是采用的是先进先出(FIFO)策略。
    ?而对于Capacity调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。
  • Fair
    在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。如下图所示,当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
    需要注意的是,在下图Fair调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成。

【Hive】MR 工作流程(数据流转) https://www.jianshu.com/p/2b3eb0cf2fe0

2.hdfs与hive

2.1 hdfs的体系结构

hdfs有namenode、secondraynamenode、datanode组成。
namenode负责管理datanode和记录元数据
secondraynamenode负责合并日志
datanode负责存储数据

2.2 hive架构

从外部使用来看:
HDFS:用来存储hive仓库的数据文件
MetaStore:保存管理hive维护的元数据
Hive:用来通过HQL的执行,转化为MapReduce程序的执行,从而对HDFS集群中的数据文件进行统计

从内部结构来看:
有解释器、编译器、优化器
yarn:用来完成hive的HQL转化的MR程序的执行

hive是基于Hadoop的一个数据仓库工具,用来进行数据提取、转化、加载,这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive数据仓库工具能将结构化的数据文件映射为一张数据库表,并提供SQL查询功能,能将SQL语句转变成MapReduce任务来执行。------ 百度百科
————————————————
版权声明:本文为CSDN博主「寒枫__梦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41408329/article/details/106116543

2.2.1 hive存储格式

Hive 支持的文件存储格式
1.行式存储:
textfile、sequencefile
2.(行分块)列式存储:
rcfile、orcfile、parquet
列式存储的优势:
1、更高的压缩比,由于相同类型的数据更容易使用高效的编码和压缩方式。
2、更小的I/O操作,可以减少一大部分不必要的数据扫描,尤其是表结构比较庞大的时候更加明显,由此也能够带来更好的查询性能。
–小记:hive不同的存储方式区别很大。生产环境采用的是textfile(无压缩,行存)和orc存储(snappy的压缩,列存)

2.3 hive内部表和外部表区别

(1)hive内部表和外部表概念
未被external修饰的是内部表(managed table)
被external修饰的为外部表(external table)
(2)hive内部表和外部表区别
区别:
内部表数据由Hive自身管理,外部表数据由HDFS管理;
内部表数据存储的位置是hive.metastore.warehouse.dir(默认:/user/hive/warehouse),外部表数据的存储位置由自己制定(如果没有LOCATION,Hive将在HDFS上的/user/hive/warehouse文件夹下以外部表的表名创建一个文件夹,并将属于这个表的数据存放在这里);
删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;(这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。
对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE table_name;)
(3)hive内部表和外部表使用场景
什么时候使用内部表,什么时候使用外部表?
hive内部表、外部表使用场景使用时机:
①外部表:比如某个公司的原始日志数据存放在一个目录中,多个部门对这些原始数据进行分析,那么创建外部表是明智选择,这样原始数据不会被删除;
②内部表:在做统计分析时候用到的中间表,结果表可以使用内部表,因为这些数据不需要共享,使用内部表更为合适。并且很多时候结果分区表我们只需要保留最近3天的数据,用外部表的时候删除分区时无法删除数据

a:删表时内部表清数据;
删表时外部表保留数据只删元数据,外部表比较安全,重要的源数据和不易恢复的数据使用外部表
b:不止hive使用,多种共用时使用外部表

3.常用语句/命令

3.1 hive sql

create external table if not exists test.report_test(
	id int,
	name char(10)
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';  --hive建表

create table dept_part2
(deptno int,dname string,loc string)
partitioned by (month string,day string)
row format delimited fields terminated by '\t';  --创建二级分区表

create table test1 like test;  --复制表结构

alter table test drop if exists partition(dt=20201213);  --删除分区

alter table test add partition(dt=20210321) location '/usr/hive/test/20210321';  --逐个修复分区
msck repair table test.test;   --批量修复分区

alter table table_name add columns (now_time string comment '当前时间');  --向Hive表中添加某个字段

alter table table_name change c_time c_time string after address ;  --正确,移动到指定位置,address字段的后面

alter table DWD_ORC_ENTRY_XF change id taskid varchar(300);  --修改字段、字段类型

ALTER TABLE test REPLACE COLUMNS (
a STRING,
b BIGINT,
c STRING,
d STRING,
e BIGINT
);   --如果需要删除 column f 列,可以使用以下语句:

load data inpath 'hdfspath' [overwrite] into table tablename  --hdfs数据加载  

load data local inpath 'localpath' [overwrite] into table tablename   --本地数据加载
注:这个操作是移动数据,而不是复制数据。

hive传递参数
hive -hivevar v_date='20210530' -hivevar v_tb='test' -f test.sql
use tradb;
select *from ${hivevar:v_tb} where dt='${hivevar:v_date}' limit 10;    

Hive中内部表和外部表之间的相互转换
外部表转换成内部表
alter table 外部表 set tblproperties   ('EXTERNAL'='False');

内部表转换成外部表
alter table 内部表 set tblproperties     ('EXTERNAL'='True');

3.2 hdfs

hdfs dfs -ls /warehouse/tablespace/external/hive/ods2_winddb.db/z_bond_mkdata   --hdfs查看
test.db/test/   --默认创建表存储路径

3.3 UDF

(1)写对应的java代码自定义函数的逻辑
(2)将代码打成jar包上传到hive
(3)在hive创建临时函数与对应的class类相关联
(4)在hive中调用临时函数。

3.4 hive函数

时间函数、字符串函数、条件表达式、聚合函数、窗口函数(窗口聚合函数、窗口排序函数)、行列转换

hive行列转换
#行转列 (根据主键,对某列进行合并)
使用函数:concat_ws(‘,’,collect_set(column))
说明:collect_list 不去重,collect_set 去重。 column 的数据类型要求是 string
select col1,col2,concat_ws(‘,’,collect_set(col3)) as bian from tmp_jiangzl_test group by col1,col2;
#列转行 (对某列拆分,形成新列)
使用函数:lateral view explode(split(column, ‘,’)) num
select col1, col2, col3_new from col_to_row_test a lateral view explode(split(col3,‘,’)) b AS col3_new;

4.hive数据倾斜解决方案

hive调优3个层面

  • a.hive建表设计层面
    存储格式、压缩格式、分区、分桶
  • b.sql语法层面
    列裁剪、分区裁剪
    谓词下推
    join优化:空值过滤、空值转换、避免不同类型字段关联
    group by 代替 distinct
    sort by 代替 order by
  • c.参数层面
    map端小文件合并:merge.mapfiles
    fetch本地抓取模式:select *,where 分区,limit
    jvm重用:个数设置为5
    map函数:将数据集解析 reduce函数:完成统计
    数据倾斜是进行大数据计算时常见的问题。主要分为map端倾斜和reduce端倾斜,map端倾斜主要是因为输入文件大小不均匀导致,reduce端主要是partition不均匀导致。
    在hive中遇到数据倾斜的解决办法:倾斜原因:map端缓慢,输入数据文件多,大小不均匀

4.1 map端

当出现小文件过多,需要合并小文件。可以通过set hive.merge.mapfiles=true来解决。
set hive.map.aggr=true; //map端部分聚合,相当于Combiner,可以减小压力(默认开启)
set hive.groupby.skewindata=true(默认关闭);//有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

4.2 reduce端

表现:是任务进度长时间维持在99%(或100%)
原因:在map和reduce两个阶段中,最容易出现数据倾斜的就是reduce阶段,因为map到reduce会经过shuffle阶段,在shuffle中默认会按照key进行hash,如果相同的key过多,那么hash的结果就是大量相同的key进入到同一个reduce中,导致数据倾斜。

4.2.1 hive表的优化

和join相关的:能过滤就过滤,过滤不掉,对于空值,就进行转换,避免数据倾斜。 --空key过滤、空key转换
①多个表关联:尽量多拆成一些中间表,避免SQL关联太多了,不知道哪一块慢了。
②大表join大表:
空key过滤
解释: 优化前是先join后再where进行过滤的,这样并没有减轻reduce的压力,优化后是在map端执行where,过滤器,然后再join的,这样大大降低了计算量。
举例: 有两张表,一张表有空 id,一张表没有空id,关联规则使用id来进行关联
如果空key过滤不掉,大量的null id的数据会发送到同一个reduceTask里面去,造成数据倾斜。
#不过滤空key
SELECT a.* FROM nullidtable a JOIN ori b ON a.id = b.id;
#过滤空key
SELECT a.* FROM (SELECT * FROM nullidtable WHERE id IS NOT NULL ) a JOIN ori b ON a.id = b.id;
#空key转换
有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的reducer上。例如:
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN concat(‘hive’, rand()) ELSE a.id END = b.id;

4.2.2 小心使用Count(Distinct)

在开发过程中,要小心使用count distinct。举个栗子:
select count(distinct user) from table
由于必须要去重了,所以hive会把所有的map阶段输出都放在一个reduce上,造成性能问题,所以通过group by再count进行优化。
由于count(distinct)操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,数据量大的情况下,就会导致整个Job很难完成。在这种情况下,可以使用先group by再count的方式替换count(distinct)。例如:
#使用count(distinct)
SELECT count(DISTINCT id) FROM bigtable;
#建议使用count() … group by 替换count(distinct)
SELECT count(id) FROM (SELECT id FROM bigtable GROUP BY id) a;

4.2.3 不同数据类型关联产生数据倾斜

场景:一张表s8的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。s8的日志中有字符串商品id,也有数字的商品id,类型是string的,但商品中的数字id是bigint的。猜测问题的原因是把s8的商品id转成数字id做hash来分配reduce,所以字符串id的s8日志,都到一个reduce上了,解决的方法验证了这个猜测。
解决方法:把数字类型转换成字符串类型
Select * from s8_log a
Left outer join r_auction_auctions b
On a.auction_id = cast(b.auction_id as string);

4.2.4 分区表

表相当于一个大的目录,分区就是在这个大的目录下面创建一个个的小目录。分区字段不能是表中已经存在的字段,分区的字段不是真实存在的,但查询的时候带上分区字段也可提升查询效率。

4.2.5 分桶表

分桶规则:Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中
在hdfs上,分桶表目录下存放的是文件,有几个桶,就有几个文件
#创建分桶表
create table stu_buck(id int,name string)
clustered by(id) into 4 buckets
row format delimited fields terminated by ‘\t’;
#抽样查询
抽样查询与分桶表联系不大,但是用到了bucket这个关键字,所以放到这里一起讲
select * from student tablesample(bucket 1 out of 4 on id);
–上述命令表示把student表按id分成4份,取出其中的第一份
#分区表和分桶表的区别
在hdfs上的目录不同:
分区:表目录下再建立分级目录,数据文件存放在各个分级目录中
分桶:数据文件经过切分之后放到表目录下(即表目录下放的是多个文件),分了几个桶,数据文件就被切成几份

创建语句不同
分区: partitioned by(分区字段名1 data_type,分区字段名2 data_type,…)
分桶:clustered by(分桶字段名) into 分桶数 buckets
分区字段不能使用原表中的字段,分桶字段必须使用原表中的字段

导入数据语句不同
分区:load data时要指定partition
分桶:与一般表load data的方式一致

是否能修改桶/区
分桶只能在建表时确定分桶的字段以及桶数,后续不能再调整;分区只用在建表时确定分区字段,只后可以随意增加、删除区。

数据分桶的作用:
好处:
1、方便抽样
2、提高join查询效率

6.数仓

6.1 数仓和数据库的区别

数据库是面向事务的设计,数据仓库是面向主题设计的。
数据库一般存储业务数据,数据仓库存储的一般是历史数据
逻辑上理解,数据库和数据仓库没有区别,都是通过数据库软件实现的存放数据的地方,只不过从数据量来说,数据仓库要比数据库更庞大得多。数据仓库主要用于数据挖掘和数据分析,辅助领导做决策。

#操作型处理,叫联机事务处理OLTP(On-Line Transaction Processing,),也可以称面向交易的处理系统,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题。传统的数据库系统作为数据管理的主要手段,主要用于操作型处理。
#分析型处理,叫联机分析处理OLAP(On-Line Analytical Processing)一般针对某些主题的历史数据进行分析,支持管理决策。

6.2 数据仓库架构分层

– https://blog.csdn.net/weixin_42656794/article/details/91818113
数据仓库标准上可以分为四层:ODS(原始数据层)、DWD(数据明细层)、DWS(数据服务层)、APP(应用层)。
数据明细层:DWD(Data WareHouse Detail)
该层一般保持和ODS层一样的数据粒度,并且提供给一定的数据质量保证。同时为了提高数据明细层的易用性,该层会采用一些维度退化手法,将维度退化到事实表中,减少事实表和维度表的关联。另外,在该层也会做一部分的数据聚合,将相同主题的数据汇集到一张表中,提高数据的可用性

6.3 数据梳理

四个主题两个层级
一级 二级
客户 对公客户
个人
账户 TA账户
交易账户
资产 份额
交易 交易流水

数仓建设
按主题、层级进行分工,比如理财主题可划分为四大主题 :客户、账户、交易、资产
其实就是围绕着业务模型 --维度建模—星型模型–,事实表就是各个维度表的主键
范式建模和其他没用到

6.4 TD迁移高斯

高斯VARCHAR类型扩位2倍是按照主仓的处理原则进行处理,主要是因为TD会存在自动截断的情况,高斯字段超长会报错。
脚本中临时表和目标表数据inert后,必须进行analyze,同一张临时表如果有多段inert,在最后一段进行添加。
analyze只能是临时表或实体表,不能对视图analyze。
高斯目前不支持merge视图,merge目前只能对临时表或者实体表进行更新。

7.生产环境遇到的问题

7.1 批量修复分区报错

解决方法:hdfs存储路径 /usr/hive/test/20210321 
将以上格式修改为/usr/hive/test/dt=20210321
如果目录格式不对,则会报错:
hive> MSCK REPAIR TABLE xxxxxx_uid_online;  
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask
注意:	为了让MSCK命令工作,分区的目录名必须是【/partition_name=partition_value/】结构的(且表级目录中不得存在非此种格式的目录名),否则将无法添加分区。这时候就必须使用add partition命令了。

7.2 服务器网络

sqoop需要和各节点调通网络,弃用换为datax

7.3 其他

简要描述如何安装配置apache的一个开源hadoop,只描述即可,无需列出具体步骤,列出具体步骤更好。
答:第一题:
1 使用root账户登录
2 修改IP
3 修改host主机名
4 配置SSH免密码登录
5 关闭防火墙
6 安装JDK
7 下载解压hadoop安装包
8 配置yum源
9 ambari安装

7 配置hadoop的核心文件 hadoop-env.sh,core-site.xml , mapred-site.xml , hdfs-site.xml
8 配置hadoop环境变量
9 格式化 hadoop namenode-format
10 启动节点start-all.sh

32.三个datanode中当有一个datanode出现错误时会怎样?

7.4 TD\GS数仓分层

TIER_1_DEV:
STG 数据缓冲层
TIER_2_DEV:
GDM 共性加工层 公共数据集市:对公客户、个人客户、第三方支付、机构参数等
PDM 基础模型层 主数据层:活动报名客户表、活动达标客户等
TIER_3_DEV:
APP 数据应用层 加工好的达标名单文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值