NoSQL之Redis配置与优化

存储数据类型分类:

结构化数据:可以通过二维表格形式表述这个数据。
非结构化数据:不方便以二维表格形式表述的这种类型的数据。
根据不同种存储数据类型分类分成两种不同类型的数据库:
sql结构化数据库:里面存储的数据类型是结构化数据。别称称为关系型数据库
nosql非结构化数据库:里面存储的数据类型是非结构化数据。别称称为非关系型数据库

关系型数据库

●一个结构化的数据库,创建在关系模型基础上
般面向于记录
●包括
◆Oracle、 MySQL、SQL Server、Microsoft Access、DB2等

非关系型数据库

●除了主流的关系型数据库外的数据库,都认为是非关系型
包括
◆Redis、 MongBD、 Hbase、 CouhDB等

非关系型数据库产生背景

■High performance-
对数据库高并发读写需求
■Huge Storage- 对海量数据高效存储与访问需求
■High Scalability && High Availability-- 对数据库高
可扩展性与高可用性需求

Redis简介

■Redis基于内存运行并支持持久化
■采用key-value (键值对)的存储形式
■优点
●具有极高的数据读写速度
●支持丰富的数据类型
●支持数据的持久化
●原子性
●支持数据备份

Redis与Memcached区别

说到缓存技术,只要有一定经验的开发人员,肯定会想到redis和memcached这两个。并且在BAT里,redis已经逐渐取代了memcached,成为分布式场景广泛使用的缓存方案。接下来,我们就分析下,redis是如何取代memcached,成为开发者的宠儿的。

一、支持的存储类型不同

虽然redis和memcached都是内存型数据库,并且memcached不仅能够存储string类型,还能够存储图片、文件、视频等格式的文件。然而对于更多的使用内存数据库做缓存以及分布式方案的程序开发者来说,memcached提供的string类型存储的应用场景非常有限,而存储图片视频的功能又十分鸡肋(许多公司的用户场景是没这方面需求)。相比之下,redis提供set,hash,list等多种类型的存储结构,非常适合分布式缓存的实现。

二、数据落盘

memcached 数据不可恢复,虽然大多数人使用缓存以及分布式方案都不会要求数据持久化,但是谁也不能保证不出现万一的情况。一旦发生稳定性问题,memcached挂掉后,数据是不可恢复的,而redis除了支持在配置里打开数据落盘(RDB),还能通过aof来找回数据。

三、内存空间与数据量

memcached可以修改最大内存,使用的是LRU算法,而redis目前底层使用了自己的VM,引入了新的特性突破了物理内存的限制。个人认为在这方面依然是redis更加优秀一些。
value值-redis最大可以达到1GB,而memcache只有1MB;

四、使用场景

(1)、会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
(2)、全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。
再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。
此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
(3)、队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。
(4),排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。
(5)、发布/订阅
最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。
(6)、其他
但是如果是对缓存的数据格式有更多的要求,且对安全性也有很高的要求的话,建议还是使用redis,这也是redis目前正在逐渐代替memcached的根本原因。
总结:

MemcachedRedis
类型Key- value数据Key-value数据库
过期策略支持支持
数据类型单一数据类型五大数据类型
持久化不支持支持
主从复制不支持支持
虚拟内存不支持支持

Redis支持五种数据类型

string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

1.String(字符串)

string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

实例:set 键  值 设置键值对     get   键   获取键的值
Set  sting1  8
Get  string1
8
Incr string1
9
Decr string1
8
Decrby string1 2
6
Incrby string1 5
11

2.Hash(哈希)

Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

实例:Hset:添加hash数据 hget:获取hash数据 hmget:获取多个hash数据
Hset hash1 key1 a
Hset hash1 key2 b
Hset hash1 key3 c
Hset hash1 field1 a1 field2 a2
Hget hash1 key1
Hmget hash1 key1 key2 key3
Hmget hash1 field1 field2

3.List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

实例:lpush:从左边推入值 lpop:从左边弹出值  rpush:从右边推入值 rpop:从右边弹出值  llen:查看某个list数据类型的长度
Lpush list1 1
Lpush list1 2
Lpush list1 3
Llen list1
3
Rpop list1
1
Llen list1
2
Lrange list1 列出所有list1的值

4.Set(集合)

Redis 的 Set 是 string 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
sadd 命令
添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
sadd key member
scard:查看set数据中存在的元素个数
sismember:判断set数据中是否存在某个元素
srem:删除某个set数据中的元素

实例:
sadd   set1  12
1
sadd  set1  13
1
sadd   set1  12
0
Scard  set1
2
Sismember  set1  11
0
Sismember  set1  13
1
Srem set1 13
1
Sismember set1  13
0
Smembers  set1 列出set1所有值

zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
zadd 命令
添加元素到集合,元素在集合中存在则更新对应score
使用方法:zadd key score member
zcard:查询
zrang:数据排序

实例:
Zadd zset1 1.1 val1
Zadd zset1 2.2 val2
Zadd zset1 3.3 val3
Zadd zset1 3.3 val33
Zcard zset1
4
Zrangebyscore  zset1  0  10
1)val1
2)val2
3)val3
4)val33
Zrange  zset1  0  10  withscores
1)val1
2)1.10000000000000001
3)Val2
4)2.20000000000000002
5)Val3
6)3.29999999999999998
7)Val3.3
8)3.29999999999999998

各个数据类型应用场景:

类型简介特性场景
String(字符串)二进制安全可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M
Hash(字典)键值对集合,即编程语言中的Map类型适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)存储、读取、修改用户属性
List(列表)链表(双向链表)增删快,提供了操作某一段元素的API1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
Set(集合)哈希表实现,元素不重复1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted将Set中的元素增加数据插入集合时,已经进行天然排序1、排行榜 2、带权重的消息队列
Set(有序集合)一个权重参数score,元素按score有序排列

项目:安装redis

下载并解压redis软件包
[root@localhost ~]# tar zxvf redis-5.0.4.tar.gz
对解压后的软件进行配置,编译,安装
[root@localhost ~]# cd redis-5.0.4/
[root@localhost redis-5.0.4]# make
[root@localhost redis-5.0.4]# make PREFIX=/usr/local/redis install
对redis的命令做链接
[root@localhost redis-5.0.4]# ln -s /usr/local/redis/bin/* /usr/local/bin/   
执行安装脚本
[root@localhost ~]# cd redis-5.0.4/utils
[root@localhost utils]# ./install_server.sh 
修改配置文件
[root@localhost ~]# vi /etc/redis/6379.conf
bind 127.0.0.1 20.0.0.10
重启redis
[root@localhost ~]# /etc/init.d/redis_6379 restart
连接数据库
[root@localhost ~]# redis-cli -h 20.0.0.10 -p 6379

在这里插入图片描述
在这里插入图片描述

测试String (字符串)

[root@server1 ~]# redis-cli -h 20.0.0.10 -p 6379
20.0.0.13:6379> set a 8 //定义键a值为10
OK
20.0.0.13:6379> get a   //获取a的值
"8"
20.0.0.13:6379> type a   //a字符类型
string
20.0.0.13:6379> incr a   //a递增
(integer) 9
20.0.0.13:6379> get a     
"9"
20.0.0.13:6379> decr a    //a递减
(integer) 8
20.0.0.13:6379> get a
"8"
20.0.0.13:6379> incrby a 2  //递增2
(integer) 10
20.0.0.13:6379> decrby a 2   //递减2
(integer) 8

在这里插入图片描述

测试Hash (哈希)

20.0.0.13:6379> hset hash1 key1 1
(integer) 1
20.0.0.13:6379> hset hash1 key2 2
(integer) 1
20.0.0.13:6379> hset hash1 key3 3
(integer) 1
20.0.0.13:6379> hset hash1 field1 a1 field2 a2
(integer) 2
20.0.0.13:6379> hget hash1 key1
"1"
20.0.0.13:6379> hget hash1 key2
"2"
20.0.0.13:6379> hget hash1 key3
"3"
20.0.0.13:6379> hmget hash1 field1 field2
1) "a1"
2) "a2"
20.0.0.13:6379> hmget hash1 key1 key2 key3 field1 field2
1) "1"
2) "2"
3) "3"
4) "a1"
5) "a2"

在这里插入图片描述

测试List(列表)

20.0.0.13:6379> lpush list1 1  //加入键list1,值为1
(integer) 1
20.0.0.13:6379> lpush list1 2
(integer) 2
20.0.0.13:6379> lpush list1 3
(integer) 3
20.0.0.13:6379> lpop list1   //输出键list1 最右边值
"3"
20.0.0.13:6379> llen list1   //查看键list1值个数
(integer) 2
20.0.0.13:6379> lrange list1 0 1
1) "2"
2) "1"
20.0.0.13:6379> lrange list1 0 3
1) "2"
2) "1"
20.0.0.13:6379> lpush list1 11
(integer) 3
20.0.0.13:6379> lrange list1 0 3
1) "11"
2) "2"
3) "1"
20.0.0.13:6379> rpop list1
"1"
20.0.0.13:6379> lrange list 0 3
(empty list or set)
20.0.0.13:6379> lrange list1 0 3
1) "11"
2) "2"

在这里插入图片描述

测试Set(集合)

20.0.0.13:6379> sadd set1 1
(integer) 1            //成功则显示1,失败则显示0
20.0.0.13:6379> sadd set1 2
(integer) 1
20.0.0.13:6379> sadd set1 1
(integer) 0
20.0.0.13:6379> scard set1
(integer) 2
20.0.0.13:6379> sismember set1 1
(integer) 1
20.0.0.13:6379> sismember set1 3
(integer) 0
20.0.0.13:6379> srem set1 1
(integer) 1
20.0.0.13:6379> sismember set1 1
(integer) 0
20.0.0.13:6379> sadd set1 3
(integer) 1
20.0.0.13:6379> sadd set1 4
(integer) 1
20.0.0.13:6379> smembers set1   //顺序排列
1) "2"
2) "3"
3) "4"

在这里插入图片描述

测试zset(sorted set:有序集合)

20.0.0.13:6379> zadd zset1 1.1 val1
(integer) 1
20.0.0.13:6379> zadd zset1 2.2 val1  //键名唯一所有创建val1失败
(integer) 0
20.0.0.13:6379> zadd zset1 2.2 val2
(integer) 1
20.0.0.13:6379> zadd zset1 3.3 val3
(integer) 1
20.0.0.13:6379> zadd zset1 3.3 val33
(integer) 1
20.0.0.13:6379> zrangebyscore zset1 0 4  //顺序排序键
1) "val1"
2) "val2"
3) "val3"
4) "val33"
20.0.0.13:6379> zrange zset1 0 10 withscores   //顺序排序键和值
1) "val1"
2) "2.2000000000000002"
3) "val2"
4) "2.2000000000000002"
5) "val3"
6) "3.2999999999999998"
7) "val33"
8) "3.2999999999999998"

在这里插入图片描述

Redis配置文件

配置参数(letc/redis/6379.conf)

  • bind:监听的主机地址
  • port:端口
  • daemonize yes:启用守护进程
  • pidfile:指定PID文件
  • loglevel notice:日志级别
  • logfile:指定日志文件

Redis数据库常用命令

redis-cli命令行工具

连接本地数据库
[root@localhost utils]# /usr/local/redis/bin/redis-cli127.0.0.1:6379>
连接远程数据库
[root@localhost utils]# redis-cli -h 192.168.10.161 -p 6379192.168.10.161:6379>

Redis 命令工具

redis-server  //用于启动Redis的工具
redis-benchmark  //用于检测Redis 在本机的运行效率
redis-check-aof  //修复AOF持久化文件
redis-check-rdb //修复RDB 持久化文件
redis-cli   //是Redis命令行工具
redis-setinel  //是哨兵模式启动的工具

redis-benchmark 测试工具

redis-benchmark是官方自带的Redis性能测试工具,可以有效的测试Redis服务的性能。基本的测试语法为redis-benchmark [option] [option value]。

-h:指定服务器主机名。
p:指定服务器端口。
-s:指定服务器socket。
-c:指定并发连接数。
-n:指定请求数。
-d:以字节的形式指定SET/GET值的数据大小。
-k:1=keep alive 0=reconnect 。
-r:SET/GET/ INCR使用随机key,SADD使用随机值。
-P:通过管道传输请求。
-q:强制退出redis。仅显示query/sec值。
–csv:以cSV格式输出。
-l:生成循环,永久执行测试。
-t:仅运行以逗号分隔的测试命令列表。
-I:idle模式。仅打开N个idle连接并等待。

key相关命令

  • keys:获取符合规则的键值列表
  • exists:判断键值是否存在
  • del:删除当前数据库的指定key
  • type:获取key对应的value值类型
  • rename(覆盖) l renamenx(不覆盖):对已有的key进行重命名
  • dbsize:查看当前数据库中key的数目

rename

rename命令是对已有key进行重命名,
其命令格式为 rename 源 key 目标 key

使用rename命令进行重命名时,无论目标key是否存在都进行重命名,且源key的值会覆盖目标key的值。在实际使用过程中,建议先用exists命令查看目标key是否存在,然后再决定是否执行rename命令,以避免覆盖重要数据

renamenx

renamenx命令的作用上对已有key进行重命名,并检测新名是否存在,
其命令格式与rename的命令格式除命令关键字不同外基本相同,
renamenx 源 key 目标 key 。

使用renamenx命令进行重命名时,如果目标key存在则不进行重命名

Redis多数据库操作

  • Redis支持多数据库,默认支持16个数据库,0-15命名
  • 多数据库相互独立,互不干扰
  • 多数据库常用命令
    多数据库间切换
    多数据库间移动数据
    清除数据库内数据

多数据库常用命令

多数据库间切换

  • Redis支持多数据库,Redis在没有任何改动的情况下默认包含16个数据库,数据库名称是用数字0-15来依次命名的。使用’Select命令可以进行’Redis的多数据库之间的切换,命令格式为selectindex,其中index表示数据库的序号。而使用redis-cli连接Redis数据库后,默认使用的是序号为O的数据库。

多数据库间移动数据

Redis数据库提供了一个move的命令,可以进行多数据库的数据移动。

命令的基本语法格式为 ”move key dbindex“。
其中 “key“表示当前数据库的目标键,“ dbindex“表示目标数据库的序号。

清除数据库内数据

  • Redis数据库的整库数据删除主要分为两个部分:清空当前数据库数据,使用FLUSHDB
  • 命令实现;清空所有数据库的数据,使用FLUSHALL命令实现。但是,数据清空操作比较危险,生产环境下一般不建议使用。

Redis持久化

持久化概述

  • Redis是运行在内存中,内存中的数据断电丢失
  • 为了能够重用Redis数据,或者防止系统故障,需要将Redis中的数据写入到磁盘空间中,即持久化

持久化分类

  • RDB方式:创建快照的方式获取某一时刻Redis中所有数据的副本
  • AOF方式:将执行的写命令写到文件的末尾,以日志的方式来记录数据的变化

二者区别:

  • RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
  • AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

二者优缺点:

RDB的优势

  • 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  • 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
  • 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
  • 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB的劣势

  • 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

  • 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

AOF的优势

  • 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
  • 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
  • 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
  • AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。

AOF的劣势

  • 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF的恢复速度要快。
  • 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

RDB持久化

  • Redis的默认持久化方式
  • 默认文件名dump.rdb
  • 触发条件
    1、在指定的时间间隔内,执行指定次数的写操作(配置文件控制)
    2、执行save或者是bgsave(异步)命令
    3、执行flushall命令,清空数据库所有数据
    4、执行shutdown命令,保证服务器正常关闭且不丢失任何数据

AOF持久化

  • Redis默认不开启
  • 弥补RDB的不足(数据的不一致性)
  • 采用日志的形式来记录每个写操作,并追加到文件中
  • Redis重启会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

AOF的重写机制

  • AOF的工作原理是将写操作追加到文件中,文件的冗余内容会越来越多
  • 当AOF文件的大小超过所设定的阈值时,Redis就会对AOF文件的内容压缩

AOF重写的原理

  • Redis会fork出一条新进程,读取内存中的数据(开没有读取旧文件),并重新写到一个临时文件中,最后替换旧的aof文件

Redis性能管理

内存碎片率

  • 操系统分配的内存值used_memory_rss除以Redis使用的内存值used_memory计算得出

  • 内存碎片是由操作系统低效的分配/回收物理内存导致的
    1、不连续的物理内存分配

  • 跟踪内存碎片率对理解Redis实例的资源性能是非常重要的
    1、内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低
    2、内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率
    3、内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换
    25/30

内存使用率

  • redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换
  • 避免内存交换
    1、针对缓存数据大小选择
    2、尽可能的使用Hash数据结构
    3、设置key的过期时间

回收key

  • 保证合理分配redis有限的内存资源
  • 当达到设置的最人内1心u全默认情况下回收策略
    1、默认情况下回收策略是禁止删除
    2、redis.conf配置文件中修改maxmemory-policy属性值
    · volatile-lru:使曳LRU算法从已设置过期时间的数据集合中淘汰数据.
    · volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰
    · volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰
    · allkeys-Iru:使用LRU算法从所有数据集合中淘汰数据
    · allkeys-random:从数据集合中任意选择数据淘汰. no-· · enviction:禁止淘汰数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值