Redis

一、NoSQL

1-1、什么是NoSQL

        NoSQL = Not Only SQL(不仅仅是SQL) ,也解释为non-relational(非关系型数据库)。在NoSQL数据库中数据之间是无联系的,无关系的。数据的结构是松散的,可变的。

1-2 为什么使用NoSQL

关系型数据库的瓶颈:

1)无法应对每秒上万次的读写请求,无法处理大量集中的高并发操作。关系型数据的是IO密集的应用。硬盘IO也变为性能瓶颈

2)表中存储记录数量有限,横向可扩展能力有限,一张表最大二百多列。纵向数据可承受能力也是有限的,一张表的数据到达百万级,读写的速度就会逐渐的下降。面对海量数据,必须使用主从复制,分库分表。这样的系统架构是难以维护的。
大数据查询SQL效率极低,数据量到达一定程度时,查询时间会呈指数级别增长

3)无法简单地通过增加硬件、服务节点来提高系统性能。数据整个存储在一个数据库中的。多个服务器没有很好的解决办法,来复制这些数据。

4)关系型数据库大多是收费的,对硬件的要求较高。软件和硬件的成本花费比重较大。

1-3 NoSQL的优势

        1.大数据量,高性能

NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。关系型数据库(例如MySQL)使用查询缓存。这种查询缓存在更新数据后,缓存就是失效了。在频繁的数据读写交互应用中。 缓存的性能不高。NoSQL的缓存性能要高的多。

        2.灵活的数据模型

NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。尤其在快速变化的市场环境中,用户的需求总是在不断变化的。

        3.高可用

NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。

NoSQL能很好的解决关系型数据库扩展性差的问题。弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本。

MySQL和NoSQL都有各自的特点和使用的应用场景,两者结合使用。让关系数据库关注在关系上,NoSQL关注在存储上

        4.低成本

这是大多数分布式数据库共有的特点,因为主要都是开源软件,没有昂贵的License成本 

1-4 NoSQL的劣势

  1. 无关系,数据之间是无联系的。
  2. 不支持标准的SQL,没有公认的NoSQL标准
  3. 没有关系型数据库的约束,大多数也没有索引的概念
  4. 没有事务,不能依靠事务实现ACID.
  5. 没有丰富的数据类型(数值,日期,字符,二进制,大文本等)

 Redis安装和使用 

2-1 Redis介绍

        Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的Key-Value数据库. Key字符类型,其值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型,每种数据类型有自己的专属命令。所以它通常也被称为数据结构服务器。

2-2 Window安装Redis

        Windows版本的Redis是Microsoft的开源部门提供的Redis. 这个版本的Redis适合开发人员学习使用,生产环境中使用Linux系统上的Redis

1)、下载

官网:https://redis.io/

windows版本:Releases · microsoftarchive/redis · GitHub

 2)、安装

下载的Redis-x64-3.2.100.zip 解压后,放到某个目录(例如d:\tools\),即可使用。

目录结构:

 3)、启动

1.​​​​、Windows7系统双击 redis-server.exe 启动Redis

2、Windows 10系统

有的机器双击redis-server.exe 执行失败,找不到配置文件,可以采用以下执行方式:

在命令行(cmd)中按如下方式执行:

D:\tools\Redis-x64-3.2.100>redis-server.exe redis.windows.conf

如图:

 4)关闭

按ctrl+c 退出Redis服务程序。

2-3 Linux上安装Redis

1)、下载

wget http://219.238.7.66/files/502600000A29C8D5/download.redis.io/releases/redis-3.2.9.tar.gz

2)、安装 

1.​​​​​​上传redis-3.2.9.tar到linux 系统。使用Xftp工具,或者使用liunx命令 rz-y

2.解压redis-3.2.9.tar到usr/local目录

3.查看解压后的文件

 

 4.编译Redis文件, Redis是使用 c 语言编写的。 会使用gcc编译器。

在解压后的Redis目录下执行 (cd /usr/local/redis-3.2.9) make 命令。

注意事项:

1)make命令执行过程中可能报错,根据控制台输出的错误信息进行解决

2)错误一:gcc命令找不到,是由于没有安装gcc导致

   解决方式:安装gcc编译器后在执行make命令

    什么是 gcc ?

gcc是GNU compiler collection的缩写,它是Linux下一个编译器集合( 相当于javac ),是c或c++程序的编译器。

   怎么安装gcc ?

使用yum进行安装gcc 。执行命令:yum -y install gcc

3)错误二: error: jemalloc/jemalloc.h: No such file or directory

解决方式执行 make MALLOC=libc

开始执行make

 

出现错误: 

没有gcc , cc 编译器 ,解决安装gcc

使用yum -y install gcc 

重新再编译make 。注意:安装完gcc之后,再执行make,先执行 make distclean 清理一下上次make后产生的文件。

先执行 make distclean

在执行make

 

 执行make成功的标志

注意:在make执行之后再执行 make install,该操作则将 src下的许多可执行文件复制到/usr/local/bin 目录下,这样做可以在任意目录执行redis的软件的命令(例如启动,停止,客户端连接服务器等), make install 可以不用执行,看个人习惯。

查看make编译结果,cd src目录

注意:在make执行之后再执行 make install,该操作则将 src下的许多可执行文件复制到/usr/local/bin 目录下,这样做可以在任意目录执行redis的软件的命令(例如启动,停止,客户端连接服务器等), make install 可以不用执行,看个人习惯。

查看make编译结果,cd src目录

cd src  在执行 ls

 3)、启动Redis

启动方式:

  •  前台启动 ./redis-server
  •  后台启动 ./redis-server &    (建议使用)

第1种 前台启动

启动Redis的服务器端:切换到src 目录下执行 redis-server程序

redis应用以前台的方式启动,不能退出当前窗口, 退出窗口,应用终止。 

 在其他窗口查看redis启动的进程

 第2种 后台启动

src目录下执行  ./redis-server &  此时关闭窗口,查看redis进程,依然存在。

 查看redis进程

4)、​​​​​​​关闭Redis

 关闭方式:

① 使用redis客户端关闭, 向服务器发出关闭命令

   切换到 redis-3.2.9/src/ 目录,执行 ./redis-cli shutdown

   推荐使用这种方式, redis先完成数据操作,然后再关闭。

② kill pid 或者 kill -9 pid

这种不会考虑当前应用是否有数据正在执行操作,直接就关闭应用。

先使用 ps -ef | grep redis 查出进程号, 在使用 kill pid

 2-4 Redis客户

Redis客户端是一个程序,通过网络连接到Redis服务器, 在客户端软件中使用Redis可以识别的命令,向Redis服务器发送命令, 告诉Redis想要做什么。Redis把处理结果显示在客户端界面上。 通过Redis客户端和Redis服务器交互。

2-4-1 redis命令行客户端:

        redis-cli (Redis Command Line Interface)是Redis自带的基于命令行的Redis客户端,用于与服务端交互,我们可以使用该客户端来执行redis的各种命令。

两种常用的连接方式:

​​​​​​​1.直接连接redis (默认ip127.0.0.1,端口6379)./redis-cli

在redis安装目录\src, 执行  ./redis-cli

此命令是连接本机127.0.0.1 ,端口6379的redis

​​​​​​​2.指定IP和端口连接redis./redis-cli -h 127.0.0.1 -p 6379

-h redis主机IP(可以指定任意的redis服务器)

-p 端口号(不同的端口表示不同的redis应用)

在redis安装目录\src, 执行  ./redis-cli -h 127.0.0.1 -p 6379

 2-4-2 redis远程客户端

Redis Desktop Manager:C++ 编写,响应迅速,性能好。:

github: https://github.com/uglide/RedisDesktopManager

官方地址:https://redisdesktop.com/icon-default.png?t=M7J4https://redisdesktop.com/使用文档:http://docs.redisdesktop.com/en/latest/

 点击“DOWNLOAD”

 1.​​安装客户端软件

        在Windows系统使用此工具,连接Linux上或Windows上的Redis , 双击此exe文件执行安装

安装后启动界面:

 

 2.​​​​​​​使用客户端连接Linux的Redis

连接Linux的Reids之前需要修改Redis服务器的配置信息。 Redis服务器有安全保护措施,默认只有本机(安装Redis的那台机器)能够访问。配置信息存放在Redis安装目录下的redis.conf文件。修改此文件的两个设置。

远程连接redis需要修改redis主目录下的redis.conf配置文件:

①、bind ip 绑定ip此行注释

②、protected-mode yes 保护模式改为no

使用vim 命令修改redis.conf 文件, 修改文件前备份此文件,执行cp 命令

 执行 vim redis.conf

 3.​​​​​​​使用redis.conf启动Redis

        修改配置文件后,需要使用配置文件重新启动Reids,默认不加载配置文件。先关闭已经启动的Redis ,使用以下命令启动Redis在Redis安装目录执行:

 ./redis-server ../redis.conf &

 4.​​​​​​​配置Redis Desktop Manamager(RDM),连接Redis

在RDM的主窗口,点击左下的“Connect to Redis Server”

 注意:如果连接不成功,可以试着将虚拟机防火墙关闭

连接成功后:

2-4-3 redis编程客户端 

1.Jedis

redis的Java编程客户端,Redis官方首选推荐使用Jedis,jedis是一个很小但很健全的redis的java客户端。通过Jedis可以像使用Redis命令行一样使用Redis。

  1. jedis完全兼容redis 2.8.x and 3.x.x
  2. Jedis源码:https://github.com/xetorthio/jedis
  3. api文档:​​​​​​​http://xetorthio.github.io/jedis/

2.redis的其他编程语言客户端:

        C 、C++ 、C# 、Erlang、Lua 、Objective-C 、Perl 、PHP 、Python 、Ruby 、Scala 、Go等40多种语言都有连接redis的编程客户端

 2-5 Redis基本操作命令

        redis默认为16个库 (在redis.conf文件可配置,该文件很重要,后续很多操作都是这个配置文件) redis默认自动使用0号库

1)、​​​​​​​沟通命令,查看状态

redis >ping 返回 PONG

解释输入pingredis给我们返回PONG,表示redis服务运行正常

 2)、​​​​​​​查看当前数据库中key的数目:dbsize

        语法:dbsize

        作用:返回当前数据库的 key 的数量。

        返回值:数字,key的数量

        例:先查索引5的key个数, 再查 0 库的key个数

 3)、​​​​​​​redis默认使用16个

         Redis默认使用16个库,从0到15。 对数据库个数的修改,在redis.conf文件中databases 16

 4)、​​​​​​​切换库命令:select db

        使用其他数据库,命令是 select index

例1: select 5

​​​​​​​5)、删除当前库的数据:flushdb

6)、​​​​​​​redis自带的客户端退出当前redis连接: exit  quit

2-6 RedisKey的操作命令

1)、​​keys 

 语法:keys pattern

作用:查找所有符合模式pattern的key.  pattern可以使用通配符。

通配符:

  1. * :表示0-多个字符 ,例如:keys * 查询所有的key。
  2. ?:表示单个字符,例如:wo?d , 匹配 word , wood

例1:显示所有的key

例2:使用 * 表示0或多个字符

例3:使用 ? 表示单个字符

2)exists 

语法:exists key [key…]

作用:判断key是否存在

返回值:整数,存在key返回1,其他返回0. 使用多个key,返回存在的key的数量。

例1:检查指定key是否存在

 例2:检查多个key

 3)、​​​​​​​expire

语法:expire key seconds

作用:设置key的生存时间,超过时间,key自动删除。单位是秒。

返回值:设置成功返回数字 1, 其他情况是 0 。

例1: 设置红灯的倒计时是5秒

 4)、ttl

语法:ttl key

作用:以秒为单位,返回key的剩余生存时间(ttl: time to live)

返回值:

  1. -1 :没有设置key的生存时间, key永不过期。
  2. -2 :key不存在
  3. 数字:key的剩余时间,秒为单位

例1:设置redlight的过期时间是10, 查看剩余时间

 5)、type

语法:type key

作用:查看key所存储值的数据类型

返回值:字符串表示的数据类型

  1. none (key不存在)
  2. string (字符串)
  3. list (列表)
  4. set (集合)
  5. zset (有序集)
  6. hash (哈希表)

例1:查看存储字符串的key :wood

 例2:查看不存在的key

6)、del

语法:del key [key…]

作用:删除存在的key ,不存在的key忽略。

返回值:数字,删除的key的数量。

例1:删除指定的key

 2-7 Redis的5种数据类型

1)、​​​​​​​字符串类型 string

        字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。最大512M。

2)、​​​​​​​哈希类型 hash

         Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象

 3)、​​​​​​​列表类型 list

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

 4)、​​​​​​​集合类型 set

        Redis的Set是string类型的无序集合,集合成员是唯一的,即集合中不能出现重复的数据.

 5)、​​​​​​​有序集合类型 zset sorted set

        Redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。

        不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。

三、 Redis数据类型操作命令

3-1 字符串类型(string

        字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。

3-1-1 基本命令

1)、​​​​​​​set

将字符串值 value 设置到 key 中

语法:set key value

 查看已经插入的key

向已经存在的key设置新的value,会覆盖原来的值

 2)​​​​​​、get

获取 key 中设置的字符串值

语法: get key

例如:获取 username这个key对应的value

 3)、incr

        将 key 中储存的数字值加1,如果 key 不存在,则 key 的值先被初始化为 0 再执行 incr 操作(只能对数字类型的数据操作)

语法:incr key

例 1:操作key,值增加 1

 例2:对非数字的值操作是不行的

 4)、decr

        将 key 中储存的数字值减1,如果 key 不存在,则么 key 的值先被初始化为 0 再执行 decr  操做(只能对数字类型的数据操作)

语法:decr key

例1:不存在的key,初值为0,再减 1 。

例2:对存在的数字值的 key ,减 1 。

先执行 incr index ,增加到 3

 5)、append

语法:append key value

说明:如果 key 存在, 则将 value 追加到 key 原来旧值的末尾

如果 key 不存在, 则将key 设置值为 value

返回值:追加字符串之后的总长度

例1:追加内容到存在的key

 例2:追加到不存在的key,同set key value

3-1-2 常用命令 

1)、strlen

语法:strlen key

说明:返回 key 所储存的字符串值的长度

返回值:

①:如果key存在,返回字符串值的长度

②:key不存在,返回0

例1:计算存在key的字符串长度

设置中文 set k4 中文长度 , 按字符个数计算 

 例2:计算不存在的key

 2)、getrange

语法:getrange key start end

作用:获取 key 中字符串值从 start 开始 到 end 结束 的子字符串,包括start和end, 负数表示从字符串的末尾开始, -1 表示最后一个字符

返回值:截取的子字符串。

使用的字符串 key: school, value: bjpowernode

例1: 截取从2到5的字符

 例2:从字符串尾部截取,start ,end 是负数,最后一位是 -1

例3:超出字符串范围的截取 ,获取合理的子串

 

 3)、setrange

语法:setrange key offset value

说明:用value覆盖(替换)key的存储的值从offset开始,不存在的key做空白字符串。

返回值:修改后的字符串的长度

例1:替换给定的字符串

 例2:设置不存在的key

 4)、mset

语法:mset key value [key value…]

说明:同时设置一个或多个 key-value 对

返回值: OK

例1:一次设置多个key, value

 5)、mget

语法:mget key [key …]

作用:获取所有(一个或多个)给定 key 的值

返回值:包含所有key的列表

例1:返回多个key的存储值

例2:返回不存在的key

 

 3-2 哈希类型hash

        redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象

3-2-1 基本命令

1)hset

语法:hset  key  field  value

作用:将哈希表 key 中的域 field 的值设为 value ,如果key不存在,则新建hash表,执行赋值,如果有field ,则覆盖值。

返回值:

①如果field是hash表中新field,且设置值成功,返回1

②如果field已经存在,旧值覆盖新值,返回0

例1:新的field

 例2:覆盖旧的的field

2)、hget

语法:hget key field

作用:获取哈希表 key 中给定域 field 的值

返回值:field域的值,如果key不存在或者field不存在返回nil

例1:获取存在key值的某个域的值

 例2:获取不存在的field

 

 3)、hmset

语法:hmset key  field value [field value…]

说明:同时将多个 field-value (域-值)设置到哈希表 key 中,此命令会覆盖已经存在的field,hash表key不存在,创建空的hash表,执行hmset.

返回值:设置成功返回ok, 如果失败返回一个错误

例1:同时设置多个field-value

使用redis-desktop-manager工具查看hash表 website的数据结构 

4)、hmget

语法:hmget key field [field…]

作用:获取哈希表 key 中一个或多个给定域的值

返回值:返回和field顺序对应的值,如果field不存在,返回nil

例1:获取多个field的值

 

 5)、hgetall

语法:hgetall key

作用:获取哈希表 key 中所有的域和值

返回值:以列表形式返回hash中域和域的值 ,key 不存在,返回空hash

例1:返回key对应的所有域和值 

例2:不存在的key,返回空列表

 

 6)、hdel

语法:hdel key field [field…]

作用:删除哈希表 key 中的一个或多个指定域field,不存在field直接忽略

返回值:成功删除的field的数量

例1:删除指定的field

3-2-2 常用命令 

1)、hkeys

语法:hkeys key

作用:查看哈希表 key 中的所有field域

返回值:包含所有field的列表,key不存在返回空列表

例1:查看website所有的域名称

 2)、hvals

语法:hvals key

作用:返回哈希表 中所有域的值

返回值:包含哈希表所有域值的列表,key不存在返回空列表

例1:显示website哈希表所有域的值

 3)、hexists

语法:hexists key field

作用:查看哈希表 key 中,给定域 field 是否存在

返回值:如果field存在,返回1, 其他返回0

例1:查看存在key中field域是否存在

 3-3 列表list

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

3-3-1 基本命令

1)、lpush

语法:lpush key value [value…]

作用:将一个或多个值 value 插入到列表 key 的表头(最左边),从左边开始加入值,从左到右的顺序依次插入到表头

返回值:数字,新列表的长度

例1:将a,b,c插入到mylist列表类型

 在 redis-desktop-manager显示

插入图示:

 

例2:插入重复值到list列表类型

 

在 redis-desktop-manager显示

 

 2)、rpush

语法:rpush key value [value…]

作用:将一个或多个值 value 插入到列表 key 的表尾(最右边),各个 value 值按从左到右的顺序依次插入到表尾

返回值:数字,新列表的长度

例1:插入多个值到列表

在 redis-desktop-manager显示: 

 3)、lrange

语法:lrange key start stop

作用:获取列表 key 中指定区间内的元素,0 表示列表的第一个元素,以 1 表示列表的第二个元素;start , stop 是列表的下标值,也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 start ,stop超出列表的范围不会出现错误。

返回值:指定区间的列表

例1:返回列表的全部内容

 例2:显示列表中第2个元素,下标从0开始

4)、lindex

语法:lindex key index

作用:获取列表 key 中下标为指定 index 的元素,列表元素不删除,只是查询。0 表示列表的第一个元素,以 1 表示列表的第二个元素;start , stop 是列表的下标值,也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

返回值:指定下标的元素;index不在列表范围,返回nil

例1:返回下标是1的元素

 

 例2:不存在的下标

5)、llen

语法:llen key

作用:获取列表 key 的长度

返回值:数值,列表的长度; key不存在返回0

例1:显示存在key的列表元素的个数

3-3-2 常用命令 

 1)、lrem

语法:lrem key count value

作用:根据参数 count 的值,移除列表中与参数 value 相等的元素, count >0 ,从列表的左侧向右开始移除; count < 0 从列表的尾部开始移除;count = 0移除表中所有与 value 相等的值。

返回值:数值,移除的元素个数

例1:删除2个相同的列表元素

 例2:删除列表中所有的指定元素,删除所有的java

 2)、lset

语法:lset key index value

作用:将列表 key 下标为 index 的元素的值设置为 value。

返回值:设置成功返回ok ; key不存在或者index超出范围返回错误信息

例1:设置下标2的value为“c”。

 3)、linsert

语法:linsert key BEFORE|ALFTER pivot value

作用:将值 value 插入到列表 key 当中位于值 pivot 之前或之后的位置。key不存在,pivot不在列表中,不执行任何操作。

返回值:命令执行成功,返回新列表的长度。没有找到pivot返回 -1, key不存在返回0。

例1:修改列表arch,在值dao之前加入service

例2:操作不存在的pivot

 

3-4 集合类型set 

        redis的Set是string类型的无序集合,集合成员是唯一的,即集合中不能出现重复的数据

3-4-1 基本命令

1)、sadd

语法:sadd key member [member…]

作用:将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略,不会再加入。

返回值:加入到集合的新元素的个数。不包括被忽略的元素。

例1:添加单个元素

 2)、smember

语法:smembers key

作用:获取集合 key 中的所有成员元素,不存在的key视为空集合

例1:查看集合的所有元素

例2:查看不存在的集合

 3)、sismember

语法:sismember key member

作用:判断 member 元素是否是集合 key 的成员

返回值:member是集合成员返回1,其他返回 0 。

例1:检查元素是否存在集合中

 4)、scard

语法:scard key

作用:获取集合里面的元素个数

返回值:数字,key的元素个数。 其他情况返回 0 。

例1:统计集合的大小

例2:统计不存在的key

 

 5)、srem

语法:srem key member [member…]

作用:删除集合 key 中的一个或多个 member 元素,不存在的元素被忽略。

返回值:数字,成功删除的元素个数,不包括被忽略的元素。

例1:删除存在的一个元素,返回数字 1

 例2:删除不存在的元素

 3-4-2 常用命令

1)、srandmember

语法:srandmember key [count]

作用:只提供key,随机返回集合中一个元素,元素不删除,依然在集合中;提供了count时,count 正数, 返回包含count个数元素的集合, 集合元素各不相同。count 是负数,返回一个count绝对值的长度的集合, 集合中元素可能会重复多次。

返回值:一个元素;多个元素的集合

例1:随机显示集合的一个元素

 例2:使用count参数, count是正数

例3:使用count参数,count是负数

 

 2)、spop

语法:spop key [count]

作用:随机从集合中删除一个元素, count是删除的元素个数。

返回值:被删除的元素,key不存在或空集合返回nil

例如1:随机从集合删除一个元素

 

 例2:随机删除指定个数的元素

3-5 有序集合类型 zset sorted set 

        redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。

        不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。

3-5-1 基本命令

1)、zadd

语法:zadd key score member [score member…]

作用:将一个或多个 member 元素及其 score 值加入到有序集合 key 中,如果member存在集合中,则更新值;score可以是整数或浮点数

返回值:数字,新添加的元素个数

例1:创建保存学生成绩的集合

 例2:使用浮点数作为score

2)、zrange

语法:zrange key start stop [WITHSCORES]

作用:查询有序集合,指定区间的内的元素。集合成员按score值从小到大来排序。 start, stop都是从0开始。0是第一个元素,1 是第二个元素,依次类推。以 -1表示最后一个成员,-2 表示倒数第二个成员。WITHSCORES选项让score和value一同返回。

返回值:自定区间的成员集合

例1:显示集合的全部元素,不显示score,不使用WITHSCORES

 例2:显示集合全部元素,并使用WITHSCORES

 例3:显示第0,1二个成员

 例4:排序显示浮点数的score

3)、​​​​​​​zrevrange

语法:zrevrange key start stop [WITHSCORES]

作用:返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。其它同zrange命令。

返回值:自定区间的成员集合

 例1:成绩榜

4)、zrem

语法:zrem key member [member…]

作用:删除有序集合 key 中的一个或多个成员,不存在的成员被忽略

返回值:被成功删除的成员数量,不包括被忽略的成员。

例1:删除指定一个成员wangwu

 

5)、zcard 

语法:zcard key

作用:获取有序集 key 的元素成员的个数

返回值:key存在返回集合元素的个数, key不存在,返回0

例1:查询集合的元素个数

 3-5-2 常用命令

1)、​​​​​​​zrangebyscore

语法:zrangebyscore key min max [WITHSCORES ] [LIMIT offset count]

作用:获取有序集 key 中,所有 score 值介于 min 和 max 之间(包括min和max)的成员,有序成员是按递增(从小到大)排序。

      min ,max是包括在内 , 使用符号 ( 表示不包括。 min,max 可以使用 -inf  ,+inf表示最小和最大

     limit 用来限制返回结果的数量和区间。

     withscores 显示score 和 value

返回值:指定区间的集合数据

使用的准备数据

例1:显示指定具体区间的数据

 

例2:显示指定具体区间的集合数据,开区间(不包括min,max)

 

 例3:显示整个集合的所有数据

例4:使用limit

增加新的数据: 

 显示从第一个位置开始,取一个元素。

2)、​​​​​​​zrevrangebyscore

 语法:zrevrangebyscore key max min  [WITHSCORES ] [LIMIT offset count]

作用:返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。其他同zrangebyscore

例1:查询工资最高到3000之间的员工

3)、zcount 

语法:zcount key min max

作用:返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量

例1:求工资在3000-5000的员工数量

四、高级话题

 4-1 Redis事务

4-1-1 什么是事务

        事务是指一系列操作步骤,这一系列的操作步骤,要么完全地执行,要么完全地不执行。

        Redis中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令被执行时中间不会被任何其他操作打断。

4-1-2 事务操作的命令

1)、multi

语法: multi

作用:标记一个事务的开始。事务内的多条命令会按照先后顺序被放进一个队列当中。

返回值:总是返回ok

2)、exec

语法:exec

作用:执行所有事务块内的命令

返回值:事务内的所有执行语句内容,事务被打断(影响)返回nil

3)、discard

语法:discard

作用:取消事务,放弃执行事务块内的所有命令

返回值:总是返回ok

4)、watch

语法:watch key [key ...]

作用监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

返回值:总是返回ok

5)、unwatch

语法:unwatch

作用:取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 

返回值:总是返回ok

4-1-3 事务的实现

1)、​​​​​​​正常执行事务

事务的执行步骤: 首先开启事务, 其次向事务队列中加入命令,最后执行事务提交

例1:事务的执行:

1multi : 用multi命令告诉Redis,接下来要执行的命令你先不要执行,而是把它们暂时存起来 (开启事务)

2)sadd works john 第一条命令进入等待队列(命令入队)

3sadd works rose 第二条命令进入等待队列(命令入队)

4)exce 告知redis执行前面发送的两条命令(提交事务)

 查看works集合

 2)、​​​​​​​​​​​​​​事务执行exec之前,入队命令错误(语法错误;严重错误导致服务器不能正常工作(例如内存不足)),放弃事务。

执行事务步骤:

1)MULTI 正常命令

2)SET key value 正常命令

3)INCR  命令语法错误

4)EXEC  无法执行事务,那么第一条正确的命令也不会执行,所以key的值不会设置成功

结论:事务执行exec之前,入队命令错误,事务终止,取消,不执行。 

3)、​​​​​​​事务执行exec命令后,执行队列命令,命令执行错误,事务提交

执行步骤:

1)MULTI 正常命令

2)SET username zhangsan 正常命令

3)lpop username  正常命令,语法没有错误,执行命令时才会有错误。

4)EXEC 正常执行 ,发现错误可以在事务提交前放弃事务,执行discard.

 结论:在exec执行后的所产生的错误,  即使事务中有某个/某些命令在执行时产生了错误, 事务中的其他命令仍然会继续执行。

Redis 在事务失败时不进行回滚,而是继续执行余下的命令。

Redis这种设计原则是:Redis 命令只会因为错误的语法而失败(这些问题不能在入队时发现),或是命令用在了错误类型的键上面,失败的命令并不是Redis导致,而是由编程错误造成的,这样错误应该在开发的过程中被发现,生产环境中不应出现语法的错误。就是在程序的运行环境中不应该出现语法的错误。而Redis能够保证正确的命令一定会被执行。再者不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

4)、放弃事务

执行步骤:

1) MULTI 开启事务

2) SET age 25  命令入队

3) SET age 30 命令入队

4) DISCARD 放弃事务,则命令队列不会被执行

例1:

5)、​​​​​​​Redis的watch机制

 A.​​​​​​​Redis的WATCH机制

WATCH机制原理:

WATCH机制:使用WATCH监视一个或多个key , 跟踪key的value修改情况, 如果有key的value值在事务EXEC执行之前被修改了, 整个事务被取消。EXEC 返回提示信息,表示事务已经失败

WATCH机制使的事务EXEC变的有条件,事务只有在被WATCH的key没有修改的前提下才能执行。不满足条件,事务被取消。使用 WATCH 监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正常执行

大多数情况下, 不同的客户端会访问不同的键, 相互同时竞争同一key的情况一般都很少, 乐观锁能够以很好的性能解决数据冲突的问题。

B.​​​​​何时取消key的监视(WATCH)?

WATCH 命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效,直到调用 EXEC 为止。不管事务是否成功执行, 对所有键的监视都会被取消。

② 当客户端断开连接时, 该客户端对键的监视也会被取消。

UNWATCH 命令可以手动取消对所有键的监视

C.​​​​​​​WATCH的事例

执行步骤:

首先启动redis-server , 在开启两个客户端连接。 分别叫 A 客户端 和 B客户端。

启动Redis服务器

 A客户端(红色):WATCH某个key ,同时执行事务

 B 客户端(黄色):对A客户端WATCH的key修改其value值。

1.在A客户端设置key : str.lp登录人数为10

2.在A客户端监视 key : str.lp

3.在A客户端开启事务 multi

4.在A客户端修改 str.lp的值为11

5.在B客户端修改 str.lp的值为 15

6.在A客户端执行事务exec

7.在A客户端查看 str.lp值,A客户端执行的事务没有提交,因为WATCH的str.lp的值已经被修改了, 所有放弃事务。

例1:乐观锁

4-2 持久化 

4-2-1 持久化概述

        持久化可以理解为存储,就是将数据存储到一个不会丢失的地方,如果把数据放在内存中,电脑关闭或重启数据就会丢失,所以放在内存中的数据不是持久化的,而放在磁盘就算是一种持久化。

        Redis的数据存储在内存中,内存是瞬时的,如果linux宕机或重启,又或者Redis崩溃或重启,所有的内存数据都会丢失,为解决这个问题,Redis提供两种机制对数据进行持久化存储,便于发生故障后能迅速恢复数据。

4-2-2 持久化方式

(一)、RDB方式

1)​​​​​​​、什么是RDB方式?

        Redis Database(RDB),就是在指定的时间间隔内将内存中的数据集快照写入磁盘,数据恢复时将快照文件直接再读到内存。

        RDB 保存了在某个时间点的数据集(全部数据)。存储在一个二进制文件中,只有一个文件。默认是dump.rdb。RDB技术非常适合做备份,可以保存最近一个小时,一天,一个月的全部数据。保存数据是在单独的进程中写文件,不影响Redis的正常使用。RDB恢复数据时比其他AOF速度快。

2)、如何实现

RDB方式的数据持久化,仅需在redis.conf文件中配置即可,默认配置是启用的。

在配置文件redis.conf中搜索 SNAPSHOTTING, 查找在注释开始和结束之间的关于RDB的配置说明。配SNAPSHOTTING置地方有三处。

①:配置执行RDB生成快照文件的时间策略。

对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个key改动”这一条件被满足时, 自动保存一次数据集。

配置格式:save  <seconds>  <changes>

save 900 1

save 300 10

save 60 10000

②:dbfilename:设置RDB的文件名,默认文件名为dump.rdb

③:dir:指定RDB文件的存储位置,默认是 ./ 当前目录

配置步骤:

①:查看 ps -ef | grep redis ,如果redis服务启动,先停止。

 ②:修改redis.conf 文件, 修改前先备份,执行 cp  redis.conf  bak_redis.conf

查看默认启用的RDB文件

 

 ③:编辑redis.conf 增加save配置, 修改文件名等。vim redis.conf

 修改的内容:

把原来的默认的dump.rdb删除,修改redis.conf后,重新启动redis

④:在20秒内容,修改三个key的值

⑤:查看生成的rdb文件

 3)、总结

优点:由于存储的是数据快照文件,恢复数据很方便,也比较快

缺点:

1)会丢失最后一次快照以后更改的数据。如果你的应用能容忍一定数据的丢失,那么使用rdb是不错的选择;如果你不能容忍一定数据的丢失,使用rdb就不是一个很好的选择。

2)由于需要经常操作磁盘,RDB 会分出一个子进程。如果你的redis数据库很大的话,子进程占用比较多的时间,并且可能会影响 Redis 暂停服务一段时间(millisecond 级别),如果你的数据库超级大并且你的服务器CPU比较弱,有可能是会达到一秒。

 (二)、AOF方式

1)、​​​​​​​什么是AOF方式

        Append-only File(AOF),Redis每次接收到一条改变数据的命令时,它将把该命令写到一个AOF文件中(只记录写操作,读操作不记录),当Redis重启时,它通过执行AOF文件中所有的命令来恢复数据。

2)、如何实现

AOF方式的数据持久化,仅需在redis.conf文件中配置即可

配置项:

①:appendonly:默认是no,改成yes即开启了aof持久化

②:appendfilename:指定AOF文件名,默认文件名为appendonly.aof

③:dir : 指定RDB和AOF文件存放的目录,默认是 ./

④:appendfsync:配置向aof文件写命令数据的策略:

no:不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),比较快但不是很安全。

always:每次执行写入都会执行同步,慢一些但是比较安全。

everysec:每秒执行一次同步操作,比较平衡,介于速度和安全之间。这是默认项。

⑤:auto-aof-rewrite-min-size:允许重写的最小AOF文件大小,默认是64M 。当aof文件大于64M时,开始整理aop文件, 去掉无用的操作命令。缩小aop文件。

例1:

①:停止运行的redis , 备份要修改的redis.conf

②:查看redis安装目录/src下有无 .aof 文件。 默认是在redis的当前目录

③:编辑 redis.conf

设置 appendonly 为 yes 即可。

查看 appendfsync 的当前策略。

查看 appendfilname的文件名称

 ④:在redis客户端执行 写入命令

⑤ 查看aof文件

2)、总结 

1)append-only 文件是另一个可以提供完全数据保障的方案;

2)AOF 文件会在操作过程中变得越来越大。比如,如果你做一百次加法计算,最后你只会在数据库里面得到最终的数值,但是在你的 AOF 里面会存在 100 次记录,其中 99 条记录对最终的结果是无用的;但 Redis 支持在不影响服务的前提下在后台重构 AOF 文件,让文件得以整理变小

3)可以同时使用这两种方式,redis默认优先加载aof文件(aof数据最完整);

4-3 主从复制 

4-3-1 主从复制--读写分离

        通过持久化功能,Redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,但是由于数据是存储在一台服务器上的,如果这台服务器出现故障,比如硬盘坏了,也会导致数据丢失。

        为了避免单点故障,我们需要将数据复制多份部署在多台不同的服务器上,即使有一台服务器出现故障其他服务器依然可以继续提供服务。

        这就要求当一台服务器上的数据更新后,自动将更新的数据同步到其他服务器上,那该怎么实现呢? Redis的主从复制。

        Redis提供了复制(replication)功能来自动实现多台redis服务器的数据同步(每天19点 新闻联播,基本从cctv1-8,各大卫视都会播放)

        我们可以通过部署多台redis,并在配置文件中指定这几台redis之间的主从关系,主负责写入数据,同时把写入的数据实时同步到从机器,这种模式叫做主从复制,即master/slave,并且redis默认master用于写,slave用于读,向slave写数据会导致错误

(一)、Redis主从复制实现(master/salve)

方式1:修改配置文件,启动时,服务器读取配置文件,并自动成为指定服务器的从服务器,从而构成主从复制的关系

方式2: ./redis-server --slaveof <master-ip> <master-port>,在启动redis时指定当前服务成为某个主Redis服务的从Slave

方式1的实现步骤:

模拟多Reids服务器, 在一台已经安装Redis的机器上,运行多个Redis应用模拟多个Reids服务器。一个Master,两个Slave.

1)、​​​​​​​新建三个Redis的配置文件

如果Redis启动,先停止。

作为Master的Redis端口是 6380

作为Slaver的Redis端口分别是6382 , 6384

从原有的redis.conf 拷贝三份,分别命名为 redis6380.conf, redis6382.conf , redis6384.conf

 2)、​​​​​​​编辑Master配置文件

编辑Master的配置文件redis6380.conf : 在空文件加入如下内容

include /usr/local/redis-3.2.9/redis.conf

daemonize yes

port 6380

pidfile /var/run/redis_6380.pid

logfile 6380.log

dbfilename dump6380.rdb

配置项说明:

include : 包含原来的配置文件内容。/usr/local/redis-3.2.9/redis.conf按照自己的目录设置。

daemonize:yes 后台启动应用,相当于 ./redis-server & , &的作用。

port : 自定义的端口号

pidfile : 自定义的文件,表示当前程序的pid ,进程id。

logfile:日志文件名

dbfilename:持久化的rdb文件名

3)、​​​​​​​编辑Slave配置文件

编辑Slave的配置文件redis6382.conf 和redis6384.conf: 在空文件加入如下内容

①:redis6382.conf:

include /usr/local/redis-3.2.9/redis.conf

daemonize yes

port 6382

pidfile /var/run/redis_6382.pid

logfile 6382.log

dbfilename dump6382.rdb

slaveof 127.0.0.1 6380

配置项说明:

slaveof : 表示当前Redis是谁的从。当前是127.0.0.0 端口6380这个Master的从。

②:redis6384.conf:

include /usr/local/redis-3.2.9/redis.conf

daemonize yes

port 6384

pidfile /var/run/redis_6384.pid

logfile 6384.log

dbfilename dump6384.rdb

slaveof 127.0.0.1 6380

 4)、​​​​​​​启动服务器 Master/Slave都启动

启动方式 ./redis-server 配置文件

启动Redis,并查看启动进程

 5)、​​​​​​​​​​​​​​查看配置后的服务信息

命令:

①: Redis客户端使用指定端口连接Redis服务器

./redis-cli -p 端口

②:查看服务器信息

info replication

登录到Master:6380

查看当前服务信息

在客户端的Redis内执行命令 info replication

Master服务的查看结果:

在新的Xshell窗口分别登录到6382 ,6384查看信息

 

6384也登录内容同6382.

6)、​​​​​​​向Master写入数据

 在6380执行flushall 清除数据,避免干扰的测试数据。 生产环境避免使用。

 7)、​​​​​​​在从Slave读数据

6382,6384都可以读主Master的数据,不能写

Slave写数据失败

(二)、​​​​​​​容灾处理

        当Master服务出现故障,需手动将slave中的一个提升为master, 剩下的slave挂至新的master上(冷处理:机器挂掉了,再处理)

命令:

①:slaveof no one,将一台slave服务器提升为Master (提升某slave为master)

②:slaveof 127.0.0.1 6381 (将slave挂至新的master上)

执行步骤:

1)、​​​​​​​将Master:6380停止(模拟挂掉)

2)、​​​​​​​选择一个Slave升到Master,其它的Slave挂到新提升的Master

 3)、​​​​​​​将其他Slave挂到新的Master

在Slave 6384上执行

现在的主从(Master/Slave)关系:Master是6382 , Slave是6384

查看6382:

 4)、​​​​​​​原来的服务器重新添加到主从结构中

6380的服务器修改后,从新工作,需要把它添加到现有的Master/Slave中

先启动6380的Redis服务

连接到6380端口

 

当前服务挂到Master上

 

 5)、​​​​​​​查看新的Master信息

在6382执行:

现在的Master/Slaver关系是:

   Master: 6382

   Slave: 6380、6384

 (三)、​​​​​​​操作命令

进入客户端需指定端口:./redis-cli -p 6380

不配置启动默认都是主master

info replication 查看redis服务器所处角色

 (四)、总结

1、一个master可以有多个slave

2、slave下线,读请求的处理性能下降

3、master下线,写请求无法执行

4、当master发生故障,需手动将其中一台slave使用slaveof no one命令提升为master,其它slave执行slaveof命令指向这个新的master,从新的master处同步数据

5、主从复制模式的故障转移需要手动操作,要实现自动化处理,这就需要Sentinel哨兵,实现故障自动转移

 4-3-2 高可用Sentinel哨兵

        Sentinel哨兵是redis官方提供的高可用方案,可以用它来监控多个Redis服务实例的运行情况。Redis Sentinel 是一个运行在特殊模式下的Redis服务器。Redis Sentinel是在多个Sentinel进程环境下互相协作工作的。

Sentinel系统有三个主要任务:

  1. 监控:Sentinel不断的检查主服务和从服务器是否按照预期正常工作。
  2. 提醒:被监控的Redis出现问题时,Sentinel会通知管理员或其他应用程序。
  3. 自动故障转移:监控的主Redis不能正常工作,Sentinel会开始进行故障迁移操作。将一个从服务器升级新的主服务器。 让其他从服务器挂到新的主服务器。同时向客户端提供新的主服务器地址。

 

Sentinel配置

1)、​​​​​​​Sentinel配置文件

复制三份sentinel.conf文件:

Sentinel系统默认 port 是26379 。三个配置port分别设置为 26380  , 26382 , 26384 。三个文件分别命名:

  1. sentinel26380.conf
  2. sentinel26382.conf
  3. sentinel26384.conf

执行复制命令 cp sentinel.conf xxx.conf

2)、​​​​​​​三份sentinel配置文件修改:

 

1、修改 port 26380、 port  26382、 port  26384

2、修改 sentinel monitor mymaster 127.0.0.1 6380 2

格式:sentinel  monitor  <name>  <masterIP>  <masterPort>  <Quorum投票数>

Sentinel监控主(Master)Redis, Sentinel根据Master的配置自动发现Master的Slave,Sentinel默认端口号为26379 。

 sentinel26380.conf

1) 修改port

 

 2)修改监控的master地址

 

sentinel26382.conf 修改port 26382  , master的port 6382

sentinel26384.conf 修改port 26384  , master的port 6382

3)、​​​​​​​启动主从(Master/Slave)Redis

启动Reids

查看Master的配置信息

连接到6382端口

使用 info 命令查看 Master/Slave

 4)、​​​​​​​启动Sentinel

 

redis安装时make编译后就产生了redis-sentinel程序文件,可以在一个redis中运行多个sentinel进程。

启动一个运行在Sentinel模式下的Redis服务实例

./redis-sentinel  sentinel配置文件

执行以下三条命令,将创建三个监视主服务器的Sentinel实例:

./redis-sentinel  ../sentinel26380.conf

./redis-sentinel  ../sentinel26382.conf

./redis-sentinel  ../sentinel26384.conf

在XShell开启三个窗口分别执行

 

 5)、​​​​​​​主Redis不能工作

让Master的Redis停止服务, 执行shutdown

先执行 info replication 确认Master的Redis ,再执行shutdown

 查看当前Redis的进程情况

6)、​​​​​​​Sentinel的起作用

在Master执行shutdown后, 稍微等一会 Sentinel要进行投票计算,从可用的Slave选举新的Master。

查看Sentinel日志,三个Sentinel窗口的日志是一样的。

查看新的Master

 

查看原Slave的变化

 

7)、​​​​​​​新的Redis加入Sentinel系统,自动加入Master

重新启动6382

 查看6384的信息

 测试数据:在Master写入数据

在6382上读取数据,不能写入

 8)、监控

1)Sentinel会不断检查Master和Slave是否正常

2)如果Sentinel挂了,就无法监控,所以需要多个哨兵,组成Sentinel网络,一个健康的

   Sentinel至少有3个Sentinel应用。 彼此在独立的物理机器或虚拟机。

3)监控同一个Master的Sentinel会自动连接,组成一个分布式的Sentinel网络,互相通信并交换彼此关于被监控服务器的信息

4)当一个Sentinel认为被监控的服务器已经下线时,它会向网络中的其它Sentinel进行确认,判断该服务器是否真的已经下线

5)如果下线的服务器为主服务器,那么Sentinel网络将对下线主服务器进行自动故障转移,通过将下线主服务器的某个从服务器提升为新的主服务器,并让其从服务器转移到新的主服务器下,以此来让系统重新回到正常状态

6)下线的旧主服务器重新上线,Sentinel会让它成为从,挂到新的主服务器下

 9)、总结

        主从复制,解决了读请求的分担,从节点下线,会使得读请求能力有所下降,Master下线,写请求无法执行

        Sentinel会在Master下线后自动执行故障转移操作,提升一台Slave为Master,并让其它Slave成为新Master的Slave

4-4 安全设置 

 4-4-1、​​​​​​​设置密码

        访问Redis默认是没有密码的,这样不安全,任意用户都可以访问。可以启用使用密码才能访问Redis。 设置Redis的访问密码,修改redis.conf 中这行requirepass 密码。密码要比较复杂,不容易破解,而且需要定期修改。因为redis 速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K 次的密码尝试,需要指定非常非常强大的密码来防止暴力破解。

1)、​​​​​​​开启访问密码设置

修改redis.conf , 使用vim命令。 找到requirepass行去掉注释,requirepass空格后就是密码。

例1:设置访问密码是 123456 ,这是练习使用,生产环境要设置复杂密码

修改redis.conf,文件480行左右。原始内容:

修改后:

 

查看修改结果:

 2)、​​​​​​​访问有密码的Redis

如果Redis已经启动,关闭后,重新启动。

访问有密码的Redis两种方式:

①:在连接到客户端后,使用命令 auth 密码 , 命令执行成功后,可以正常使用Redis

②:在连接客户端时使用 -a 密码。例如 ./redis-cli -h ip -p port -a password

启动Redis

 使用 ① 访问

 输入命令 auth 密码

使用 ② 方式

 

 4-4-2、绑定Ip

        修改redis.conf文件,把# bind 127.0.0.1前面的注释#号去掉,然后把127.0.0.1改成允许访问你redis服务器的ip地址,表示只允许该ip进行访问。多个ip使用空格分隔。

例如 bind 192.168.1.100  192.168.2.10

4-4-3、​​​​​​​修改默认端口

        修改redis的端口,这一点很重要,使用默认的端口很危险,redis.conf中修改port 6379 将其修改为自己指定的端口(可随意),端口1024是保留给操作系统使用的。用户可以使用的范围是1024-65535

使用 -p 参数指定端口,例如:./redis-cli -p 新设置端口

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值