Redis简介
REDIS数据库为NOSQL的其中一种,又称为REDIS缓存。
- 80%的系统瓶颈主要出现在数据库一侧 --(海量并发下,网络、磁盘IO开销会导致数据库性能出现瓶颈) --(海量数据下,数据查找可能需要关联上千张表、遍历数千万的数据、花费几分钟) 为了减少数据库压力,提升访问速度,我们需要用到读取速度更快的高性能缓存框 架。
- 常用的缓存框架有哪些 --EHCache 高性能 轻量 系统内嵌 --Memcached 多线程 高性能 系统内嵌 --Redis 分布式 高性能 持久化
Redis是什么?
- REDIS是Remote Dictionary Server的缩写,是一个开源的高性能的Key-Value 存储系统,独立的进程服务,它使用字典结构存储数据,并允许其他应用 通过TCP协议读写字典中的内容。
- REDIS提供了丰富的数据结构以及对这些数据结构的操作支持。
- REDIS可以替代Memcached,并且解决断电后数据丢失的问题。
- REDIS的官方网站:http://redis.io
简单来说,Redis是一个基于键值的存储在内存的NoSql数据库,主要用来作为缓存使用。
Redis的特性
- 速度快
- 持久化
- 多种数据结构
- 支持多种编程语言
- 功能丰富
- 源码简单
- 主从复制
- 高可用分布式
速度快
1、什么语言编写的?
--- C语言 3万多行
2、数据存储在哪儿?
---系统内存中
官方测试:
在50个并发的情况下请求10万次,写的速度是11W次/s,读的速度是8.1W次/s
测试环境:
1、LINUX2.6内核 Xeon X3320 2.5GHz服务器
2、读和写大小为256bytes的字符串
持久化
REDIS所有数据保持在内存中,为了保持断电不丢数据,也提供持久化的支持,将内存中的数据的异步写到磁盘上,同时不影响继续提供服务。
1、机器断电
2、磁盘故障
3、服务重启
数据结构
REDIS支持多种丰富的数据结构:
1、字符类型 2、散列类型 3、列表类型 4、集合类型 5、有序集合
多编程支持
REDIS具有丰富的客户端,支持现阶段流行的大多数编程语言:
1、JAVA
2、PHP
3、C#
4、C++
5、PYTHON
6、RUBY
7、NODEJS ....
JAVA常用的是Jedis (http://redis.io/clients)
功能丰富
Redis在很多场合是名副其实的多面手,越来越多的人将其用作缓存、队列系统中。例如,Redis可作为缓存系统,并且可以为每个键设置生存时间,生存时间到期后键会自动删除;Redis还支持“发布/订阅”的消息模式,等等
足够简单
REDIS使用相对简单,源代码量共23000行,定制化开发相对容易
主从复制
企业项目使用REDIS上线,考虑到单节点REDIS的高可靠性。
1、主节点 2、备节点 ....
官方主从复制速度:SLAVE在21秒即完成了对AMAZON网站10g的 key、set复制。
集群分布
企业大规模使用REDIS过程中会受限于多个方面:
1、单机内存有限 2、带宽压力 3、单点问题 4、动态扩容 ....
安装配置
Redis安装
1.WINDOWS系统REDIS单节点服务器安装
REDIS官方建议服务器安装到LINUX系统,默认更新LINUX REDIS系统包。 学习入门简易性开发便捷性在WINDOWS安装:(安装MSI或解压ZIP文件夹),如下图:
- Windows下的安装几乎没有什么过程,解压后就可以使用。简单介绍下着几个exe文件的用途:
- redis.windows.conf --Redis的配置文件
- redis-benchmark.exe --Redis性能测试工具
- redis-check-aof.exe --AOF文件修复工具
- redis-check-dump.exe --RDB检查数据库文件
- redis-cli.exe --redis命令行客户端
- redis-server.exe --redis服务器
1、 redis-server 双击运行或者用dos命令打开都可以,成功运行后可以看到界面内容如下
会带有版本号、运行进程号、运行端口信息。并且会提醒使用redis.windows.conf配置文件(个别系统必须指定配置文件)。
1、 正常启动方式就是带指定redis.conf配置文件的启动方式,如下:
2、如果准备长期使用,可注册为系统服务
- 注册安装系统服务,DOS命令:
- redis-server.exe --service-install redis.conf --service-name 服务名
- redis-server --service-start --service-name 服务名
- 停止卸载系统服务,DOS命令:
- redis-server --service-stop --service-name 服务名
- redis-server --service-uninstall --service-name 服务名
如何判断服务是否正常已经启动?
DOS命令行中输入:netstat -aon|findstr "6379"
redis启动流程
1.初始化server变量,设置redis相关的默认值
2.读入配置文件,同时接收命令行中传入的参数,替换服务器设置的默认值
3.初始化服务器功能模块。在这一步初始化了包括进程信号处理、客户端链表、共享对象、初始化数据、初始化网络连接等
4.从RDB或AOF持久文件中重载数据
5.网络监听服务启动前的准备工作
6.开启事件监听,开始接受客户端的请求
2.REDIS基础配置常用配置项
配置文件:
1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 (windows不支持)
daemonize no
2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
pidfile /var/run/redis.pid
3. 指定Redis监听端口,默认端口为6379,为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
port 6379
4. 绑定的主机地址(允许哪些IP可以访问REDIS,多个IP以空格分割)
bind 127.0.0.1 192.168.138
5.当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300
6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose
7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout
8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save <seconds> <changes>
Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
11. 指定本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
12. 指定本地数据库存放目录
dir ./
13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
14. 当master服务设置了密码保护时,slav服务连接master的密码
masterauth <master-password>
15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
requirepass foobared
16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxclients 128
17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory <bytes>
18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
19. 指定更新日志文件名,默认为appendonly.aof
appendfilename appendonly.aof
20. 指定更新日志条件,共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec
21. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf
3.REDIS常用命令行指令
redis-cli.exe ,全称(Redis Command Line Interface),是Redis自带的基于命令行客户端。
如何通过redis-cli向redis发送命令:
1、默认不带参数
执行时候会按照默认服务器地址:127.0.0.1,端口号:6379,连接redis
2、指定服务器参数
redis-cli -h 127.0.0.1 -p 6379 -a 123456 通过-h 和 -p自定义服务地址和端口号。-a 为登陆密码,如果无密码不需要。
简单几个常用命令:
1、auth 登陆密码
2、ping 连接是否正常
3、info 查看服务相关状态信息
4、get 查询KEY对应的值
5、set 设置键值对(增加或修改)--支持有效期
6、keys 查找匹配的键
7、incr 自增1,只对整数值
8、decr 自减1,只对整数值
数据类型
REDIS数据库概念
REDIS是一个字典结构的存储服务器,提供了多个用于存储的字典,客户端可以指定 存储在哪个字典中,可以理解为每个为独立的数据库。
REDIS默认支持16个数据库。
数据库以编号命名,从0开始到15。默认使用第0个数据库。
如何切换数据库?
select 1 切换到1号数据库
注:REDIS数据库更像是命名空间,而不适应存储不同应用的数据。实际生产用选择数据库的存储极少
Redis内部内存管理中是如何描述这些不同数据类型的:
Redis内部使用一个
redisObject对象来表示所有的key和value, redisObject最主要的信息如图所示:
- type代表一个value对象具体是何种数据类型, encoding是不同数据类型在redis内部的存储方式, 每次当我们在Redis数据库中新创建一个键值对时,至少会创建两个对象,一个对象用作键值对的键(键对象),另一个用作键值对的值(值对象)。
- 比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串。
- vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的
redis本质上一个key-value 数据库,所以我们首先来看看他的key. 首先key也是字符串类型,由于key不是binary safe的字符串, 所以像“my key”和“mykey\n”这样包含空格和换行的key是不允许的。
我们在使用的时候可以自己定义一个Key的格式。例如 object-type:id:field
Key不要太长。占内存,查询慢。
Key不要太短。u:1000:pwd
不如 user:1000:password 可读性好
KEY相关命令
exists key 测试指定key是否存在,返回1表示存在,0不存在
del key1 key2 ....keyN 删除给定key,返回删除key的数目,0表示给定key都不存在
type key 返回给定key的value类型。返回 none 表示不存在,key有string字符类型,list 链表类型 set 无序集合类型等...
keys pattern 返回匹配指定模式的所有key(支持*,?,[abc ]的方式),下面给个例子
dbsize 返回当前数据库的key数量
expire key seconds 为key指定过期时间,单位是秒。返回1成功,0表示key已经设置过过期时间或者不存在
ttl key 返回设置了过期时间的key的剩余过期秒数, -1表示key不存在或者没有设置过过期时间
select db-index 通过索引选择数据库,默认连接的数据库所有是0,默认数据库数是16个。返回1表示成功,0失败
move key db-index 将key从当前数据库移动到指定数据库。返回1成功。0 如果key不存在,或者已经在指定数据库中
flushdb 删除当前数据库中所有key,此方法不会失败。慎用
flushall 删除所有数据库中的所有key,此方法不会失败。更加慎用
字符类型(String)
- string是redis最基本的类型,而且string类型是二进制安全的。
- redis的string可以包含任何数据。包括jpg图片或者序列化的对象。
- 最大上限是512M,建议不要超过10m
- 如果只用string类型,redis就可以被看作加上持久化特性的memcached
实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
String相关命令
- set key value 设置key对应的值为string类型的value,返回1表示成功,0失败
- setex 将值value关联到key,并将key的生存时间设为seconds(以秒为单位)。 如果key 已经存在,SETEX命令将覆写旧值。
- setnx 当且仅当key不存在,将key的值设为value,并返回1;若给定的key已经存在,则SETNX不做任何动作,并返回0,SETNX 是SET if Not eXists的简写
- get key 获取key对应的string值,如果key不存在返回nil getset 将给定key的值设为value,并返回key的旧值 (old value),当key存在但不是 字符串类型时,返回一个错误,当key不存在时,返回nil。
- mget key1 key2 ... keyN 一次获取多个key的值,如果对应key不存在,则对应返回 nil。下面是个实验, nonexisting不存在,对应返回nil
- mset key1 value1 ... keyN valueN 一次设置多个key的值,成功返回1表示所有的值都设置了,失败返回0表示没有任何值被设置
- msetnx key1 value1 ... keyN valueN 同上,但是不会覆盖已经存在的key
- incr key 对key的值做加加操作,并返回新的值。注意incr一个不是int的value会返回错误,incr一个不存在的key,则设置key为1
- decr key 同上,但是做的是减减操作,decr一个不存在key,则设置key为-1
- incrby key integer 同incr,加指定值 ,key不存在时候会设置key,并认为原来的value是 0
- decrby key integer 同decr,减指定值。decrby完全是为了可读性,我们完全可以通过incrby一个负值来实现同样效果,反之一样。
- append key value 给指定key的字符串值追加value,返回新字符串值的长度。
- substr key start end 返回截取过的key的字符串值,注意并不修改key的值。下标是从0开始的。
String应用场景
1、普通的数据库前置缓存,get/set简单数据到内存中
2、incr自增原子计数器,生成分布式业务唯一编号(比如:携程网的订单号生成、中移 10085主键生成等,这样订单号或者主键编号就不依赖于任何业务数据库,对后续的分 库分表很方便。
3、setnx结合getset实现分布式锁,高并发抢红包秒杀等应用
散列类型(Hash)
- redis hash是一个string类型的field和value的映射表。
- hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。
实现方式
Hash对应value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转为真正的HashMap,此时encoding为ht
Hash相关命令
- hget key field 获取指定的hash field
- hset key field value 设置hash field为指定值,如果key不存在,则先创建
- hgetall key 返回hash的所有filed和value
- hmget key filed1....fieldN 获取全部指定的hash filed
- hmset key filed1 value1 ... filedN valueN 同时设置hash的多个field
- hincrby key field integer 将指定的hash filed 加上给定值
- hexists key field 测试指定field是否存在
- hdel key field 删除指定的hash field
- hlen key 返回指定hash的field数量
- hkeys key 返回hash的所有field
- hvals key 返回hash的所有value
Hash应用场景
主要存储类似数据库中的二维行列结构数据,对JAVA编码而言就是对象结构数据。
1、比如分布式SESSION,当前登陆用户(用户编号,部门编号,角色编号等属性)
2、大型互联网高并发电商中对商品不同维度的计数(喜欢数,评论数,浏览数等)
3、微博中用户维度的(发帖数、动态数、关注数、粉丝数等)
列表类型(List)
- redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。
List相关命令
- lpush key string 在key对应list的头部添加字符串元素,返回1表示成功,0表示key存在且不是list类型
- rpush key string 同上,在尾部添加
- lpop key 从list的头部删除元素,并返回删除元素。如果key对应list不存在或者是空返回nil,如果key对应值不是list返回错误
- rpop 同上,但是从尾部删除
- lrange key start end 返回指定区间内的元素,下标从0开始,负值表示从后面计算,-1表示倒数第一个元素 ,key不存在返回空列表
- llen key 返回key对应list的长度,key不存在返回0,如果key对应类型不是list返回错误
- ltrim key start end 截取list,保留指定区间内元素,成功返回1,key不存在返回错误
- lset key index value 设置list中指定下标的元素值,成功返回1,key或者下标不存在返回错误
- lrem key count value 从key对应list中删除count个和value相同的元素。
List应用场景
主要存储类似列表结构应用
1、twitter的关注列表,粉丝列表 2、新浪微博的关注列表等 3、取最新的N个数据的操作
集合类型(Set)
- redis的set是string类型的无序集合。
- set元素最大可以包含(2的32次方-1)个元素。
- set的是通过hash table实现的,hash table会随着添加或者删除自动的调整大小。
- 关于set集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现sns中的好友推荐和blog的tag功能。
Set相关命令
- sadd key member 添加一个string元素到,key对应的set集合中,成功返回1,如果元素以及在集合中返回0,key对应的set不存在返回错误
- srem key member 从key对应set中移除给定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key对应的不是set类型的值返回错误
- spop key 删除并返回key对应set中随机的一个元素,如果set是空或者key不存在返回nil
- srandmember key 同spop,随机取set中的一个元素,但是不删除元素
- smove srckey dstkey member 从srckey对应set中移除member并添加到dstkey对应set中,整个操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果key不是set类型返回错误
- scard key 返回set的元素个数,如果set是空或者key不存在返回0
- sismember key member 判断member是否在set中,存在返回1,0表示不存在或者key不存在
- sinter key1 key2...keyN 返回所有给定key的交集
- sinterstore dstkey key1...keyN 同sinter,但是会同时将交集存到dstkey下
- sunion key1 key2...keyN 返回所有给定key的并集
-
sunionstore dstkey key1...keyN 同sunion,并同时保存并集到dstkey
-
sdiff key1 key2...keyN 返回所有给定key的差集
-
sdiffstore dstkey key1...keyN 同sdiff,并同时保存差集到dstkey下
-
smembers key 返回key对应set的所有元素,结果是无序的
Set应用场景
Set对外提供的功能与list类似,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的接口。
1、Uniqe操作,获取某段时间所有数据的排重值
2、共同好友,二度好友
3、利用唯一性,统计访问网站的所有独立IP
4、好友推荐,根据标签TAG求交集,大于某个界定值就可以推荐
有序类型(Sorted Set)
- 和set一样sorted set也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score。sorted set的实现是skip list和hash table的混合体。当元素被添加到集合中时,一个元素到score的映射被添加到hash table中,另一个score到元素的映射被添加到skip list 并按照score排序,所以就可以有序的获取集合中的元素。
- zadd key score member 添加元素到集合,元素在集合中存在则更新对应score
- zrem key member 删除指定元素,1表示成功,如果元素不存在返回0
- zincrby key incr member 增加对应member的score值,然后移动元素并保持skip list有序。返回更新后的score值
- zrank key member 返回指定元素在集合中的排名(下标,非score),集合中元素是按score从小到大排序的
- zrevrank key member 同上,但是集合中元素是按score从大到小排序
- zrange key start end 类似lrange操作从集合中取指定区间的元素。返回的是有序结果
- zrevrange key start end 同上,返回结果是按score逆序的
- zrangebyscore key min max 返回集合中score在给定区间的元素
- zcount key min max 返回集合中score在给定区间的数量
- zcard key 返回集合中元素个数
- zscore key element 返回给定元素对应的score
- zremrangebyrank key min max 删除集合中排名在给定区间的元素
- zremrangebyscore key min max 删除集合中score在给定区间的元素
Sorted Set应用场景
与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级score的参数来为成员排序,并且是插入有序的,即自动排序,当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构。
1、在线游戏排行榜:列出前100名高分选手,列出某用户当前全球排名
每次获得新得分时,我们用这样的代码: ZADD leaderboard <score> <username> 得到前100名高分用户很简单:ZREVRANGE leaderboard 0 99。 用户的全球排名也相似,只需要:ZRANK leaderboard <username>。
2、需要精准设定过期时间的应用(时间戳为score)
sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。