NOSQL之Redis配置与优化

一、关系数据库和非关系数据库

1、关系型数据库

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

2、非关系型数据库

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

NOSQL之Redis配置与优化_第1张图片

Redis基于内存运行并支持持久化
采用key-value(键值对)的存储形式
优点

  • 具有极高的数据读写速度
  • 支持丰富的数据类型
  • 支持数据的持久化
  • 原子性
  • 支持数据备份

关系型数据库和非关系型数据库区别:
(1)数据存储方式不同
关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。
与其相反,非关系型数据不适合存储在数据表的行和列中,而是大块组合在一起。非关系型数据通常存储在数据集中,就像文档、键值对或者图结构。你的数据及其特性是选择数据存储和提取方式的首要影响因素。
(2)扩展方式不同
SQL和NoSQL数据库最大的差别可能是在扩展方式上,要支持日益增长的需求当然要扩展。
要支持更多并发量,SQL数据库是纵向扩展,也就是说提高处理能力,使用速度更快速的计算机,这样处理相同的数据集就更快了。因为数据存储在关系表中,操作的性能瓶颈可能涉及很多个表,这都需要通过提高计算机性能来克服。虽然sQL数据库有很大扩展空间,但最终肯定会达到纵向扩展的上限。
而NoSQL数据库是横向扩展的。因为非关系型数据存储天然就是分布式的,NoSQL数据库的扩展可以通过给资源池添加更多普通的数据库服务器(节点)来分担负载。
(3)对事务性的支持不同
如果数据操作需要高事务性或者复杂数据查询需要控制执行计划,那么传统的SQL数据库从性能和稳定性方面考虑是你的最佳选择。SQL数据库支持对事务原子性细粒度控制,并且易于回滚事务。
虽然NoSQL数据库也可以使用事务操作,但稳定性方面没法和关系型数据库比较,所以它们真正闪亮的价值是在操作的扩展性和大数据量处理方面。

非关系型数据库产生背景
可用于应对web2.0纯动态网站类型的三高问题。
(1)High performance—对数据库高并发读写需求
(2)Huge Storage—对海量数据高效存储与访问需求
(3)High Scalability && High Availability—对数据库高可扩展性与高可用性需求

关系型数据库和非关系型数据库都有各自的特点与应用场景,两者的紧密结合将会给web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,非关系型数据库关注在存储上。例如,在读写分离的MySQL数据库环境中,可以把经常访问的数据存储在非关系型数据库中,提升访问速度。
Mysql 高热数据—》redis
web—》redis-》mysql
CPU—》内存/缓存—》磁盘

总结
非关系数据库
1、数据保存在缓存中,利于读取速度/查询数据
2、架构中位置灵活
3、分布式、扩展性高
关系数据库
1、安全性高(持久化)
2、事务处理能力强
3、任务控制能力强
4、可以做日志备份、恢复、容灾的能力更强一点。

mysql优化
①SQL语句优化
②索引优化
③漫查询日志
④硬件优化
⑤连接数优化(超时时间)
⑥分库分表
⑦线程池优化
⑧存储过程:存储过程在使用过程中是将常用或者复杂的工作预先使用SQL语句写好并用一个指定的名称存储起来,这个过程经编译和优化后存储在数据库服务器中。当需要使用该存储过程时,只需要调用它即可

在介绍优化时候,你完整的表述出过程:

  • 首先介绍优化的方向
  • 优化的对象是谁?在哪边操作
  • 可以达到什么效果

总结:
关系型数据库:
实例–>数据库–>表(table)–>记录行(row)、数据字段(column)-------》存储数据
非关系型数据库:
实例–>数据库–>集合(collection)–>键值对(key-value)
非关系型数据库不需要手动建数据库和集合(表)。

二、Redis安装部署

Redis简介
Redis(远程字典服务器)是一个开源的、使用c语言编写的NoSQL数据库。
Redis基于内存运行并支持持久化,采用key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环。

Redis服务器程序是单进程模型,也就是在一台服务器上可以同时启动多个Redis进程,Redis的实际处理速度则是完全依靠于主进程的执行效率。若在服务器上只运行一个Redis进程,当多个客户端同时访问时,服务器的处理能力是会有一定程度的下降:若在同一台服务器上开启多个Redis进程,Redis在提高并发处理能力的同时会给服务器的cPU造成很大压力。即:在实际生产环境中,需要根据实际的需求来决定开启多少个Redis进程。若对高并发要求更高一些,可能会考虑在同一台服务器上开启多个进程。若cPU资源比较紧张,采用单进程即可。

Redis具有以下几个优点:
(1)具有极高的数据读写速度:数据读取的速度最高可达到110000次/s,数据写入速度最高可达到81000次/s。
(2)支持丰富的数据类型:支持key-value、strings、Lists、Hashes、sets及 Sorted Sets等数据类型操作。
(3)支持数据的持久化:可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
(4)原子性:Redis所有操作都是原子性的。
(5)支持数据备份:即 master-salve模式的数据备份。

Redis作为基于内存运行的数据库,缓存是其最常应用的场景之一。除此之外,Redis常见应用场景还包括获取最新N个数据的操作、排行榜类应用、计数器应用、存储关系、实时分析系统、日志记录。

Redis为什么这么快?
1、Redis是一款纯内存结构,避免了磁盘I/O等耗时操作。
2、Redis命令处理的核心模块为单线程,减少了锁竟争,以及频繁创建线程和销毁线程的代价,减少了线程上下文切换的消耗。
3、采用了I/0多路复用机制,大大提升了并发效率。

注:在Redis6.0中新增加的多线程也只是针对处理网络请求过程采用了多线性,而数据的读写命令,仍然是单线程处理的。

Redis安装部署
systemctl stop firewalld
setenforce 0
yum install -y gcc gcc-c++ make

tar zxvf redis-5.0.7.tar.gz -C /opt/
cd /opt/redis-5.0.7/
make
make PREFIX=/usr/local/redis install
#由于Redis源码包中直接提供了Makefile文件,所以在解压完软件包后,不用先执行./configure进行配置,可直接执行 make与make install命令进行安装。
#执行软件包提供的 install_server.sh 脚本文件设置Redis服务所需要的相关配置文件
cd /opt/redis-5.0.7/utils
./install_server.sh
#一直回车
………
Please select the redis executable path [/usr/local/bin/redis-server] /usr/local/redis/bin/redis-server

#把redis的可执行程序文件放入路径环境变量的目录中便于系统识别
ln -s /usr/local/redis/bin/* /usr/local/bin/

#当 install_server.sh脚本运行完毕,Redis服务就已经启动,默认监听端口为 6379
netstat -natp | grep redis
#Redis服务控制

/etc/init.d/redis_6379 stop #停止
/etc/init.d/redis 6379 start #启动
/etc/init.d/redis_6379 restart #重启
/etc/init.d/redis_6379 status #状态

修改配置/etc/redis/6379.conf参数
vim /etc/redis/6379.conf

bind 127.0.0.1 192.168.80.10 #70行,添加监听的主机地址
port 6379 #93行,Redis默认的监听端口
daemonize yes #137行,启用守护进程
pidfile /var/run/redis_6379.pid #159行,指定PID文件
loglevel notice #167行,日志级别
logfile /var/log/redis_6379.log #172行,指定日志文件

/etc/init.d/redis_6379 restart

三、Redis数据库常用命令

Redis 命令工具
redis-server:用于启动 Redis 的工具
redis-benchmark:用于检测 Redis 在本机的运行效率
redis-check-aof:修复 AOF 持久化文件
redis-check-rdb:修复RDB持久化文件
redis-cli:Redis 命令行工具
-----redis-cli命令行工具-----
语法:redis-cli -h host -p port -a password
-h:指定远程主机
-p:指定Redis服务的端口号a…
-a:指定密码,未设置数据库密码可以省略-a选项
若不添加任何选项表示,则使用127.0.0.1:6379连接本机上的Redis数据库
redis-cli -h 192.168.80.10 -p 6379

-----redis-benchmark 测试工具-----
redis-benchmark是官方自带的Redis性能测试工具,可以有效的测试 Redis服务的性能。
基本的测试语法:redis-benchmark [选项] [选项值]。
-h:指定服务器主机名OeuctmnaLA L
-p:指定服务器端口。
-s:指定服务器socket
-c:指定并发连接数。
~n:指定请求数。
-d:以字节的形式指定SET/GET值的数据大小。
-k: l=keep alive 0=reconnect。
-r:SET/GET/INCR 使用随机 key,SADD 使用随机值。
-P:通过管道传输< numreq >请求。
-q:强制退出 redis。仅显示query/sec值。
–csv:以csv格式输出。
-l:生成循环,永久执行测试。
-t:仅运行以逗号分隔的测试命令列表。
-I:Idle模式。仅打开 N个idle连接并等待。

#向IP地址为192.168.80.10、端口为6379的Redis服务器发送100个并发连接与100000个请求测试性能
redis-benchmark -h 192.168.80.10 –p 6379 –c 100 -n 100000

#测试存取大小为100字节的数据包的性能
redis-benchmark -h 192.168.10.161 -p 6379 -q -d 100

#测试本机上Redis服务在进行 set与 lpush操作时的性能
redis-benchmark -t set,lpush -n 100000 -q

Redis数据库常用命令
set:存放数据,命令格式为 set key value
get:获取数据,命令格式为 get key

192.168.80.10:6379> set teacher zhangsan
OK
192.168.80.10:6379> get teacher
“zhangsan”

#keys命令可以取符合规则的键值列表,通常情况可以结合*、?等选项来使用。
192.168.80.10:6379> set k1 1
192.168.80.10:6379> set k2 2
192.168.80.10:6379> set k3 3
192.168.80.10:6379> set v1 4
192.168.80.10:6379> set v5 5
192.168.80.10:6379> set v22 5

192.168.80.10:6379> KEYS * #查看当前数据库中所有键
192.168.80.10:6379> KEYS v* #查看当前数据库中以v开头的数据
192.168.80.10:6379> KEYS v? #查看当前数据库中以v开头后面包含任意一位的数据
192.168.80.10:6379> KEYS v?? #查看当前数据库中以v开头v开头后面包含任意两位的数据

#exists命令可以判断键值是否存在。

192.168.80.10:6379> exists teacher #判断teacher键是否存在
(integer) 1 #1表示teacher键是存在
192.168.80.10:6379> exists tea
(integer) 0 #0表示tea键不存在

#del命令可以删除当前数据库的指定key。
192.168.80.10:6379> keys *
192.168.80.10:6379> del v2
(integer) 1
192.168.80.10:6379> get v2
(nil)

#type 命令可以获取 key对应的 value值类型。
192.168.80.10:6379> type k1
string

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

192.168.80.10:6379> keys v*

  1. “v1”
  2. “v22”
    192.168.80.10:6379> rename v22 v2
    OK
    192.168.80.10:6379> keys v*
  3. “v1”
  4. “v2”
    192.168.80.10:6379> get v2
    “5”
    192.168.80.10:6379> get v1
    “4”
    192.168.80.10:6379> rename v1 v2
    OK
    192.168.80.10:6379> get v1
    (nil)
    192.168.80.10:6379> get v2
    “4”
    192.168.80.10:6379> keys v*
  5. “v2”

#renamenx命令的作用是对已有key进行重命名,并检测新名是否存在,如果目标 key存在则不进行重命名。(不覆盖)
命令格式:renamenx源key目标key
192.168.80.10:6379> keys *
192.168.80.10:6379> get teacher
“zhangsan”
192.168.80.10:6379> get v2
“4”
192.168.80.10:6379> renamenx v2 teacher
(integer) 0
192.168.80.10:6379> keys *
192.168.80.10:6379> get teacher
“zhangsan”
192.168.80.10:6379> get v2
“4”

#dbsize命令的作用是查看当前数据库中 key的数目。
192.168.80.10:6379> dbsize
(integer) 8

#使用config set requirepass yourpassword命令设置密码
192.168.80.10:6379> config set requirepass 123456

#使用config get requirepass命令查看密码(一旦设置密码,必须先验证通过密码,否则所有操作不可用)
192.168.80.10:6379> config get requirepass
(error) NOAUTH Authentication required.
192.168.80.10:6379> auth 123456
OK
192.168.80.10:6379> config get requirepass

  1. “requirepass”
  2. “123456”

----Redis 多数据库常用命令----
Redis支持多数据库,Redis默认情况下包含16个数据库,数据库名称是用数字0-15来依次命名的。
多数据库相互独立,互不干扰。

#多数据库间切换
命令格式:select序号
使用redis-cli连接Redis数据库后,默认使用的是序号为0的数据库。

192.168.80.10:6379> select 10 #切换至序号为10的数据库
OK
192.168.80.10:6379[10]> select 15 #切换至序号为15的数据库
OK
192.168.80.10:6379[15]> select 2 #切换至序号为2的数据库
OK
192.168.80.10:6379[2]>

#多数据库间移动数据
格式:move 键值 序号

192.168.80.10:6379[2]> select 0
OK
192.168.80.10:6379> set k1 100
OK
192.168.80.10:6379> get k1
“100”
192.168.80.10:6379> select 1
OK
192.168.80.10:6379[1]> get k1
(nil)
192.168.80.10:6379[1]> select 0
OK
192.168.80.10:6379> get k1
“100”
192.168.80.10:6379> move k1 1
(integer) 1
192.168.80.10:6379> get k1
(nil)
192.168.80.10:6379> select 0
OK
192.168.80.10:6379> get k1
(nil)

#清除数据库内数据
FLUSHDB:清空当前数据库数据
192.168.80.10:6379[1]> dbsize
(integer) 1
192.168.80.10:6379[1]> keys *

  1. “k1”
    192.168.80.10:6379[1]> flushdb
    OK
    192.168.80.10:6379[1]> keys *
    (empty list or set)

FLUSHALL:清空所有数据库的数据,慎用!

Redis 高可用
在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.98、99.998、99.9998等等)
但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等。

在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和cluster集群,下面分别说明它们的作用,以及解决了什么样的问题。

  • 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
  • 主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化:写操作无法负载均衡:存储能力受到单机的限制。
  • 哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡:存储能力受到单机的限制。
  • cluster集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

四、Redis持久化

持久化的功能:Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

Redis提供两种方式进行持久化:

  • RDB持久化:原理是将Reids在内存中的数据库记录定时保存到磁盘上。
  • AOF持久化(append only file):原理是将Reids的操作日志以追加的方式写入文件,类似于MySQL的binlog。

由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。

1、RDB持久化

RDB持久化是指在指定的时间间隔内将内存中当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),用二进制压缩存储,保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。

1.触发条件
RDB持久化的触发分为手动触发和自动触发两种。

(1)手动触发
save命令和bgsave命令都可以生成RDB文件。
save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用。
(2)自动触发
在自动触发RDB持久化时,Redis也会选择bgsave而不是save来进行持久化。
save m n
自动触发最常见的情况是在配置文件中通过save m n,指定当m秒内发生n次变化时,会触发bgsave。
vim /etc/redis/6379.conf
–219行–以下三个save条件满足任意一个时,都会引起bgsave的调用
save 9001:当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave
save30010:当时间到300秒时,如果redis数据发生了至少10次变化,则执行bgsave
save6010000:当时间到60秒时,如果redis数据发生了至少10000次变化,则执行bgsave
–254行–指定RDB文件名
dbfilename dump.rdb
–264行–指定RDB文件和AOF文件所在目录
dir /var/lib/redis/6379
–242行–是否开启RDB文件压缩
rdbcompression yes

2.执行流程
(1)Redis父进程首先判断:当前是否在执行save,或bgsave/bgrewriteaof的子进程,如果在执行则bgsave命令直接返回。
bgsave/bgrewriteaof的子进程不能同时执行,主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。
(2)父进程执行fork操作创建子进程,这个过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
(3)父进程fork后,bgsave命令返回"Background saving started"信息并不再阻塞父进程,并可以响应其他命令
(4)子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换
(5)子进程发送信号给父进程表示完成,父进程更新统计信息

3.启动时加载
RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AO
F的优先级更高,因此当AOF开启时,Redis会优先载入
AOF文件来恢复数据;只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,
并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止。
Redis载入RDB文件时,会对RDB文件进行校验,如果文件损坏,则日志中会打印错误
,Redis启动失败。

2、AOF持久化

RDB持久化是将进程数据写入文件,而AOF持久化,则是将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录;当Redis重启时再次执行AOF文件中的命令来恢复数据。与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。
1.开启AOF
Redis服务器默认开启RDB,关闭AOF;要开启AOF,需要在配置文件中配置:
vim /etc/redis/6379.conf
–700行–修改,开启AOF
appendonly yes
–704行–指定AOF文件名称
appendfilename “appendonly.aof”
–796行–是否忽略最后一条可能存在问题的指令
aof-load-truncated yes
NOSQL之Redis配置与优化_第2张图片

RDB和AOF的优缺点

  • RDB持久化
    优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
    缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。
  • AOF持久化
    与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。
    对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),Io压力更大,甚至可能造成AOF追加阻塞
    AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。

小结:redis的持久化
1、RDB和AOF的基本理解
RDB:周期性的把内存中的数据保存在磁盘中
AOF:从redis的操作日志记录中执行的过程同步到磁盘中

2、RDB和AOF持久化过程
RDB:内存中—》写入磁盘中保存方式
结果数据—》写入磁盘中保存的数据对象
●内存–》写入磁盘后,会进行压缩,来减小*.rdb的磁盘占用空间量
●内存—》append追加到缓冲区—》调用cpu资源来写入到磁盘中

AOF:
●操作日志记录中的执行语句—》追加到缓冲—》调用CPU来写入磁盘
●内存—》缓冲—》磁盘,写入后,会周期性的进行重写,跳过一些“无效操作“来保存

3、RDB和AOF触发方式
RDB分为
手动触发
自动触发 save m n(假设save 60 900 60则表示60s内有900条语句执行,则触发RDB持久化)
特殊触发:当手动关闭redis时,会进行RDB方式持久化
/etc/init.d/redis_6379 stop |star
shutdown 关闭时
kill不会触发

AOF分为
●手动触发
●自动触发
1)always每条语句同步执行持久化
2)no不进行持久化
3)every second每秒进行一次Aor持久化(建议使用的,均衡型场景)
4、RDB和AOF优先级
●因为redis默认是将数据保存在内存中的,所以若redis重启,关闭时内存中的数据会丢失
前提:

五、Redis性能管理

查看Redis内存使用
127.0.0.1:6001> info memory

1、内存碎片率

操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存总量值 used_memory 计算得出。
内存值 used_memory_rss 表示该进程所占物理内存的大小,即为操作系统分配给 Redis 实例的内存大小。

除了用户定义的数据和内部开销以外,used_memory_rss 指标还包含了内存碎片的开销, 内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)。

举例来说:Redis 需要分配连续内存块来存储 1G 的数据集。如果物理内存上没有超过 1G 的连续内存块, 那操作系统就不得不使用多个不连续的小内存块来分配并存储这 1G 数据,该操作就会导致内存碎片的产生。

#跟踪内存碎片率对理解Redis实例的资源性能是非常重要的:
●内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换。
●内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save 命令,让 Redis 数据库执行保存操作并关闭 Redis 服务,再重启服务器。
●内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少 Redis 内存占用。

2、内存使用率

redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换。

#避免内存交换发生的方法:
●针对缓存数据大小选择安装 Redis 实例
●尽可能的使用Hash数据结构存储
●设置key的过期时间

3、内回收key

内存清理策略,保证合理分配redis有限的内存资源。

当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除。
配置文件中修改 maxmemory-policy 属性值:
vim /etc/redis/6379.conf
–598–
maxmemory-policy noenviction
●volatile-lru:使用LRU算法从已设置过期时间的数据集合中淘汰数据(移除最近最少使用的key,针对设置了TTL的key)
●volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰(移除最近过期的key)
●volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰(在设置了TTL的key里随机移除)
●allkeys-lru:使用LRU算法从所有数据集合中淘汰数据(移除最少使用的key,针对所有的key)
●allkeys-random:从数据集合中任意选择数据淘汰(随机移除key)
●noenviction:禁止淘汰数据(不删除直到写满时报错)

六、redis搭建部署

搭建Redis主从复制
NOSQL之Redis配置与优化_第3张图片

Master节点:192.168.80.10
Slave1节点:192.168.80.20
Slave2节点:192.168.80.30
systemctl stop firewalld
setenforce 0

安装 Redis
yum install -y gcc gcc-c++ make
tar zxvf redis-5.0.7.tar.gz -C /opt/
wget -p /opt http://download.redis.io/releases/redis-5.0.9.tar.gz
cd /opt/redis-5.0.7/
make
make PREFIX=/usr/local/redis install

cd /opt/redis-5.0.7/utils
./install_server.sh

Please select the redis executable path [/usr/local/bin/redis-server]
/usr/local/redis/bin/redis-server

ln -s /usr/local/redis/bin/* /usr/local/bin/

修改 Redis配置文件(Master节点操作)
vim /etc/redis/6379.conf

bind 0.0.0.0 #70行,修改监听地址为0.0.0.0
daemonize yes #137行,开启守护进程
logfile /var/log/redis_6379.log #172行,指定日志文件目录
dir /var/lib/redis/6379 #264行,指定工作目录
appendonly yes #700行,开启AOF持久化功能

/etc/init.d/redis_6379 restart

修改Redis配置文件(Slave节点操作)
vim /etc/redis/6379.conf

bind 0.0.0.0 #70行,修改监听地址为0.0.0.0
daemonize yes #137行,开启守护进程
logfile /var/log/redis_6379.log #172行,指定日志文件目录
dir /var/lib/redis/6379 #264行,指定工作目录
replicaof 192.168.80.10 6379 #288行,指定要同步的Master节点IP和端口
appendonly yes #700行,开启AOF持久化功能

/etc/init.d/redis_6379 restart

验证主从效果
在Master节点上看日志:
tail -f /var/log/redis_6379.log

NOSQL之Redis配置与优化_第4张图片

在Master节点上验证从节点:
redis-cli info replication

NOSQL之Redis配置与优化_第5张图片

在master上创建数据

NOSQL之Redis配置与优化_第6张图片

在slave上查看数据

NOSQL之Redis配置与优化_第7张图片

Redis哨兵模式
NOSQL之Redis配置与优化_第8张图片

主从切换技术的方法是:当服务器宕机后,需要手动一台从机切换为主机,这需要人工干预,不仅费时费力而且还会造成一段时间内服务不可用。为了解决主从复制的缺点,就有了哨兵机制。

哨兵的核心功能:在主从复制的基础上,哨兵引入了主节点的自动故障转移。

#哨兵模式原理:
哨兵(sentinel):是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的 Master并将所有slave连接到新的Master。所以整个运行哨兵的集群的数量不得少于3个节点。

#哨兵模式的作用:

  • 监控:哨兵会不断地检查主节点和从节点是否运作正常。

  • 自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其它从节点改为复制新的主节点。

  • 通知(提醒):哨兵可以将故障转移的结果发送给客户端。

哨兵结构由两部分组成,哨兵节点和数据节点:

  • 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据。
  • 数据节点:主节点和从节点都是数据节点。

#故障转移机制:
1.由哨兵节点定期监控发现主节点是否出现了故障
每个哨兵节点每隔1秒会向主节点、从节点及其它哨兵节点发送一次ping命令做一次心跳检测。如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的)。当超过半数哨兵节点认为该主节点主观下线了,这样就客观下线了。

2.当主节点出现故障,此时哨兵节点会通过Raft算法(选举算法)实现选举机制共同选举出一个哨兵节点leader,来负责处理主节点的故障转移和通知。所以整个运行哨兵的集群的数量不得少于3个节点。

3.由leader哨兵节点执行故障转移,过程如下:

  • 将某一个从节点升级为新的主节点,让其它从节点指向新的主节点;
  • 若原主节点恢复也变成从节点,并指向新的主节点;
  • 通知客户端主节点已经更换。

需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。

#主节点的选举:
1.过滤掉不健康的(已下线的),没有回复哨兵ping响应的从节点。
2.选择配置文件中从节点优先级配置最高的。(replica-priority,默认值为100)
3.选择复制偏移量最大,也就是复制最完整的从节点。

哨兵的启动依赖于主从模式,所以须把主从模式安装好的情况下再去做哨兵模式搭建Redis哨兵模式
Master节点:192.168.80.10
Slave1节点:192.168.80.20
Slave2节点:192.168.80.30
systemctl stop firewalld
setenforce 0
修改Redis哨兵模式的配置文件(所有节点操作)
vim /opt/redis-5.0.7/sentinel.conf
protected-mode no #17行,关闭保护模式
port 26379 #21行,Redis哨兵默认的监听端口
daemonize yes #26行,指定sentinel为后台启动
logfile “/var/log/sentinel.log” #36行,指定日志存放路径
dir “/var/lib/redis/6379” #65行,指定数据库存放路径
sentinel monitor mymaster 192.168.80.10 6379 2 #84行,修改指定该哨兵节点监控192.168.80.10:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移
sentinel down-after-milliseconds mymaster 30000 #113行,判定服务器down掉的时间周期,默认30000毫秒(30秒)
sentinel failover-timeout mymaster 180000 #146行,故障节点的最大超时时间为180000(180秒)

启动哨兵模式
先启master,再启slave
cd /opt/redis-5.0.7/
redis-sentinel sentinel.conf &

查看哨兵信息
redis-cli -p 26379 info Sentinel
#Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.80.10:6379,slaves=2,sentinels=3

故障模拟
#查看redis-server进程号:
ps -ef | grep redis
root 6318 1 0 19:35 ? 00:00:04 /usr/local/redis/bin/redis-server 0.0.0.0:6379
root 6532 1 0 19:52 ? 00:00:01 redis-sentinel *:26379 [sentinel]
root 6600 5754 0 19:58 pts/1 00:00:00 grep --color=auto redis

#杀死 Master节点上redis-server的进程号
kill -9 6318
kill -9 6532 #Master节点上redis-server的进程号

#验证结果
tail -f /var/log/sentinel.log
6531:X 22 Aug 2022 19:52:02.562 # Configuration loaded
6532:X 22 Aug 2022 19:52:02.579 * Increased maximum number of open files to 10032 (it was originally set to 1024).
6532:X 22 Aug 2022 19:52:02.579 * Running mode=sentinel, port=26379.
6532:X 22 Aug 2022 19:52:02.579 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
6532:X 22 Aug 2022 19:52:02.580 # Sentinel ID is e932e8e9b3d1cd2ff13a7cc8964f1e7a03b4e4b7
6532:X 22 Aug 2022 19:52:02.580 # +monitor master mymaster 192.168.80.10 6379 quorum 2
6532:X 22 Aug 2022 19:52:02.580 * +slave slave 192.168.80.20:6379 192.168.80.20 6379 @ mymaster 192.168.80.10 6379
6532:X 22 Aug 2022 19:52:02.581 * +slave slave 192.168.80.30:6379 192.168.80.30 6379 @ mymaster 192.168.80.10 6379
6532:X 22 Aug 2022 19:52:02.949 * +sentinel sentinel 99192e7b3834f2c68f3e8bd893f2cbb10395eb59 192.168.80.30 26379 @ mymaster 192.168.80.10 6379
6532:X 22 Aug 2022 19:52:03.438 * +sentinel sentinel 9cd950fe9bf867bf42df2b7e444b7036b5a9ad09 192.168.80.20 26379 @ mymaster 192.168.80.10 6379

查看哨兵信息
redis-cli -p 26379 info Sentinel

NOSQL之Redis配置与优化_第9张图片

Redis群集模式
NOSQL之Redis配置与优化_第10张图片

集群,即Redis Cluster,是Redis 3.0开始引入的分布式存储方案。
集群由多个节点(Node)组成,Redis的数据分布在这些节点中。集群中的节点分为主节点和从节点:只有主
节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。
#集群的作用,可以归纳为两点:
(1)数据分区:数据分区(或称数据分片)是集群最核心的功能。
集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个
主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
Redis单机内存大小受限问题,在介绍持久化和主从复制时都有提及;例如,如果单机内存太大,bgsave和
bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服
务,全量复制阶段主节点的复制缓冲区可能溢出。
(2)高可用:集群支持主从复制和主节点的自动故障转移(与哨兵类似);当任一节点发生故障时,集群
仍然可以对外提供服务。
#Redis集群的数据分片:
Redis集群引入了哈希槽的概念
Redis集群有16384个哈希槽(编号0-16383)
集群的每个节点负责一部分哈希槽
每个Key通过CRC16校验后对16384取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节
点,然后直接自动跳转到这个对应的节点上进行存取操作

#以3个节点组成的集群为例:
节点A包含0到5460号哈希槽
节点B包含5461到10922号哈希槽
节点c包含10923到16383号哈希槽
#Redis集群的主从复制模型
集群中具有A、B、C三个节点,如果节点B失败了,整个集群就会因缺少5461-10922这个范围的槽而不可以
用。
为每个节点添加一个从节点A1、B1、C1整个集群便有三个Master节点和三个slave节点组成,在节点B失败
后,集群选举B1位为的主节点继续服务。当B和B1都失败后,集群将不可用。

搭建Redis群集模式

redis的集群一般需要6个节点,3主3从。方便起见,这里所有节点在同一台服务器上模拟:以端口号进行区分:3个主节点端口号:6001/6002/6003,对应的从节点端口号:6004/6005/6006。
cd /etc/redis/
mkdir -p redis-cluster/redis600{1…6}
for i in {1…6}
do
cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600 i c p / o p t / r e d i s − 5.0.7 / s r c / r e d i s − c l i / o p t / r e d i s − 5.0.7 / s r c / r e d i s − s e r v e r / e t c / r e d i s / r e d i s − c l u s t e r / r e d i s 600 i cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis-cluster/redis600 icp/opt/redis5.0.7/src/rediscli/opt/redis5.0.7/src/redisserver/etc/redis/rediscluster/redis600i
done

#开启群集功能:
#其他5个文件夹的配置文件以此类推修改,注意6个端口都要不一样。
cd /etc/redis/redis-cluster/redis6001
vim redis.conf

#bind 127.0.0.1 #69行,注释掉bind项,默认监听所有网卡
protected-mode no #88行,修改,关闭保护模式
port 6001 #92行,修改,redis监听端口,
daemonize yes #136行,开启守护进程,以独立进程启动
cluster-enabled yes #832行,取消注释,开启群集功能
cluster-config-file nodes-6001.conf #840行,取消注释,群集名称文件设置
cluster-node-timeout 15000 #846行,取消注释群集超时时间设置
appendonly yes #700行,修改,开启AOF持久化

ps -ef | grep redis
root 1090 1 0 12:33 ? 00:00:27 /usr/local/redis/bin/redis-server 127.0.0.1:6379
root 6244 5736 0 17:27 pts/1 00:00:00 grep --color=auto redis

/etc/init.d/redis_6379 stop

ps -ef | grep redis
root 6259 5736 0 17:28 pts/1 00:00:00 grep --color=auto redis

#启动redis节点
分别进入那六个文件夹,执行命令:redis-server redis.conf,来启动redis节点
cd /etc/redis/redis-cluster/redis6001
redis-server redis.conf

for d in {1…6}
do
cd /etc/redis/redis-cluster/redis600$d
redis-server redis.conf
done

6709:C 23 Aug 2022 16:18:43.704 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6709:C 23 Aug 2022 16:18:43.704 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6709, just started
6709:C 23 Aug 2022 16:18:43.704 # Configuration loaded
6711:C 23 Aug 2022 16:18:43.730 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6711:C 23 Aug 2022 16:18:43.730 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6711, just started
6711:C 23 Aug 2022 16:18:43.730 # Configuration loaded
6716:C 23 Aug 2022 16:18:43.765 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6716:C 23 Aug 2022 16:18:43.765 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6716, just started
6716:C 23 Aug 2022 16:18:43.765 # Configuration loaded
6721:C 23 Aug 2022 16:18:43.785 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6721:C 23 Aug 2022 16:18:43.785 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6721, just started
6721:C 23 Aug 2022 16:18:43.785 # Configuration loaded
6726:C 23 Aug 2022 16:18:43.810 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6726:C 23 Aug 2022 16:18:43.810 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6726, just started
6726:C 23 Aug 2022 16:18:43.810 # Configuration loaded
6731:C 23 Aug 2022 16:18:43.834 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6731:C 23 Aug 2022 16:18:43.834 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=6731, just started
6731:C 23 Aug 2022 16:18:43.834 # Configuration loaded

ps -ef | grep redis

root 6345 1 0 15:57 ? 00:00:02 /usr/local/redis/bin/redis-server 0.0.0.0:6379
root 6710 1 0 16:18 ? 00:00:00 redis-server *:6001 [cluster]
root 6715 1 0 16:18 ? 00:00:00 redis-server *:6002 [cluster]
root 6720 1 0 16:18 ? 00:00:00 redis-server *:6003 [cluster]
root 6725 1 0 16:18 ? 00:00:00 redis-server *:6004 [cluster]
root 6730 1 0 16:18 ? 00:00:00 redis-server *:6005 [cluster]
root 6735 1 0 16:18 ? 00:00:00 redis-server *:6006 [cluster]
root 6740 5755 0 16:18 pts/1 00:00:00 grep --color=auto redis

#启动集群
redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1

#六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点。下面交互的时候需要输入Yes才可以创建。
replicas 1表示每个主节点有1个从节点。

#测试群集
redis-cli -p 6001 -c #加-c参数,节点之间就可以互相跳转
127.0.0.1:6001> cluster slots #查看节点的哈希槽编号范围

    1. (integer) 5461
    2. (integer) 10922
      1. “127.0.0.1”
      2. (integer) 6002
      3. “3c4cbe58e32996ef8a046189654b5689245e144a”
      1. “127.0.0.1”
      2. (integer) 6005
      3. “d67c2e33deaf46fd3b942a609ec5aec3b0589737”
    1. (integer) 0
    2. (integer) 5460
      1. “127.0.0.1”
      2. (integer) 6001
      3. “09a5e492d6b7c0aff77003a33903d4d2fb5ed3fd”
      1. “127.0.0.1”
      2. (integer) 6004
      3. “a23cb711a4c08f4388e7a050dfaf215d24ab6f42”
    1. (integer) 10923
    2. (integer) 16383
      1. “127.0.0.1”
      2. (integer) 6003
      3. “66e21f2081161295aea19061fa4c81bfdfd639a0”
      1. “127.0.0.1”
      2. (integer) 6006
      3. “3070acf34745b3b41b5d556bb742e561f21573cb”

127.0.0.1:6001> set name ux
OK

redis-cli -p 6004 -c
127.0.0.1:6004> keys *
#对应的slave节点也有这条数据,但是别的节点没有

  1. “name”

七、redis 数据类型

1、String数据类型

概述:String是 redis 最基本的类型,最大能存储 512MB 的数据,String类型是二进制安全的,即可以存储任何数据、比如数字、图片、序列化对象等

1、 SET/GET/APPEND/STRLEN:
PS:APPEND
APPEND key value追加键值,并返回追加后的长度(若键不存在,则相当于创建)

exists home
#判断该键是否存在,存在返回1,否则返回0

append home “cat”
#该键并不存在,因此append命令返回当前Value的长度

append home “dog”
#该键已经存在,因此返回追加后Value的长度

get home
#通过get命令获取该键,以判断append的结果

redis-cli
redis 127.0.0.1:6379> exists mykey #判断该键是否存在,存在返回1,否则返回0。
(integer) 0
redis 127.0.0.1:6379> append mykey “hello” #该键并不存在,因此append命令返回当前Value的长度。
(integer) 5
redis 127.0.0.1:6379> append mykey " world" #该键已经存在,因此返回追加后Value的总长度。
(integer) 11
redis 127.0.0.1:6379> get mykey #通过get命令获取该键,以判断append的结果。
“hello world”
redis 127.0.0.1:6379> set mykey “this is a test” #通过set命令为键设置新值,并覆盖原有值。
OK
redis 127.0.0.1:6379> get mykey
“this is a test”
redis 127.0.0.1:6379> strlen mykey #获取指定Key的字符长度。
(integer) 14

2、 INCR/DECR/INCRBY/DECRBY:
INCR key:key值递增加1(key值必须为整数)
DECR key:key值递减1(key值必须为整数)

redis 127.0.0.1:6379> set mykey 20 #设置Key的值为20
OK
redis 127.0.0.1:6379> incr mykey #该Key的值递增1
(integer) 21
redis 127.0.0.1:6379> decr mykey #该Key的值递减1
(integer) 20
redis 127.0.0.1:6379> del mykey #删除已有键。返回1说明删除成功
(integer) 1
redis 127.0.0.1:6379> decr mykey #对空值执行递减操作,其原值被设定为0,递减后的值为-1
(integer) -1
redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> incr mykey #对空值执行递增操作,其原值被设定为0,递增后的值为1
(integer) 1
redis 127 .0.0.1:6379> set mykey hello #将该键的Value设置为不能转换为整型的普通字符串。
OK
redis 127.0.0.1:6379> incr mykey
(error) ERR value is not an integer or out of range
redis 127.0.0.1:6379> set mykey 10
OK
redis 127.0.0.1:6379> decrby mykey 5 #减少指定的整数
(integer) 5
redis 127.0.0.1:6379> incrby mykey 10 #增加指定的整数
(integer) 15

3、 GETSET:
GETSET key value:获取key值并返回,同时给key设置新值

redis 127.0.0.1:6379> incr mycounter #将计数器的值原子性的递增1
(integer) 1
redis 127.0.0.1:6379> getset mycounter 0 #在获取计数器原有值的同时,并将其设置为新值,这两个操作原子性的方式同时完成。
redis 127.0.0.1:6379> get mycounter #查看设置后的结果。
“0”

4、SETEX:
setex key seconds value:设置指定key的过期时间为seconds
作用场景:

redis 127.0.0.1:6379> setex mykey 15 “hello” #设置指定Key的过期时间为15秒。
redis 127.0.0.1:6379> ttl mykey #通过tt1命令查看指定Key的剩余存活时间(秒数),0表示已经过期,-1表示永不过期。
(integer) 4
redis 127.0.0.1:6379> get mykey #在该键的存活期内我们仍然可以获取到它的Value。
“hello”
redis 127.0.0.1:6379> ttl mykey #该ttl命令的返回值显示,该Key已经过期。
(integer) -2
redis 127.0.0.1:6379> get mykey #获取已过期的Key将返回nil
(nil)

redis -1 往往代表的是一个上限,表示所有的意思
-2 表示的失效/过期

5、 SETNX:
SETNX key value:不存在键的话执行set操作,存在的话不执行

redis 127 .0.0.1:6379> del mykey #删除该键,以便于下面的测试验证。
(integer) 1
redis 127.0.0.1:6379> setnx mykey “hello” #该键并不存在,因此setnx命令执行成功。
(integer) 1
redis 127.0.0.1:6379> setnx mykey “world” #该键已经存在,因此本次设置没有产生任何效果。
(integer) 0
redis 127 .0.0.1:6379> get mykey #从结果可以看出,返回的值仍为第一次设置的值。
“hello”

6、 MSET/MGET/MSETNX:
MSET key value [key value …]:批量设置键-值对
MGET key [key …]:批量获取键值对
MSETNX key value [key value …]:批量设置键-值对,都不存在就执行并返回1;只要有一个存在就不执行并返回0

redis 127.0.0.1:6379> mset key1 “hello” key2 “world” #批量设置了key1和key2两个键。
redis 127.0.0.1:6379> mget key1 key2 #批量获取了key1和key2两个键的值。

  1. “hello”
  2. “world”
    redis 127.0.0.1:6379> msetnx key3 “zhang” key4 “san” #批量设置了key3和key4两个键,因为之前他们并不存在,所以msetnx命令执行成功并返回1。
    (integer) 1
    redis 127.0.0.1:6379> mget key3 key4
  3. “zhang”
  4. “san”
    redis 127.0.0.1:6379> msetnx key3 “hello” key5 “world” #批量设置了key3和key5两个键,但是key3已经存在,所以msetnx命令执行失败并返回0。
    (integer) 0
    redis 127.0.0.1:6379> mget key3 key5 #批量获取key3和key5,由于key5没有设置成功,所以返回nil
  5. “zhang”
  6. (nil)

get
mget

2、List 数据类型

概述:列表的元素类型为string,按照插入顺序排序,在列表的头部或尾部添加元素

1、 LPUSH/LPUSHX/ LRANGE:

LPUSH key value [value …]在头部(左侧)依次插入列表元素
LPUSHX key value:键必须存在才能执行,在头部插入元素值并返回并返回列表元素数量
LRANGE key start stop:取从位置索引start到位置索引stop的所有元素(所以以0开始)

redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> lpush mykey a b c d
#mykey键并不存在,该命令会创建该键及与其关联的List,之后在将参数中的values从左到右依次插入。
(integer) 4
redis 127.0.0.1:6379> lrange mykey 0 2 #取从位置0开始到位置2结束的3个元素。

  1. “d”
  2. “c”
  3. “b”
    redis 127.0.0.1:6379> lrange mykey 0 -1 #取链表中的全部元素,其中0表示第一个元素,-1表示最后一一个元素。
  4. “d”
  5. “c”
  6. “b”
  7. “a”
    redis 127.0.0.1:6379> lpushx mykey2 e #mykey2键此时并不存在,因此lpushx命令将不会进行任何操作,其返回值为0。
    (integer) 0
    redis 127.0.0.1:6379> lrange mykey2 0 -1 #可以看到mykey2没有关联任何List Value。
    (empty list or set)
    redis 127.0.0.1:6379> lpushx mykey e #mykey键此时已经存在,所以lpushx命令插入成功,并返回链表中当前元素的数量。
    (integer) 5
    redis 127.0.0.1:6379> lrange mykey 0 0 #获取该键的List Value的头部元素。
  8. “e”

2、LPOP/LLEN:
redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> lpush mykey a b c d
(integer) 4
redis 127.0.0.1:6379> lpop mykey #移除并返回mykey键的第一个元素,即从右往左第一个
“d”
redis 127.0.0.1:6379> lpop mykey
“c”
redis 127.0.0.1:6379> llen mykey #获取表中元素数量,在执行lpop命令两次后,链表头部的两个元素已经被弹出,此时链表中元素的数量是2
(integer) 2

3、LREM/LSET/LINDEX/LTRIM:
LREM key count value:从头部开始删除count个值为value的元素,并返回实际删除数量
LSET key index value:将位置索引为index的元素设置新值value
LINDEX key index:获取索引为index的元素
LTRIM key start stop:仅保留从位置索引start到索引stop的元素

redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> lpush mykey a b c d a c #为后面的示例准备测试数据。
(integer) 6
redis 127.0.0.1:6379> lrem mykey 2 a #从头部(left)向尾部(right)变量链表,删除2个值等于a的元素,返回值为实际删除的数量。
(integer) 2
redis127.0.0.1:6379>lrange mykey 0 -1 #看出删除后链表中的全部元素。

  1. “c”
  2. “d”
  3. “c”
  4. “b”
    redis 127.0.0.1:6379> lindex mykey 1 #获取索引值为1(头部的第二个元素)的元素值。
    “d”
    redis 127.0.0.1:6379> lset mykey 1 e #将索引值为1(头部的第二个元素)的元素值设置为新值e。
    OK
    redis 127.0.0.1:6379> lindex mykey 1 #查看是否设置成功。
    “e”
    redis 127.0.0.1:6379> lindex mykey 6 #索引值6超过了链表中元素的数量,该命令返回nil。
    (nil)
    redis 127.0.0.1:6379> lset mykey 6 hh #设置的索引值6超过了链表中元素的数量,设置失败,该命令返回错误信息。
    (error) ERR index out of range
    redis 127 .0.0.1:6379> ltrim mykey 0 2 #仅保留索引值0到2之间的3个元素,注意第0个和第2个元素均被保留。
    OK
    redis 127.0.0.1:6379> lrange mykey 0 -1 #查看ltrim后的结果。
  5. “c”
  6. “e”
  7. “c”

4、 LINSERT
LINSERT key BEFORE|AFTER pivot value:在元素pivot的前面(做左)或后面(右)插入新元素value

redis 127.0.0.1:6379> del mykey #删除该键便于后面的测试。
(integer) 1
redis 127.0.0.1:6379> lpush mykey a b c d e #为后面的示例准备测试数据。
(integer) 1
redis 127.0.0.1:6379> linsert mykey before a a1 #在a的前面插入新元素a1。
(integer) 6。
redis 127.0.0.1:6379> lrange mykey 0 -1 #查看是否插入成功,从结果看已经插入

  1. “e”
  2. “d”
  3. “c”
  4. “b”
  5. “a1”
  6. “a”
    redis 127.0.0.1:6379> linsert mykey after e e2 #在e的后面插入新元素e2,从返回结果看已经插入成功。
    (integer) 7
    redis 127.0.0.1:6379> lindex mykey 1 #再次查看是否插入成功。
    “e2”
    redis 127.0.0.1:6379> linsert mykey after k a #在不存在的元素之前或之后插入新元素,linsert 命令操作失败,并返回-1。
    (integer) -1
    redis 127.0.0.1:6379> linsert mykey1 after a a2 #为不存在的Key插入新元素,linsert命 令操作失败,返回0。.
    (integer) 0

5、RPUSH/ RPUSHX/RPOP/RPOPLPUSH:
RPUSH key value [value …]在列表的尾部依次插入value
RPUSHX key value:key必须存在才可执行,将value从尾部插入,并返回所有元素数量
RPOP key:在尾部弹出(移除)一个元素,并返回该元素
RPOPLPUSH source destination:在key1的尾部弹出一个元素并返回,将它插入key2的头部

redis 127.0.0.1:6379> del mykey #删除该键,以便于后而的测试。
(integer) 1
redis 127.0.0.1:6379> rpush mykey a b c d #从链表的尾部插入参数中给出的values,插入顺序是从右到左依次插入。
(integer) 4
redis 127.0.0.1:6379> lrange mykey 0 -1 #通过lrange命令可以获悉rpush在插入多值时的插入顺序。

redis 127.0.0.1:6379> rpushx mykey e #该键已经存在并且包含4个元素,rpushx命令将执行成功,并将元素e插入到链表的尾部。
(integer) 5
redis 127.0.0.1:6379> lindex mykey 4 #通过lindex命令可以看出之前的rpushx命令确实执行成功,因为索引值为4的元素已经是新元素了。
“e”
redis 127.0.0.1:6379> rpushx mykey2 e #由于mykey2键并不存在,因此rpushx命令不会插入数据,其返回值为0。
(integer) 0
redis 127.0.0.1:6379> lrange mykey 0 -1 #在执行rpoplpush命令前,先看一下 mykey中链表的元素有哪些,注意他们的位置关系。

  1. “a”
  2. “b”
  3. “c”
  4. “d”
  5. “e”
  1. 0.0.1:6379> RPOP mykey #移除并返回mykey键的第一个元素,从右取
    “e”
    127.0.0.1:6379> LRANGE mykey 0 -1
  1. “a”
  2. “b”
  3. “c”
  4. “d”
    redis 127.0.0.1:6379> rpoplpush mykey mykey2 #将mykey的尾部元素e弹出,同时再插入到mykey2的头部(原子性的完成这两步操作)。
    “d”
    redis 127.0.0.1:6379> lrange mykey 0 -1 #通过lrange命令查看mykey在弹出尾部元素后的结果。
  5. “a”
  6. “b”
  7. “c”
    redis 127.0.0.1:6379> lrange mykey2 0 -1 #通过lrange命令查看mykey2在插入元素后的结果。
  8. “d”
    redis 127.0.0.1:6379> rpoplpush mykey mykey #将source和destination设为同一键,将mykey中的尾部元素移到其头部。
    “c”
    redis 127.0.0.1:6379> lrange mykey 0 -1 #查看移动结果。
  9. “c”
  10. “a”
  11. “b”

lrange

3、Hash数据类型 (散列类型)

概述:hash用于存储对象。可以采用这样的命名方式(hash格式):对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。
如:存储ID为2的汽车对象。
如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储4294967295个键值对。

1、 HSET/HGET/HDEL/HEXISTS/HLEN/HSETNX:
redis 127.0.0.1:6379> hset myhash field1 “zhang” #给键值为myhash的键设置字段为field1,值为zhang。
(integer) 1
redis 127.0.0.1:6379> hget myhash field1 #获取键值为myhash,字段为field1的值。
“zhang”
redis 127.0.0.1:6379> hget myhash field2 #myhash键中不存在field2字段,因此返回nil.
(nil)
redis 127.0.0.1:6379> hset myhash field2 “san” #给myhash添加一个新的字段field2,其值为san。
(integer) 1
redis 127.0.0.1:6379> hlen myhash #hlen命令获取myhash键的字段数量。
(integer) 2
redis 127.0.0.1:6379> hexists myhash field1 #判断myhash键中是否存在字段名为field1的字段,由于存在,返回值为1。
(integer) 1
redis 127.0.0.1:6379> hdel myhash field1 #删除myhash键中字段名为field1的字段,删除成功返回1。
(integer) 1
redis 127 .0.0.1:6379> hdel myhash field1 #再次删除myhash键中字段名为field1的字段,由于上一条命令已经将其删除,因为没有删除,返回0
(integer) 0
redis 127 .0.0.1:6379> hexists myhash field1 #判断myhash键中是否存在field1字段,由于上一条命令已经将其删除,因为返回0。
(integer) 0
redis 127.0.0.1:6379> hsetnx myhash field1 zhang #通过hsetnx命令给myhash添加新字段field1,其值为zhang,因为该字段已经被删除,所以该命令添加成功并返回1
(integer) 1
redis 127.0.0.1:6379> hsetnx myhash field1 zhang #由于myhash的field1字段已经通过上一条命令添加成功,因为本条命令不做任何操作后返回0。
(integer) 0

2、HINCRBY:
redis 127.0.0.1:6379> del myhash #删除该键,便于后面示例的测试。
(integer) 1
redis 127.0.0.1:6379> hset myhash field 5 #准备测试数据,该myhash的field字段设定值5。
(integer) 1
redis 127.0.0.1:6379> hincrby myhash field 1 #hincrby命令给myhash的field字段的值加1,返回加后的结果。
(integer) 6
redis 127.0.0.1:6379> hincrby myhash field -1 #hincrby命令给myhash的field字段的值加-1,返回加后的结果。
(integer) 5
redis 127.0.0.1:6379> hincrby myhash field -10 #hincrby命令给myhash的field字段的值加-10,返回加后的结果。
(integer) -5

3、 HGETALL/HKEYS/HVALS/HMGET /HMSET:
redis 127.0.0.1:6379> del myhash #删除该键,便于后面示例测试。
(integer) 1
redis 127.0.0.1:6379> hmset myhash field1 “hello” field2 “world”
#hmset命令为该键myhash,一次性设置多个字段,分别是field1=“hello”,field2=“world”。
OK
redis 127.0.0.1:6379> hmget myhash field1 field2 field3
#hmget命令获取myhash键的多个字段,其中field3并不存在,因为在返回结果中与该字段对应的值为nil。

  1. “hello”
  2. “world”
  3. (nil)
    redis 127.0.0.1:6379> hgetall myhash #hgetall命令返回myhash键的所有字段及其值,从结果中可以看出,他们是逐对列出的。
  4. “field1”
  5. “hello”
  6. “field2”
  7. “world”
    redis 127.0.0.1:6379> hkeys myhash #hkeys命令仅获取myhash键中所有字段的名字。
  8. “field1”
  9. “field2”
    redis 127.0.0.1:6379> hvals myhash #hvals命令仅获取myhash键中所有字段的值。
  10. “hello”
  11. “world”

4、set数据类型(无序集合)

概述:无序集合,元素类型为string类型,元素具有唯一性, 不允许存在重复的成员。多个集合类型之间可以进行并集、交集和差集运算

应用范围:
1、可以使用Redis的Set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一IP地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的IP存入Redis中,Set数据类型会自动保证IP地址的唯一性。
2、充分利用Set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某–电子设备的客户ID被存储在一个指定的Set中,而购买另外一种电子产品的客户ID被存储在另外一个Set中,如果此时我们想获取有哪些客户同时购买了这两种商品时,Set的intersections 命令就可以充分发挥它的方便和效率的优势了。

1、SADD/ SMEMBERS/ SCARD/ SISMEMBER:
sdd/smembers/scard/sismembers
redis 127.0.0.1:6379> sadd myset a b c #插入测试数据,由于该键myset之前并不存在,因此参数中的三个成员都被正常插入。
(integer) 3
redis 127.0.0.1:6379> sadd myset a d e #由于参数中的a在myset中已经存在,因此本次操作仅仅插入了d和e两个新成员。
(integer) 2
redis 127.0.0.1:6379> sismember myset a #判断a是否已经存在,返回值为1表示存在。
(integer) 1
redis 127.0.0.1:6379> sismember myset f #判断f是否已经存在,返回值为0表示不存在。
(integer) 0
redis 127.0.0.1:6379> smembers myset #通过smembers命令查看插入的结果,从结果可以看出,输出的顺序和插入顺序无关。

  1. “c”
  2. “b”
  3. “a”
  4. “d”
  5. “e”
    redis 127.0.0.1:6379> scard myset #获取Set集合中元素的数量
    (integer) 5

2、SPOP/SREM/ SRANDMEMBER/ SMOVE
redis 127.0.0.1:6379> del myset #删除该键,便于后而的测试。
(integer) 1
redis 127.0.0.1:6379> sadd myset a b c d #为后面的示例准备测试数据。
(integer) 4
redis 127.0.0.1:6379> smembers myset #查看Set中成员的位置。

  1. “d”
  2. “a”
  3. “b”
  4. “c”
    redis 127.0.0.1: 6379> srandmember myset #从结果可以看出,该命令确实是随机的返回了某一成员
    “c”
    redis 127.0.0.1:6379> spop myset #随机的移除并返回Set中的某一成员。
    “d”
    redis 127.0.0.1:6379> smembers myset #查看移出后set的成员信息。
  5. “a”
  6. “b”
  7. “c”
    redis 127.0.0.1:6379> srem myset a d f #从myseet中移出a、d和f三个成员,其中f并不存在,因此只有a和d两个成员被移出,返回为2。
    (integer) 1
    redis 127.0.0.1:6379> smembers myset #查看移出后的输出结果。
  8. “b”
  9. “c”
    redis 127.0.0.1:6379> sadd myset a b #为后面的smove命令准备数据。
    (integer) 1
    redis 127.0.0.1:6379> sadd myset2 c d
    (integer) 2
    redis 127.0.0.1:6379> smove myset myset2 a #将a从myset移到myset2,从结果可以看出移动成功。
    (integer) 1
    redis 127.0.0.1:6379> smove myset myset2 a #再次将a从myset移到myset2,由于此时a已经不是myset的成员了,因此移动失败并返回0。
    (integer) 0
    redis 127.0.0.1:6379> smembers myset #分别查看myset和myset2的成员,确认移动是否真的成功。
  10. “b”
  11. “c”
    redis 127.0.0.1:6379> smembers myset2
  12. “a”
  13. “d”
  14. “c”

5、Sorted Set数据类型 (zset、有序集合)

概述:
a、有序集合,元素类型为Sting,元素具有唯一性, 不能重复。
b、每个元素都会关联–个double类型的分数score(表示权重),可以通过权重的大小排序,元素的score可以相同。

应用范围:

可以用于一个大型在线游戏的积分排行榜。每当玩家的分数发生变化时,可以执行ZADD命 令更新玩家的分数,此后再通过ZRANGE命令获取积分TOP10的用户信息。当然我们也可以利用ZRANK命令通过username来获取玩家的排行信息。最后我们将组合使用ZRANGE和ZRANK命令快速的获取和某个玩家积分相近的其他用户的信息。
Sorted-Set类型还可用于构建索引数据。
1、ZADD/ ZCARD/ ZCOUNT / ZREM/ ZINCRBY/ ZSCORE/ ZRANGE/ ZRANK:

redis 127.0.0.1:6379> zadd myzset 1 “one” #添加一个分数为1的成员。
(integer) 1
redis 127.0.0.1:6379> zadd myzset 2 “two” 3 “three” #添加两个分数分别是2和3的两个成员。
(integer) 2
redis 127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES #0表示第一个成员,-1表示最后一个成员。WITHSCORES选 项表示返回的结果中包含每个成员及其分数,否则只返回成员。

  1. “one”
  2. “1”
  3. “two”
  4. “2”
  5. “three”
  6. “3”
    redis 127.0.0.1:6379> zrank myzset one #获取成员one在Sorted-Set中的位置索引值。0表示第一个位置。
    (integer) 0
    redis 127.0.0.1:6379> zrank myzset four #成员four并不存在,因此返回nil。
    (nil)
    redis 127.0.0.1:6379> zcard myzset #获取myzset键中成员的数量。
    (integer) 3
    redis 127.0.0.1:6379> zcount myzset 1 2 #zcount key min max,分数满足表达式1 <= score <= 2的成员的数量。
    (integer) 2
    redis 127.0.0.1:6379> zrem myzset one two #删除成员one和two,返回实际删除成员的数量
    (integer) 2
    redis 127.0.0.1:6379> zcard myzset #查看是否删除成功。
    (integer) 1
    redis 127.0.0.1:6379> zscore myzset three #获取成员three的分数。返回值是字符串形式。
    “3”
    redis 127.0.0.1:6379> zscore myzset two #由于成员two已经被删除,所以该命令返回nil。
    (nil)
    redis 127 .0.0.1:6379> zincrby myzset 2 one #成员one不存在,zincrby命令将添加该成员并假设其初始分数为0,将成员one的分数增加2,并返回该成员更新后的分数。
    “2”
    redis 127.0.0.1:6379> zincrby myzset -1 one #将成员one的分数增加-1,并返回该成员更新后的分数。
    “1”
    redis 127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES #查看在更新了成员的分数后是否正确。
  7. “one”
  8. "1’
  9. “three”
  10. “3”

2、Z RANGE BY SCORE/ Z REM RANGE BY RANK/ Z REM RANGE BY SCORE
redis 127.0.0.1:6379> del myzset
(integer) 1
redis 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
redis 127.0.0.1:6379> zrangebyscore myzset 1 2 #zrangebyscore key min max,获取分数满足表达式1 <= score <= 2的成员。

  1. “one”
  2. “two”
    redis 127.0.0.1:6379> zrangebyscore myzset (1 2 #获取分数满足表达式1 < score <= 2的成员。
  3. “two”
    redis 127.0.0.1:6379> zrangebyscore myzset -inf +inf limit 2 3
    #-inf表示第一个成员(位置索引值最低的,即0),+inf表示最后一个成员(位置索引值最高的),limit后面的参数用于限制返回成员的值,2表示从位置索引等于2的成员开始,取后而3个成员。
  4. “three”
  5. “four”
    redis 127.0.0.1:6379> zrangebyscore myzset 0 4 limit 2 3
  6. “three”
  7. “four”
    redis 127.0.0.1:6379> zremrange byscore myzset 1 2 #删除分数满足表达式1 <= score <= 2的成员,并返回实际删除的数量。
    (integer) 2
    redis 127.0.0.1:6379> zrange myzset 0 -1 #查看一下.上面的删除是否成功。
  8. “three”
  9. ”four"
    redis 127.0.0.1:6379> zremrangebyrank myzset 0 1 #删除位置索引满足表达式0 <= rank <= 1的成员。
    (integer) 2
    redis 127 .0.0.1:6379> zcard myzset #查看上–条命令是否删除成功。
    (integer) 0

3、ZREVRANGE/ ZREVRANGEBYSCORE/ ZREVRANK:
redis 127.0.0.1:6379> del myzset #为后面的示例准备测试数据。
(integer) 1
redis 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
redis 127.0.0.1:6379> zrevrangemyzset 0 -1 WITHSCORES #以位置索引从高到低的方式获取并返回此区间内的成员。

  1. “four”
  2. “4”
  3. “three”
  4. “3”
  5. “two”
  6. “2”
  7. “one”
  8. “1”
    redis 127.0.0.1:6379> zrevrange myzset 1 3 #由于是从高到低的排序,所以位置等于0的是four,1是three,并以此类推。
  9. “three”
  10. “two”
  11. “one”
    redis 127.0.0.1:6379> zrevrank myzset one #由于是从高到低的排序,所以one的位置/索引下标是3。
    (integer) 3
    redis 127.0.0.1:6379> zrevrank myzset four #由于是从高到低的排序,所以four的位置是0。
    (integer) 0
    redis 127.0.0.1:6379> z rev range by score myzset 3 0 # zrevrangebyscore key max min,获取分数满足表达式3 >= score >= 0的成员,并以从高到底的顺序输出。
  12. “three”
  13. “two”
  14. “one”
    redis 127.0.0.1:6379> zrevrangebyscore myzset 4 0 limit 1 2 #zrevrangebyscore命令支持limit选项,其含义等同于zrangebyscore中的该选项,只是在计算位置时按照相反的顺序计算和获取。
  15. “three”
  16. “two”
    192.168.80.10:6379> zrevrangebyscore myzset +inf -inf limit 1 3
  17. “three”
  18. “two”
  19. “one”

redis作用和应用场景

作用:主要用redis实现缓存数据的存储,可以设置过期时间,对于一些高频读写、临时存储的数据特别适用

应用场景
缓存 分布式会话 分布式锁 消息系统 查询表
2、使用redis的好处
速度快
支持事务(原子性)
支持丰富数据类型(1ist hash set string Sorted Set)
丰富特性

3、redis主从复制模式下,主挂了怎么办?redis提供哨兵模式(高可用)
nk <= 1的成员。
(integer) 2
redis 127 .0.0.1:6379> zcard myzset #查看上–条命令是否删除成功。
(integer) 0

3、ZREVRANGE/ ZREVRANGEBYSCORE/ ZREVRANK:
redis 127.0.0.1:6379> del myzset #为后面的示例准备测试数据。
(integer) 1
redis 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
redis 127.0.0.1:6379> zrevrangemyzset 0 -1 WITHSCORES #以位置索引从高到低的方式获取并返回此区间内的成员。

  1. “four”
  2. “4”
  3. “three”
  4. “3”
  5. “two”
  6. “2”
  7. “one”
  8. “1”
    redis 127.0.0.1:6379> zrevrange myzset 1 3 #由于是从高到低的排序,所以位置等于0的是four,1是three,并以此类推。
  9. “three”
  10. “two”
  11. “one”
    redis 127.0.0.1:6379> zrevrank myzset one #由于是从高到低的排序,所以one的位置/索引下标是3。
    (integer) 3
    redis 127.0.0.1:6379> zrevrank myzset four #由于是从高到低的排序,所以four的位置是0。
    (integer) 0
    redis 127.0.0.1:6379> z rev range by score myzset 3 0 # zrevrangebyscore key max min,获取分数满足表达式3 >= score >= 0的成员,并以从高到底的顺序输出。
  12. “three”
  13. “two”
  14. “one”
    redis 127.0.0.1:6379> zrevrangebyscore myzset 4 0 limit 1 2 #zrevrangebyscore命令支持limit选项,其含义等同于zrangebyscore中的该选项,只是在计算位置时按照相反的顺序计算和获取。
  15. “three”
  16. “two”
    192.168.80.10:6379> zrevrangebyscore myzset +inf -inf limit 1 3
  17. “three”
  18. “two”
  19. “one”

redis作用和应用场景

作用:主要用redis实现缓存数据的存储,可以设置过期时间,对于一些高频读写、临时存储的数据特别适用

应用场景
缓存 分布式会话 分布式锁 消息系统 查询表
2、使用redis的好处
速度快
支持事务(原子性)
支持丰富数据类型(1ist hash set string Sorted Set)
丰富特性

3、redis主从复制模式下,主挂了怎么办?redis提供哨兵模式(高可用)
就是通过哨兵节点进行自主监控主从节点以及其他哨兵节点,发现主节点故障时自主进行故障转移

你可能感兴趣的:(redis,nosql,数据库)