redis的数据结构与命令及其持久化方式

############################################ 声明 ############################################
$key 键值对的key值
$target_key 目标key
$value 键值对的value值
$index 索引
$time 时间()
$num 数值
$start 开始索引
$end 结束索引
$offset 偏移量
$count 个数
$pivot 基准值
$score 分数,作zset排序用
$x 经度
$y 纬度
$name 名称
$unit 距离单位, m-米 km-千米

############################################ 通用 ############################################

# 查看所有key
keys *
# 查看配置
config get *
# 切换数据库(默认16个数据库,使用的是第0个)
select $index
# 清空当前数据库
flushdb
# 清空所有数据库
flushall
# 移动key 到其他数据库
move $key $index
# 设置过期时间
expire $key $time
# 查看key过期时间
ttl $key
# 查看key是否存在
exists $key
# 查看key类型
type $key
# 更改key的名字,如果源key不存在则会报错 (error) ERR no such key,如果目标key已存在则会被覆盖
rename $key $target_key


############################################ String ############################################

# 设置键值对
set $key $value
# 获取值
get $key
# 追加值,如果key存在则追加,不存在则相当于set一个新key
append $key $value
# 查看字符长度
strlen $key
# 指定key的值加1
incr $key 
# 指定key的值减1
decr $key
# 指定key的值加指定数值
incrby $key $num 
# 指定key的值减指定数值
decrby $key $num 
# 截取字符串的指定范围区间 -1可代表直达最末端
getrange $key $start $end
# 将字符串的某个偏移量开始 替换成指定的value,value的长度会替换对应数量的值
setrange $key $offset $value
# 设置指定过期时间的键值对 setex (set with expire)
setex $key $time $value
# *判断一个key是否存在,如果存在则无法set,不存在则可以set (set if not exists),在分布式锁中常使用
setnx $key $value
# 批量设置键值对, (高阶用法存储对象 key为user:{id}:{field} : mset user:1:name porty user:1:age 18)
mset $key1 $value1 $key2 $value2 $key3 $value3...
# 批量获取key
mget $key1 $key2 $key3...
# 批量判断设置,原子性操作,只要有其中一个key存在则所有设置都失败
msetnx $key1 $value1 $key2 $value2
# 组合命令 getset, 先获取值再设置值
getset $key $value


############################################ Lsit ############################################

# list集合的值可以重复、有序
# 所有的list命令以 l 开头的都是从左边进行操作,r开头则从右边进行操作,应用场景 可做栈 ,队列等来使用
# 设置集合,可以将一个或多个值从左/右方插入
lpush/rpush $key $value
# 从左/右方开始弹出值
lpop/rpop $key
# 获取指定区间的值
lrange $key $start $end
# 获取指定下标的值
lindex $key $index
# 查看list的长度
llen $key
# 移除集合中指定数量的某个值 $count为0或者$count比实际存在的还多时代表移除所有$value
lrem $key $count $value
# 截断集合中指定范围的数据
ltrim $key $start $end
# 移除源列表中的最右(最后)一个元素,并把它添加到目标列表的最左(最前),如果目标列表不存在则会创建目标列表
rpoplpush $key $target_key
# 更新列表中指定下标的值,如果 列表key不存在则会报错(error) ERR no such key 列表中对应下标不存在则会报错 (error) ERR index out of range
lset $key $index $value
# 对列表的指定基准值的前方或后方before/after插入值, 如果列表不存在/者空列表/基准值不存在 则插入失败,如果$key的类型不是列表将报错
linsert $key before/after $pivot $value


############################################ Set ############################################

# set集合的值不重复且无序
# 设置单个或多个值,多个值空格符隔开
sadd $key $value
# 获取集合中的所有数据
smembers $key 
# 判断集合中是否包含该值
sismember $key $value
# 获取集合的元素数量,不存在或者空则返回0
scard $key
# 移除集合中的单个值或多个值,多个值用空格符隔开
srem $key $value
# 随机挑选指定数量的元素,count, 为正数则至多只能挑选出元素的最大数量,如果为负数则可以重复返回到指定数量,默认count 为1个。
srandmember $key [$count]
# 随机弹出一个或指定数量的元素
spop $key [$count]
# 将源集合中的一个元素移动到目标集合中,如果目标集合不存在则会创建集合
smove $key $target_key $value
# 两个集合求差集/交集/并集
sdiff/sinter/sunion $key1 $key2
# 将两个集合的差集/交集/并集放入目标集合中
sdiffstore/sinterstore/sunionstore $target_key $key1 $key2

############################################ Hash ############################################

# 在set的基础上,增加了一个分值,用作排序使用
# 使用场景:排序,排行  取 Top 10等场景
# 给集合添加带分数的元素/多个元素
zadd $key $score $value
# 通过score从小到大排序获取指定区间的元素 -inf为负无穷 +inf为正无穷,withscores可选。
zrangebyscore $key -inf +inf [withscores]
# 从大到小排序
zrevrange $key $start $end
# 获取指定区间的元素也可以通过zrange
zrange $key $start $end
# 移除集合中的单个元素或多个,多个元素用空格符分隔
zrem $key $value
# 获取集合中的元素个数
zcard $key
# 获取集合中指定分数区间内有多少个元素,
zcount $key $score1 $score2
# 获取元素在集合中的分数
zscore $key $field


############################################ Hash ############################################

# Map集合,key value,这个value本质是个map集合
# hash命令以h开头,使用场景:适合于对象的存储,String更加适合字符串存储
# 设置hash的一个成员值
hset $key $field $value
# 批量设置hash的成员值
hmset $key $field1 $value1 $field2 $value2 ...
# 判断hash中该成员是否存在,不存在时创建才有效
hsetnx $key $field $value
# 获取hash的一个成员值
hget $key $field
# 获取hash的多个成员值
hmget $key $field1 $field2...
# 获取hash中所有的键值对
hgetall $key
# 查看hash下的所有成员field
hkeys $key
# 查看hash下所有成员的值
hvals $key
# 删除hash中指定的单个成员/多个成员,多个成员以空格符分割
hdel $key $field
# 查看hash有多少个成员
hlen $key
# 获取hash中指定成员的值长度
hstrlen $key $field
# 判断hash中某个成员是否存在,存在返回1,不存在返回0
hexists $key $field
# 给hash中的某个成员值增加指定数值,如果是要删减则将num置为负数即可
hincrby $key $field $num



############################################ 三种特殊数据类型 ############################################

############################################ geospatial ############################################

# geospatial地理空间,geo的底层实现原理其实就是zset,可以用各别zset的命令来操作geo,如zrem删除元素
# 添加地理位置,经度 纬度 名称,有效的经度从-180度到180度。有效的纬度从-85.05112878度到85.05112878度。
geoadd $key $x $y $name
# 查看同个key下两个城市之间的距离,默认单位为米(m),可设置 km 表示单位为千米。mi 表示单位为英里。ft 表示单位为英尺
geodist $key $name1 $name2  [$unit]
# 查询key下某城市的经纬度
geopos $key $name
# 返回城市标准的Geohash
geohash $key $name
# 找到某个经纬度的指定半径距离有什么城市,可选项withdist-距离, withcoord-经纬度,count $num-显示个数,asc-顺序 desc-逆序
georadius $key $x $y $num $unit [withdist]
# 以key里面的一个成员(城市)为中心,指定半径内的,可选项同上。如果指定城市不存在则报错(error) ERR could not decode requested zset member
georadiusbymember $key $name $num $unit 

############################################ hyperloglog ############################################

# hyperloglog 基数统计算法,从redis 2.8.9版本就更新了该数据结构,hyperloglog有0.8%的错误率,占用的内存空间是固定的12kb
# 使用场景:网页UV(用户访问量-去重)
# 添加key,可设置单个值或多个值
pfadd $key $value1 $value2...
# 获取key里面的元素-不重复
pfcount $key
# 合并两个key,将$key的值合并到$target对象key中,也可以合并多个$key到目标$target中
pfmerge $target $key 

############################################ bitmaps ############################################

# bitmaps位图,位存储 ,操作二进制位进行记录只有 0 1 两个状态
# 使用场景:统计活跃人数,统计是否登录,统计打卡!两个状态的都可以使用bitmaps解决
# 声明 此数据结构的$value值只有 0 和 1
# 设置值
setbit $key $offset $value
# 获取key中指定偏移量的value值
getbit $key $offset
# 获取key中指定范围内值为1的数量,默认为全部
bitcount $key [$start $end]





############################################ 事务 ############################################


# redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
# 一次性、顺序性、排他性!执行一系列的命令!
# ----队列 set set set 执行----
# redis事务没有隔离级别的概念!
# 所有命令在事务中(入队中)并没有被执行,只有到了执行命令的时候才会执行。Exec 
# redis单条命令保证原子性,但是redis事务不保证原子性
# redis事务:
#        开启事务(multi)->  命令入队(....)-> 执行事务(exec)


# 开启事务
multi
# 执行
exec
# 放弃事务
discard
# 监控(锁)key是否被修改,如果修改则事务执行失败,实现乐观锁 cas(check-and-set)
watch $key
# 取消监控(解锁)
unwatch
# 事务问题:
# 1.编译型异常:代码有问题,命令错误。当exec执行时,事务中的所有命令都不会执行
# 2.运行时异常:错误的命令不会执行,其他命令不受影响,正常执行


############################################ redis.conf ############################################

# 配置文件
# 配置文件 unit 单位对大小写不敏感! units are case insensitive so 1GB 1Gb 1gB are all the same.

# # # 网络 # # #
# 绑定ip,如果允许所有来源则设置为 0.0.0.0,如果多个来源使用空格符隔开
bind 127.0.0.1 
# 保护模式,默认开启
protected-mode yes
# 端口号,默认为6379
port 6379

# # # 通用 # # #
# daemonize默认为no,不是以守护线程的方式运行的,可修改为yes设置
daemonize yes
# 如果以后台的方式运行,就需要指定一个pid进程文件
pidfile /var/run/redis_6379.pid

# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice

# 日志的文件位置名
logfile ""

# 当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 0
# 设置数据库的数量,默认数据库为0,可以使用select $index命令在连接上指定数据库id
# $index是从0到‘databases’-1的数目
databases 16

# 是否总是显示logo
always-show-logo yes

# include可以包含其他配置文件,进行组合
include /path/to/local.conf

# # # 快照 # # #
# 持久化,在规定的时间内执行了多少次操作则会持久化到文件  .aof/.rdb
# redis是内存数据库,没有持久化那么数据断电即失
# 900秒内,至少有1个key进行了修改,我们就进行持久化操作
save 900 1
# 300秒内,至少有10个key进行了修改,我们就进行持久化操作
save 300 10
# 60秒内,至少有10000个key进行了修改,我们就进行持久化操作
save 60 10000
# 可以自定义

# 持久化如果出错了,是否还需要继续工作
stop-writes-on-bgsave-error yes

# 是否压缩rdb文件,需要消耗一些CPU资源
rdbcompression yes
# 保存rdb文件的时候,进行错误的校验
rdbchecksum yes
# rdb文件保存的目录
dir ./

# # # REPLICATION 主从复制# # #


# # # SECURITY 安全# # #
# 设置密码,默认没有密码
requirepass 密码
# 设置了密码后需要使用auth 密码进行验证才能进一步操作
auth 密码

# # # CLIENTS 客户端设置# # #
# 客户端最大连接数
maxclients 10000

# # # MEMORY MANAGEMENT 内存 # # #
# 最大内存
maxmemory <bytes>
# 内存到达上限的处理策略
#1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
#2、allkeys-lru : 删除lru算法的key   
#3、volatile-random:随机删除即将过期key  
#4、allkeys-random:随机删除   
#5、volatile-ttl : 删除即将过期的   
#6、noeviction : 永不过期,返回错误
maxmemory-policy noeviction


# # # APPEND ONLY MODE 配置aof # # #
# 默认不开启aof模式,默认使用rdb方式持久化
appendonly no
# 持久化文件的名字
appendfilename "appendonly.aof"

# 每次修改都会sync,消耗性能
# appendfsync always
# 每秒执行一次sync,可能会丢失这1s的数据
appendfsync everysec
# 不执行sync,不同步,这个时候操作系统自己同步数据,速度最快
# appendfsync no


############################################ Redis持久化 ############################################

######################## RDB (Redis Database) ########################
# RDB工作原理
主进程正常工作,fork子进程来IO,不会影响主进程的效率,会先制作一个临时的rdb文件,待持久化结束后会将该临时文件替换原有的rdb文件。
但有可能导致最后一次数据丢失

# 生成RDB文件
1.save命令满足后自动触发RDB规则
2.执行了flushall命令,也会触发RDB规则
3.关闭redis

# 如何恢复RDB文件
1.将RDB文件放置到redis的启动目录,redis启动的时候会自动检查dump.rdb 恢复其中的数据

# 优点
1.适合大规模的数据恢复!
2.对数据的完整性要求不高!

# 缺点
1.需要一定的时间间隔,如果redis意外宕机了,最后一次修改的数据就没有了
2.fork进程的时候会占用一定的内存空间


######################## AOF (Append Only File) ########################
# 将我们所有的操作命令都记录下来,类似history,恢复的时候就把这个文件全部再执行一遍
# aof默认是不开启的,需要手动配置redis.conf文件中的appendonly变量为yes
# 如果aof文件有错误,redis将启动失败,需要使用 redis-check-aof --fix xx.aof 修复这个文件。
# 注意:修复可能导致某些命令会被删除掉
# aof默认采取的记录策略是 1s 记录一次,如果宕机可能导致最后一秒的记录丢失
redis-check-aof --fix xx.aof 
# 优点
1.每一次修改都同步,文件的完整性更好
2.每秒同步一次,可能会丢失一秒的数据
3.不开启,从不同步
# 缺点
1.相对于数据文件来说,aof远远大于rdb,修复的速度比rdb慢
2.aof运行效率比rdb慢,所以redis的默认持久化配置是rdb


############################################ 订阅者与发布者 ############################################
######################## 订阅者,读取订阅 ########################
# 订阅渠道
subcribe channel 
######################## 发布者,发布订阅 ########################
# 对指定渠道发布信息
publish channel messages


############################################ 主从复制 ############################################

# 主从复制,读写分离。主库负责写,从库负责读,因为大部分时间都是在读取数据(80%)最低配 一主二从
# 主要作用:
1.数据冗余:实现数据的热备份
2.故障恢复:当主节点出现问题事,可由从节点提供服务,实现快速的故障恢复
3.负载均衡:读写分离
4.高可用(集群)基石
# 细节:
1.主机可以写,从机不能写只能读(除非配置replica-read-only no,)。主机中的所有信息和数据,都会自动同步到从机中保存
# 环境配置:只配置从库
# 查看主从信息
info replication
# 修改redis.conf
# 1.端口号
port
# 2.pid进程名字
pidfile
# 3.log日志名字
logfile 
# 4.rdb文件名
dbfilename

# 测试:搭建一主二从
# 为redis配置主库,使用命令配置只作用本次redis启动有效,永久有效需要使用配置文件配置 replicaof <masterip> <masterport>
slaveof host port
# 从节点可以使自己变回成为主节点
slaveof no one
# 使用info replication校验redis角色状态

# 复制原理
第一次建立主从,主库会做一次 全量复制 给从节点。往后都是 增量复制。如果从节点服务重启,那么主节点还是会做一次全量复制。

############################################ *sentinel哨兵模式-自动选举老大 ############################################
# failover->故障转移
# 后台监视主机是否故障,如果故障了根据投票数自动将从库转为主库。
# 哨兵模式是一种特殊模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,独立运行。
# 原理就是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

# 1.配置哨兵的配置文件sentinel.conf 命令-> sentinel monitor 自定名字 ip 端口 1(这个1是代表 哨兵发现主库宕机后会进行投票选举新主库)
sentinel monitor redis_name host port 1
# 2.启动哨兵 ,使用redis bin目录下的redis-sentinel工具启动哨兵
redis-sentinel sentinel.conf
# 如果主机宕机了,那么哨兵在一段时间后会"随机"选举一个从节点并投票给他,最终哪个从节点的票数最多将成为主机,其他节点将成为该新主机的从机
# 如果原来的主机再次恢复服务,那么他也将成为先主机的从机

# 优点
1.哨兵集群,基于主从复制模式,拥有所有的主从配置优点
2.主从可以切换,故障可以转移,系统的可用性更好
3.哨兵模式就是手动主从升级到自动主从,更加健壮
# 缺点
1.Redis不好在线扩容,集群容量一旦到达上限,在线扩容十分麻烦
2.实现哨兵模式的配置其实是很麻烦的,里面有很多选择,上面只是配置了最基础的配置

# 以下是哨兵模式的全部配置
# 开始

# 哨兵sentinel实例运行的端口 默认26379
port 26379
# 哨兵sentinel的工作目录
dir /tmp
# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由A-z 数字 0-9 字符".-_"组成
# quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <host> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
# 当在Redis实例中开启了requirepass foobared 授权密码,这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置的密码一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passwOrd
# 指定多少毫秒之后,主节点没有应答哨兵sentinel,此时 哨兵主观上认为主节点下线,默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
# 这个配置项指定了在发生failover主从切换时最多可以有多少个slave同时对新的master进行同步
# 这个数字越小,完成failover所需要的的时间就越长,但是如果这个数字越大,就意味着越多的slave因为
# replication而不可用。可以通过将这个值设定为1来保证每次只有一个slave处于不能处理命令请求的状态.
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间failover-timeout可以用在以下这些方面:
# 1.同一个sentinel对同一个master两次failover之间的间隔时间。
# 2.当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
# 3.当想要取消一个正在进行的failover所需要的时间。
# 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000

#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚木将会被一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当sentine1有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,
#SNS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,-个是事件的描述。如果sentine1.conf配置文件中配置了这个脚木路径,
#那么必须保证这个脚木存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本
#sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh
#客户端重新配置主节点参数脚本
#当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。#以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>#目前<state>总是“failover”,
#<role>是“1eader”或者"“observer"中的一个。
# 参数 from-ip,from-port,to-ip,to-port是用来和旧的master和新的master(即旧的slave)通信的#这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
# 结束


############################################ *Redis缓存穿透和雪崩 ############################################

# 缓存穿透(查不到)
# 问题:如果用户查询的时候命中redis缓存,那么会直接返回.如果此时redis缓存中并没有数据,那么会去数据库查询,如果数据库也没有。但是用户还一直查询就会一直请求到数据库查询
# 假如用户量多的话会给数据库造成巨大的性能消耗。

# 解决:
1.布隆过滤器
2.返回空对象:即使数据库没有数据也需要给redis缓存添加上一个空对象,这样就可以保护好数据库.

# 缓存击穿(量太大,缓存过期时突然巨大压力瞄准一个点冲向数据库)
#这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
#当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。

# 解决:
1.设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后的问题
2.加互斥锁
分布式锁∶使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

# 缓存雪崩
# 缓存雪崩,是指在某一个时间段,缓存集中过期失效。
# 产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,
# 这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。
# 而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况.

# 致命问题:
# 其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,
# 这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把教据库压垮。
# 停掉一些服务,保证主要服务可用

# 解决方案
1.redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台reds ,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
2.限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
3.数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值