为什么要用Redis
NoSQL:
NoSQL是不同于传统的关系数据库的数据库管理系统的统称。其两者最重要的区别是NoSQL不使用SQL作为查询语言。 NoSQL数据存储可以不需要固定的表格模式。NoSQL是基于键值对的,可以想象成表中的主键和值的对应关系。
常见的NoSQL有:redis、memcached、mongodb、guava(loadingCache)
redis的定义:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多 种类型的数据结构,如 字符串(strings)、散列(hashes)、 列表(lists)、 集合(sets)、 有序集合(sorted sets)等。
作为同款功能的内存缓存产品,redis和memcached各有什么优势:
内存管理机制
Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小, 将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎 片问题。空闲列表进行判断存储状态,【类似于Java虚拟机对象的分配,空闲列表】
Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,【CPU内存是连续,类似于Java虚拟机对象的分配,直接内存分配(指针碰撞)】
数据持久化方案
memcached不支持内存数据的持久化操作,所有的数据都以in-memory的形式存储。
redis支持持久化操作。redis提供了两种不同的持久化方法来讲数据存储到硬盘里面, 第一种是rdb形式,一种是aof形式:
rdb:属于全量数据备份,备份的是数据
aof:append only if,增量持久化备份,备份的是指令
缓存数据过期机制
概念:key,设计一个小时之后过期,超过一个小时查数据就会查不到
Memcached 在删除失效主键时也是采用的消极方法,即 Memcached 内部也不会监视主键是否失效,而是在通过 Get 访问主键时才会检查其是否已经失效
Redis 定时、定期等多种缓存失效机制,减少内存泄漏
支持的数据类型
Memcached支持单一数据类型:[k,v]
redis支持五种数据类型:【字符串(strings)、散列(hashes)、 列表(lists)、 集合(sets)、 有序集合(sorted sets)】
redis作为数据库的使用有什么优缺点?
优点:没有Scheme约束,数据结构的变更相对容易,一开始确定数据类型, 抗压能力强,性能极高,10万/qps
缺点:没有索引,没有外键,缺少int/date等基本数据类型,多条件查询需要通过集合内联(sinter,zinterstore) 和连接间接实现开发效率低,可维护性不佳
redis作为缓存的使用,搭配数据库使用的两种方案
1.jedis整合使用方案 set key,value ["11","22"] 第一层在缓存进行查询,如果得到数据则直接返回, 第二层在数据库进行查询,并且刷新缓存,方便下次查询 ["33,"44"]
2.作为mybatis/hibernate二级缓存使用方案,一级缓存:sqlSession,进程缓存,单次链接有效
Redis安装启动
redis4.0安装步骤:
- 安装wget yum install wget
- 下载redis安装包 wget http://download.redis.io/releases/redis-4.0.6.tar.gz
- 解压压缩包 tar -zxvf redis-4.0.6.tar.gz
- yum install gcc
- 跳转到redis解压目录下 cd redis-4.0.6
- 编译安装 make MALLOC=libc
- cd src ./redis-server
redis三种启动方式以及其中的使用区别
1.直接启动(例如:cd src ./redis-server)
2.通过指定配置文件启动(例如:cd src ./redis-server ../redis.conf)
3.使用redis启动脚本设置开机启动,linux配置开机自启动/etc/init.d
配置步骤:
- 启动脚本 redis_init_script 位于Redis的 /utils/ 目录下
- mkdir /etc/redis
- cp redis.conf /etc/redis/6379.conf
- 将启动脚本复制到/etc/init.d目录下,本例将启动脚本命名为redisd(通常都以d结尾表示是后台自启动服务)。
cp redis_init_script /etc/init.d/redisd
- 设置为开机自启动,直接配置开启自启动 chkconfig redisd on 发现错误: service redisd does not support chkconfig
解决办法:在启动脚本开头添加如下注释来修改运行级别
#!/bin/sh # chkconfig: 2345 90 10
- 设置为开机自启动服务器
chkconfig redisd on
service redisd start 打开服务
service redisd stop 关闭服务
Redis五种数据类型和消息订阅
Key / Value数据类型
String是最常用的一种数据类型,普通的key/value存储都可以归为此类。
常用的命令:
set/get
设置key对应的值为String类型的value
获取key对应的值mget
批量获取多个key的值,如果可以不存在则返回nilincr && incrby
incr对key对应的值进行加加操作,并返回新的值;incrby加指定值decr && decrby
decr 对key对应的值进行减减操作,并返回新的值;decrby减指定值setnx
设置key对应的值为String类型的value,如果key已经存在则返回0setex
设置key对应的值为String类型的value,并设定有效期其他命令
getrange:获取key对应value的子字符串
mset:批量设置多个key的值,如果成功表示所有值都被设置,否则返回0表示没有任何值被设置
msetnx:同mset,不存在就设置,不会覆盖已有的key
getset:设置key的值,并返回key旧的值
append:给指定key的value追加字符串,并返回新字符串的长度
Hash类型
- Hash是一个String类型的field和value之间的映射表
- redis的Hash数据类型的key(hash表名称)对应的value实际的内部存储结构为一个HashMap
- Hash特别适合存储对象
- 相对于把一个对象的每个属性存储为String类型,将整个对象存储在Hash类型中会占用更少内存。
- 所存储的成员较少时数据存储为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
- 运用场景:如用一个对象来存储用户信息,商品信息,订单信息等等。
- Hash命令讲解
hset——设置key对应的HashMap中的field的value
hget——获取key对应的HashMap中的field的value
hgetall——获取key对应的HashMap中的所有field的value
hlen——返回key对应的HashMap中的field的数量
List类型
- lpush——在key对应的list的头部添加一个元素
- lrange——获取key对应的list的指定下标范围的元素,-1表示获取所有元素
- lpop——从key对应的list的尾部删除一个元素,并返回该元素
- rpush——在key对应的list的尾部添加一个元素
- rpop——从key对应的list的尾部删除一个元素,并返回该元素
Set类型
- sadd——在key对应的set中添加一个元素
- smembers——获取key对应的set的所有元素
- spop——随机返回并删除key对应的set中的一个元素
- suion——求给定key对应的set并集
- sinter——求给定key对应的set交集
SortSet类型
set的基础增加顺序score,再根据score进行排序
实战(用途):通过sortset实现排行榜
- zadd ——在key对应的zset中添加一个元素
- zrange——获取key对应的zset中指定范围的元素,-1表示获取所有元素
- zrem——删除key对应的zset中的一个元素
- zrangebyscore——返回有序集key中,指定分数范围的元素列表,排行榜中运用
- zrank——返回key对应的zset中指定member的排名。其中member按score值递增(从小到大); 排名以0为底,也就是说,score值最小的成员排名为0,排行榜中运用
- set是通过hashmap存储,key对应set的元素,value是空对象 sortset是怎么存储并实现排序的呢,hashmap存储,还加了一层跳跃表 跳跃表:相当于双向链表,在其基础上添加前往比当前元素大的跳转链接
redis消息订阅发布
作用:发布订阅类似于信息管道,用来进行系统之间消息解耦,类似于mq,rabbitmq、rocketmq、kafka、activemq主要有消息发布者和消息订阅者。比如运用于:订单支付成功,会员系统加积分、钱包进行扣钱操作、发货系统(下发商品)
PUBLISH 将信息message发送到指定的频道channel。返回收到消息的客户端数量
SUBSCRIBE 订阅给指定频道的信息
UNSUBSCRIBE 取消订阅指定的频道,如果不指定,则取消订阅所有的频道。
redis的消息订阅发布和mq对比?
redis发布订阅功能比较薄弱但比较轻量级,mq消息持久化,数据可靠性比较差,无后台功能可msgId、msgKey进行查询消息
传统关系型数据库事务与Redis事务
事务概要和事务隔离级别
一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:
1)为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2)当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。事务的ACID四大特性
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中事务隔离机制
语法:set global transaction isolation level read uncommitted;
种类:read uncommitted、read committed、repeatable read、serializable
mysql事务隔离机制和MVCC
redis事务隔离机制可重复读讲解(repeatable read)
select @@tx_isolation ; 查看事务类型
-
InnoDB MVCC多版本并发控制
在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空,其实还有一列称为回滚指针,用于事务回滚)。这里的版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号, 用来和查询每行记录的版本号进行比较
redis事务机制
MULTI 与 EXEC命令
以 MULTI 开始一个事务,然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令DISCARD命令
DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消-
WATCH命令
WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
redis事务ACID
原子性(Atomicity)
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。如果一个事务队列中的所有命令都被成功地执行,那么称这个事务执行成功一致性(Consistency)
入队错误
在命令入队的过程中,如果客户端向服务器发送了错误的命令,比如命令的参数数量不对等等, 那么服务器将向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC 。
执行错误
如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响
隔离性(Isolation)
WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败持久性(Durability)
因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定