Redis简介
Redis是一个用C语言编写的、开源的、基于内存运行并支持持久化的、高性能的NoSQL数据库,也是当前热门的NoSQL数据库之一。
Redis中的数据以K-V模型存储数据,大部分时间都是存储内存中的,适合存储频繁访问、数据量比较小的数据,常用作缓存数据库。
关系型数据库:oracle、mysql、DB2、sqlserver、….
- 数据模型:表
非关系型数据库(NoSql): 彻底改变底层存储机制。不再采用关系数据模型,而是采用聚合数据结构存储数据: redis、mongoDB、HBase、….
数据模型: 聚合模型—把一组相关联的数据作为一个整体进行存储和管理。
BSON:数据保存到键值对中、数据和数据之间用逗号隔开,{}表示对象,[]表示数组。
eg:
{ "student":{ "id":1001, "name":"zhangsan", "addresses":{"province":"beijing","city":"daxingqu","street":"liangshuihe"}, "courses":[ { "id":01, "name":"java" }, { "id":02, "name":"mybatis" }, { "id":03, "name":"spring" } ] } }
K-V键值对、列簇、图表模型等。Redis采用的是K-V模型存储数据。
redis的特点
支持数据持久化:Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
支持多种数据结构:Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
支持数据备份:Redis支持数据的备份,即master-slave模式的数据备份
Redis中的操作命令
redis服务的启动与关闭
- 启动redis服务
- 前台启动:在任何目录下执行 redis-server
- 后台启动:在任何目录下执行 redis-server &
- 启动redis服务时,指定配置文件:redis-server reids.conf &
- 关闭redis服务
- 通过kill命令
- ps-ef|grep redis 查看pid
- kill -9 pid
- 通过redis-cli命令关闭
- redis-cli shutdown
- 通过kill命令
- 启动redis客户端(用来连接redis服务,向redis服务端发送命令,并且显示redis服务处理结果。)
- redis-cli:启动redis自带的客户端,默认连接127.0.0.1(本机)的6379端口上的redis服务)
- redis-cli -p 端口号:连接127.0.0.1(本机)的指定端口上的redis服务
- redis-cli -h ip地址 -p 端口:连接指定ip主机上的指定端口的redis服务
- 退出客户端
- 在客户端执行命令:exit或者quit
redis的基本知识
- 测试redis服务的性能:redis-benchmark
- 查看redis服务是否正常运行:ping (如果正常返回-pong)
- 查看redis服务器的统计信息
- info: 查看redis服务的所有统计信息
- info [信息段]: 查看redis服务器的指定的统计信息
- eg:info replication: 查看本端口的从属关系
- redis的数据库实例
- 作用类似于mysql的数据库实例,redis中的数据库实例只能由redis服务来创建和维护,开发人员不能修改和自行创建数据库实例
- 默认情况下,redis会自动创建16个数据库实例,并且给这些数据库实例进行编号,从0开始,一直到15,使用时通过编号来使用数据库
- 可以通过配置文件,指定redis自动创建的数据库个数
- redis的每一个数据库实例本身占用的存储空间是很少的,所以也不造成存储空间的太多浪费
- 默认情况下,redis客户端连接的是编号是0的数据库实例;可以使用select index切换数据库实例
- 对数据库实例的常用操作命令
- dbsize:查看当前数据库实例中所有key的数量
- keys *:查看当前数据库实例中所有的key
- flushdb:清空当前数据库实例
- flushall:清空所有的数据库实例
- config get *:查看redis中所有的配置信息
- config get parameter: 查看redis中的指定的配置信息
Redis的五种数据结构
程序处理完的数据要存储到redis中,不同特点的数据要存储在Redis中不同类型的数据结构中。
- 字符串string——单key:单value
- eg:username:zhangsan
- 列表list——单key:多有序value
- 多个value之间有顺序,最左侧是表头,最右侧是表尾
- 每一个元素都有下标,表头元素的下标是0,依次往后排序,最后一个元素下标是列表长度-1
- 每一个元素的下标又可以用负数表示,负下标表示从表尾计算,最后一个元素下标用-1表示
- 元素在列表中的顺序或者下标由放入的顺序来决定
- 通过key和下标来操作数据
- eg:contacts:13900009999,xxx,xxxx
- 集合set——单key:多无序value
- 一个key对应多个vlaue, value之间没有顺序,并且不能重复
- 通过业务数据直接操作集合
- eg:city:bj sh cq tj
- hash——单key: 对象(属性:值)
- eg:student:id:1001,name:zhangsan,age:20
- zset——单key:多有序vlaue
- 有序集合, 本质上是集合,所有元素不能重复
- 每一个元素都关联一个分数,redis会根据分数对元素进行自动排序,分数可以重复
- 既然有序集合中每一个元素都有顺序,那么也都有下标
- 有序集合中元素的排序规则和列表中元素的排序规则不一样
- eg:city:1000 tj,1200 cq,1500 sh,2000 bj
Redis中对数据的操作命令
redis中有关key的操作命令
- 查看数据库中的key:keys pattern
- *:匹配0个或者多个字符
- keys *:查看数据库中所有的key
- keys k*:查看数据库中所有以k开头的key
- keys h*o:查看数据库中所有以h开头、以o结尾的key
- ?: 匹配1个字符
- keys h?o: 查看数据库中所有以h开头、以o结尾的、并且中间只有一个字符的key
- []:匹配[]里边的1个字符
- keys h[abc]llo:查看数据库中所有以h开头以llo结尾,并且h后边只能取abc中的一个字符的key
- *:匹配0个或者多个字符
- 判断key在数据库中是否存在:exists key
- 如果存在,则返回1;如果不存在,则返回0
- exists key [key key ….] 返回值是存在的key的数量
- 移动指定key到指定的数据库实例:move key index
- 查看指定key的剩余生存时间:ttl key
- 如果key没有设置生存时间,返回-1
- 如果key不存在,返回-2
- 设置key的最大生存时间:expire key seconds
- expire k2 20
- 查看指定key的数据类型:type key
- type k1
- 重命名key: rename key newkey
- rename hello k2
- 删除指定的key:del key [key key …..]
- 返回值是实际删除的key的数量
redis中有关string类型数据的操作命令
- 将string类型的数据设置到redis中:set 键 值
- 如果key已经存在,则后来的value会把以前的value覆盖掉
- set zsname zhangsan
- 如果key已经存在,则后来的value会把以前的value覆盖掉
- 从redis中获取string类型的数据:get 键
- 追加字符串:append key value
- 返回追加之后的字符串长度
- 如果key不存在,则新创建一个key,并且把value值设置为value。
- set phone 1389999 append phone 8888 get “phone”——“13899998888”
- 获取字符串数据的长度:strlen key
- 将字符串数值进行加1运算:incr key
- 返回加1运算之后的数据
- 如果key不存在,首先设置一个key,值初始化为0,然后进行incr运算。
- 要求key所表示value必须是数值,否则,报错
- 将字符串数值进行减1运算:decr key
- 返回减1运算之后的数据
- 如果key不存在,首先设置一个key,值初始化为0,然后进行decr运算。
- 要求key所表示value必须是数值,否则,报错
- 将字符串数值进行加offset运算:incrby key offset
- 返回加offset运算之后的数据
- 如果key不存在,首先设置一个key,值初始化为0,然后进行incrby运算。
- 要求key所表示value必须是数值,否则,报错
- 将字符串数值进行减offset运算:decrby key offset
- 返回减offset运算之后的数据
- 如果key不存在,首先设置一个key,值初始化为0,然后进行decrby运算。
- 要求key所表示value必须是数值,否则,报错
- 闭区间获取字符串key中从startIndex到endIndex的字符组成的子字符串:getrange key startIndex endIndex
- 下标自左至右,从0开始,依次往后,最后一个字符的下标是字符串长度-1;
- 用value覆盖从下标为startIndex开始的字符串,能覆盖几个字符就覆盖几个字符:setrange key startIndex value
- 设置字符串数据的同时,设置它最大生命周期:setex key seconds value
- 设置string类型的数据value到redis数据库中,当key不存在时设置成功,否则,则放弃设置:setnx key value
- 批量将string类型的数据设置到redis中:mset 键1 值1 键2 值2 …..
- 批量从redis中获取string类型的数据:mget 键1 键2 键3…..
- 批量设置string类型的数据value到redis数据库中,当所有key都不存在时设置成功,否则(只要有一个已经存在),则全部放弃设置:msetnx 键1 值1 键2 值2 …..
redis中有关list类型数据的操作命令
- 将一个或者多个值依次插入到列表的表头(左侧):lpush key value [value value …..]
- 获取指定列表中指定下标区间的元素:lrange key startIndex endIndex
- 将一个或者多个值依次插入到列表的表尾(右侧):rpush key value [value value …..]
- 从指定列表中移除并且返回表头元素:lpop key
- 从指定列表中移除并且返回表尾元素:rpop key
- 获取指定列表中指定下标的元素:lindex key index
- 获取指定列表的长度:llen key
- 根据count值移除指定列表中跟value相等的数据:lrem key count value
- count>0:从列表的左侧移除count个跟value相等的数据
- count<0:从列表的右侧移除count个跟vlaue相等的数据
- count=0:从列表中移除所有跟value相等的数据
- 截取指定列表中指定下标区间的元素组成新的列表,并且赋值给key:ltrim key startIndex endIndex
- lpush list04 1 2 3 4 5 ltrim list04 1 3 结果:5 4 3 2 1
- 将指定列表中指定下标的元素设置为指定值: lset key index value
- 将value插入到指定列表中位于pivot元素之前/之后的位置: linsert key before/after pivot vlaue
redis中有关set类型数据的操作命令
- 将一个或者多个元素添加到指定的集合中:sadd key value [value value ….]
- 如果元素已经存在,则会忽略
- 返回成功加入的元素的个数
- 获取指定集合中所有的元素:smembers key
- 判断指定元素在指定集合中是否存在:sismember key member
- 存在,返回1
- 不存在,返回0
- 获取指定集合的长度:scard key
- 移除指定集合中一个或者多个元素:srem key member [member …..]
- 不存在的元素会被忽略
- 返回成功成功移除的个数
- 随机获取指定集合中的一个或者多个元素:srandmember key [count]
- count>0:随机获取的多个元素之间不能重复
- count<0: 随机获取的多个元素之间可能重复
- 从指定集合中随机移除一个或者多个元素:spop key [count]
- 将指定集合中的指定元素移动到另一个元素:smove source dest member
- 获取第一个集合中有、但是其它集合中都没有的元素组成的新集合:sdiff key key [key key ….]
- 获取所有指定集合中都有的元素组成的新集合:sinter key key [key key ….]
- 获取所有指定集合中所有元素组成的大集合:sunion key key [key key …..]
redis中有关hash类型的操作命令
- 将一个或者多个field-vlaue对设置到哈希表中:hset key filed1 value1 [field2 value2 ….]
- 如果key field已经存在,把value会把以前的值覆盖掉
- 获取指定哈希表中指定field的值:hget key field
- 批量将多个field-value对设置到哈希表中: hmset key filed1 value1 [field2 value2 ….]
- 批量获取指定哈希表中的field的值:hmget key field1 [field2 field3 ….]
- 获取指定哈希表中所有的field和value:hgetall key
- 从指定哈希表中删除一个或者多个field:hdel key field1 [field2 field3 ….]
- 获取指定哈希表中所有的filed个数:hlen key
- 判断指定哈希表中是否存在某一个field:hexists key field
- 获取指定哈希表中所有的value列表:hvals key
- 对指定哈希表中指定field值进行整数加法运算:hincrby key field int
- 对指定哈希表中指定field值进行浮点数加法运算:hincrbyfloat key field float
- 将一个field-vlaue对设置到哈希表中,当key-field已经存在时,则放弃设置;否则,设置file-value:hsetnx key field value
redis中有关zset类型数据的操作命令
- 将一个或者多个member及其score值加入有序集合:zadd key score member [score member ….]
- 如果元素已经存在,则把分数覆盖
- 获取指定有序集合中指定下标区间的元素:zrange key startIndex endIndex [withscores]
- 获取指定有序集合中指定分数区间(闭区间)的元素:zrangebyscore key min max [withscores]
- 删除指定有序集合中一个或者多个元素:zrem key member [member……]
- 获取指定有序集合中所有元素的个数:zcard key
- 获取指定有序集合中分数在指定区间内的元素的个数:zcount key min max
- 获取指定有序集合中指定元素的排名(排名从0开始): zrank key member
- 获取指定有序集合中指定元素的分数:zscore key member
- 获取指定有序集合中指定元素的排名(按照分数从大到小的排名):zrevrank key member
redis的配置文件
redis安装完成之后,在redis的根目录会提供一个配置文件(redis.conf);redis服务可以参考配置文件中的参数进行运行;只有启动redis服务器指定使用的配置文件,参数才会生效;否则,redis会采用默认的参数运行
网络配置
- port:配置redis服务运行的端口号
- 如果不配置port,则redis服务默认使用6379端口
- redis-cli :默认连接127.0.0.1本机上的6379端口服务
- 强调:一旦redis服务配置了port和bind(如果port不是6379、bind也不是127.0.0.1),客户端连接redis服务时,就要指定端口和ip
- redis-cli -h bind绑定的ip地址 -p port设置的端口:连接bind绑定的ip地址主机上的port设置的端口redis服务
- redis-cli -h bind绑定的ip地址 -p port设置的端口 shutdown:关闭redis服务
- 如果不配置port,则redis服务默认使用6379端口
- bind: redis服务被客户端连接时,客户端所能使用的ip地址
- 默认情况下,不配置bind,客户端连接redis服务时,通过服务器上任何一个ip都能连接到redis服务
- 一旦配置了bind,客户端就只能通过bind指定的ip地址连接redis服务
- 一般情况下,bind都是配置服务器上某一个真实ip
- tcp-keepalive:连接保活策略
- 如果两端的 TCP 连接一直没有数据交互,达到了触发 TCP 保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文。
- 如果对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来
- 如果对端主机崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡
- 如果两端的 TCP 连接一直没有数据交互,达到了触发 TCP 保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文。
常规配置
- loglevel:配置日志级别,开发阶段配置debug,上线阶段配置notice或者warning
- logfile:指定日志文件。redis在运行过程中,会输出一些日志信息
- 默认情况下,这些日志信息会输出到控制台
- 使用logfile配置日志文件,使redis把日志信息输出到指定文件中
安全配置
- requirepass:设置访问redis服务时所使用的密码
- 默认不使用
- 此参数必须在protected-mode=yes时才起作用
- 一旦设置了密码验证,客户端连接redis服务时,必须使用密码连接:redis-cli -h ip -p port -a pwd
redis的持久化
redis提供持久化策略,在适当的时机采用适当手段把内存中的数据持久化到磁盘中,每次redis服务启动时,都可以把磁盘上的数据再次加载内存中使用。
RDB策略
- 在指定时间间隔内,redis服务执行指定次数的写操作,会自动触发一次持久化操作,将内存中的数据写入到磁盘中
- RDB策略是redis默认的持久化策略,redis服务开启时这种持久化策略就已经默认开启了。
- 配置
- save
:配置持久化策略 - dbfilename:配置redis RDB持久化数据存储的文件
- dir: 配置redis RDB持久化文件所在目录
- save
AOF策略
- 采用操作日志来记录进行每一次写操作,每次redis服务启动时,都会重新执行一遍操作日志中的指令。
- 效率低下,redis默认不开启AOF功能
- 配置
- appendonly:配置是否开启AOF策略
- appendfilename:配置操作日志文件
根据数据的特点决定开启哪种持久化策略, 一般情况,开启RDB足够了。
reids的事务
事务:把一组数据库命令放在一起执行,保证操作原子性,要么同时成功,要么同时失败。
Redis的事务:允许把一组redis命令放在一起,把命令进行序列化,然后一起执行,保证部分原子性。
redis事务常用命令:
开启事务:multi
- 事务开启后,redis会将后续的命令逐个放入队列中
- 开启成功返回OK
执行事务中的命令:exec
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态
如果在把命令压入队列的过程中报错,则整个队列中的命令都不会执行,执行结果报错
如果在压队列的过程中正常,在执行队列中某一个命令报错,则只会影响本条命令的执行结果,其它命令正常运行
当使用WATCH命令时,只有当受监控的键没有被修改时,EXEC命令才会执行事务中的命令;而一旦执行了exec命令,之前加的所有watch监控全部取消
命令时,如果事务执行中止,那么EXEC命令就会返回一个Null值
清除事务中的命令:discard
- 清除所有先前在一个事务中放入队列的命令,并且结束事务
- 如果使用了watch命令,那么discard命令就会将当前连接监控的所有键取消监控
监控事务:watch
- 监控某一个键,当事务在执行过程中,此键代码的值发生变化,则本事务放弃执行;否则,正常执行
- Watch命令相当于关系型数据库中的乐观锁
清除事务监控:unwatch
- 清除所有先前为一个事务监控的键
- 如果在watch命令之后调用了exec或d命discard令,那么就不需要手动调用unwatch命令
单独的隔离操作:事务中的所有命令都会序列化、顺序地执行。事务在执行过程中,不会被其它客户端发来的命令请求所打断,除非使用watch命令监控某些键。
不保证事务的原子性:redis同一个事务中如果一条命令执行失败,其后的命令仍然可能会被执行,redis的事务没有回滚。Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。
redis消息的订阅与发布
redis客户端订阅频道,消息的发布者往频道上发布消息,所有订阅此频道的客户端都能够接受到消息。
相关命令:
- subscrib:订阅一个或者多个频道的小溪
- eg:subscribe ch1 ch2 ch3
- publish:将消息发布到指定频道
- eg:publish ch1 hello
- psubcribe:订阅一个或者多个频道的消息,频道名支持通配符
- eg:psubscribe news.*
消息的订阅与发布有更优秀的中间件来执行(activeMQ2….)
redis的主从复制
主少从多、主写从读、读写分离、主写同步复制到从。
相关命令:
查看当前redis服务在集群中的主从角色:info replication
- 默认情况下,所有的redis服务都是主机,即都能写和读,但是都还没有从机
设置主从关系:slaveof 主机ip 端口号
- 将当前主机设为主机ip 端口号的从机
- 设从不设主
全量复制:一旦主从关系确定,会自动把主库上已有的数据同步复制到从库
增量复制:主库写数据会自动同步到从库
主写从读,读写分离
- 主机宕机、从机原地待命
- 主机恢复、一切恢复正常
- 从机宕机、主机少一个从机、其它从机不变
- 从机恢复、从机为主机,需要重新设置主从关系
从机上位
- 主机宕机、从机原地待命
- 从机断开原来主从关系:slaveof no one
- 重新设置主从关系:slaveof 主机ip 主机port
- 既是主机又是从机的只能读不能写
一台主机配置多台从机,一台从机又可以配置多台从机,从而形成一个庞大的集群架构。减轻一台主机的压力,但是增加了服务间的延迟时间。
redis的哨兵模式
主机宕机、从机上位的自动版。Redis提供了哨兵的命令,哨兵命令是一个独立的进程,哨兵通过发送命令,来监控主从服务器的运行状态,如果检测到master故障了根据投票数自动将某一个slave转换master,然后通过消息订阅模式通知其它slave,让它们切换主机。然而,一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多哨兵进行监控。
相关命令:
- 创建哨兵文件sentinel.conf
- 启动哨兵:redis-sentinel 哨兵文件全路径
- 开启监控:sentinel monitor dc-redis 指定监控主机的ip地址 port端口 得到哨兵的投票数
- 当哨兵投票数大于或者等于此数时切换主从关系
- 设置密码:sentinel auth-pass mymaster pwd
哨兵模式三大任务:监控,提醒,自动故障迁移。
Jedis操作Redis
jedis是redis官方提供的在java应用中操作redis数据的技术。 把所有的redis指令都定义成java工具类的方法,方法名和redis的指令名完全一样。
开发通过程序访问redis,只需要使用工具类及其方法即可。
在java程序中访问redis:
创建maven版的java工程
添加jedis依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.3.0</version> </dependency>
3.创建Jedis连接(关闭linux的防火墙)
//连接jedis
Jedis jedis=new Jedis("主机ip",主机port);
4.使用Jedis类中的方法操作redis
//连接redis
Jedis jedis=new Jedis("192.168.148.132",6380);
//使用jedis对象
String res= jedis.ping();
System.out.println(res);
Set<String> keys = jedis.keys("*");
for (String key:keys){
System.out.println(key);
}
Boolean k2 = jedis.exists("k2");
System.out.println(k2);
Long k21 = jedis.move("k2", 1);
System.out.println(k21);
jedis.select(1);
//.......
遇到的问题及解决方法:
问题1: java.net.SocketTimeoutException: connect timed out
解决方法:
1. 关闭服务器防火墙:systemctl stop firewalld
2. 重启redis服务(可能之前改了配置没有重启服务,还存有缓存,导致客户端向服务器发送接口的时候没有得到响应)
- 导致有缓存的原因:
- 防火墙放开端口
- 后台更改了ip配置等等
Redis安装
官网下载redis到window上
使用Xftp上传redis-5.0.2.tar.gz到Linux系统
执行linux命令tar -zxvf redis-5.0.2.tar.gz -C /opt 解压redis-5.0.2.tar.gz到/opt目录
联网情况下执行命令yum -y install gcc安装编译器gcc
- 编译结果:在redis的安装目录下src目录中,生成redis的一系列可执行文件。
cd进入解压目录,执行命令make编译redis
- 编译结果:在redis的安装目录下src目录中,生成redis的一系列可执行文件。
执行命令make install 把redis的安装目录下src目录中生成redis的一系列可执行文件拷贝到/usr/local/bin中,在任何目录下都可以执行redis命令。