分布式缓存Redis
What is Redis?
Redis是一个开源的,基于内存的数据结构存储服务器,被用作数据库、缓存、消息代理。它支持的数据结构类型有strings, hashes, lists, sets, sorted sets,bitmaps, hyperloglogs, geospatial, Stream。Redis有内置的复制,lua脚本,LRU(Least Recently Used最近最少使用)淘汰,事务,磁盘持久化,并提供高可用的Redis Sentinel哨兵和自动分区的Redis Cluster集群。
Redis环境搭建
下载:http://download.redis.io/releases/redis-5.0.5.tar.gz
解压:tar -zxvf redis-5.0.5.tar.gz -C /usr/local
编译:切换到解压后的目录: cd redis-5.0.5,执行命令:make (make命令是编译,Linux需要有gcc编译器,如果没有,安装请执行 yum install gcc -y )
测试编译状态:make test (可以跳过)
执行make 后,redis安装完成;
安装说明:
1. 测试编译状态需要安装tcl: yum install tcl -y
2. error: jemalloc/jemalloc.h: No such file or directory提示该错误是Redis在安装时需要有一个内存分配器allocator,如果指定了MALLOC这个环境变量,那么会用这个环境变量的去建立Redis。如果没有,那么就是用默认的分配器,Redis 2.4版本之后,默认使用jemalloc来做内存管理,因为jemalloc被证明解决fragmentation problems(内存碎片化问题)比libc更好。但是如果你的环境中没有jemalloc而只有libc,所以make会出错,你可以加这么一个参数即可。
解决办法:
make MALLOC=libc
Redis基本配置
redis-server |
redis服务器 |
redis-cli |
Redis命令行客户端 |
redis-benchmark |
Redis性能测试工具 |
redis-check-aof |
Aof文件修复工具 |
redis-sentinel |
Sentinel服务器 |
redis-check-rdb |
rdb文件修复工具 |
mkreleasehdr.sh |
编译redis源码时需要用到的一个脚本 |
redis-trib.rb |
官方提供的Redis Cluster的管理工具,因该工具是用ruby开发的,所以需要安装ruby环境。 |
配置文件 |
作用 |
redis.conf |
Redis核心配置文件 |
sentinel.conf |
Redis sentinel 哨兵配置文件 |
在使用Redis之前,建议将安装目录下redis-5.0.5/redis.conf配置文件修改三个配置项:
1、protected-mode no (改为不保护,否则远程访问不了)
2、bind 127.0.0.1 (注释掉,否则只能本机ip访问)
3、daemonize yes (改为yes表示后台启动redis)
启动:切换到 redis-5.0.5/src/ 目录执行命令 ./redis-server ../redis.conf
关闭: 切换到 redis-5.0.5/src/ 目录执行:./redis-cli shutdown 或者 kill pid 或者 kill -9 pid
说明:
Redis默认6379端口是手机键盘上的MERZ,MERZ是一名意大利歌女的名字;
考虑到redis有可能正在将内存的数据同步到硬盘中,强行终止redis进程可能会导致数据丢失,正确停止redis的方式应该是向Redis发送SHUTDOW命令,
当redis收到SHUTDOWN命令后,会先断开所有客户端连接,然后根据配置执行持久化,最终完成优雅退出
Redis的windows版本:https://github.com/microsoftarchive/redis/releases
Redis客户端
直接连接redis (默认ip127.0.0.1,端口6379):./redis-cli
指定IP和端口连接redis:./redis-cli -h 127.0.0.1 -p 6379
测试redis运行是否正常:ping
redis默认为16个库,redis默认自动使用0号库;
切换库命令:select db
查看当前数据库中key的数目:dbsize
删除所有库的数据:flushall
删除当前库的数据:flushdb
查看redis服务器的统计信息:info
获得redis的所有配置项:config get *
Redis图形界面客户端
Redis Desktop Manager
注意:
远程连接redis需要修改redis安装目录下的redis.conf配置文件:1、bind ip 绑定ip注释掉;2、protected-mode yes 保护模式改为no;
国人开源AnotherRedisDesktopManager
github:https://github.com/qishibo/AnotherRedisDesktopManager
Redis编程客户端
Jedis
Jedis源码:https://github.com/xetorthio/jedis
api文档:http://xetorthio.github.io/jedis/
Jedis是一个很小巧但功能很健全的redis的java客户端;其实就是一个jar包,放到项目中,利用该jar包连接和操作redis;
Lettuce
Github:https://github.com/lettuce-io/lettuce-core
Lettuce是一个可伸缩线程安全的Redis客户端,多个线程可以共享同一个RedisConnection,它利用优秀netty NIO框架来高效地管理多个连接。
Redisson
Github: https://github.com/redisson/redisson
2014年1月发布的开源项目,底层也是采用netty进行通信,不支持string数据结构,促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合;
Redis支持50多种语言的编程客户端.
Redis数据类型
String类型
字符串类型是redis中最基本的数据类型,也是使用最多的一种数据类型,它能存储任何形式的字符串,包括二进制数据,byte字节等,也就是说string类型能存储任
何数据,你可以用它存储序列化后的用户对象,json化的对象,甚至图片,视频等,一个key下的string类型允许存储的最大数据容量是512M;
String类型可以用来存储任何类型的数据; SET, GET;
String类型可以用来做计数器; INCR, DECR, INCRBY,DECRBY
list类型
列表类型可以存储一个字符串列表,按照数据加入的顺序排序,它非常方便地在往列表左右两端添加元素(左边称为头部,右边称为尾部)。 LPUSH,RPUSH
一个list列表最大能存放2的32次方-1个元素(4294967295, 40多亿个元素)
列表类型内部使用双向链表实现,所以向列表两端添加元素的时间复杂度为O(1), 获取越接近两端的元素速度就越快。这意味着即使是一个有几千万个元素的列表,获取
头部或尾部的10条记录也是很快的,但是如果尝试访问一个非常大的列表的中间元素,则速度会很慢,因为这是一个时间复杂度O(n)操作。
使用场景:类似时间轴的应用,每个时间点发生的重大事件存入list形成时间轴;
LPUSH,LRANGE 记住最近的操作,往list列表头部放入元素,取头部的几个元素即为最近记录;
LPUSH,RPOP 可以作为一个消息传递的顺序队列,从左边放入元素,从右边取出元素;LPUSH,RPOP
set类型
set类型是一个无顺序的字符串集合,集合中每个元素都是不同的,也就是不允许有重复数据,多次添加同一个元素,集合中只会有一个该元素一个set集合最大能存
放2的32次方-1个元素(4294967295, 40多亿个元素)
集合类型和列表类型的最大的区别是无序性/有序性和唯一性/可重复; set类型在redis内部是使用的值为空的散列表(hash table),所以添加或删除元素操作的时间复杂度都是O(1);
使用场景:跟踪不同的事情,比如:每天的ip访问量;使用set做抽奖,把名单放入set,set不会重复,随机弹出元素;
zset类型(sorted set)
zset类型与set相似,也是一个无重复元素的集合,不同的是zset的每个元素会关联一个分数,这个分数用于对集合元素进行排序;zset中的元素是唯一的,但是每个元素的分数是可以重复的;
使用场景:实时的数据排行榜,每次数据的更新会更新分数;
hash类型
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
过期时间设置
在Redis中提供了Expire命令设置一个键的过期时间,到期以后Redis会自动删除它,实际使用中也经常使用。
EXPIRE命令:EXPIRE key seconds --先设置好数据,然后再设置该key的过期时间;SETEX key seconds value --在设置数据的同时,可以直接设置过期时间;
其中seconds 参数表示键的过期时间,单位为秒。EXPIRE 返回值为1表示设置成功,0表示设置失败或者key不存在;
keys * --查看redis中当前数据库0号库所有的key
如果想知道一个key还有多久时间过期,可以使用TTL命令:TTL key
当键不存在时,TTL命令会返回-2 如果key没有设置过期时间,通过TTL命令会返回-1, -1表示永不过期;
如果想取消key的过期时间(使该key恢复成永久的),可以使用PERSIST命令,如果该命令执行成功,清除了过期时间,则返回1 ,否则返回0(key不存在或者本身就是永久的)
EXPIRE命令的seconds命令必须是整数,所以最小单位是1秒,如果想要更精确的设置key的过期时间可以使用PEXPIRE命令,当然实际过程中用秒的单位就够了。PEXPIRE命令的单位是毫秒。即PEXPIRE key 1000与EXPIREkey 1相等,对应的PTTL以毫秒单位获取键的剩余有效时间;
过期key自动删除(自动清理)的原理
Redis 中的key失效是如何实现的,即失效的key是如何删除的?实际上,Redis 删除失效key的方法主要有两种:
消极方法:在key被访问时如果发现它已经失效,那么就删除它;
积极方法:周期性地从设置了过期时间的key中选择一部分过期的key删除.对于那些从未被查询的key,即便它们已经过期,消极方式也无法清除,因此Redis会周期性
地随机测试一些key,已过期的key将会被删掉。
Redis每秒会进行10次操作,具体的流程:1. 随机测试 20 个带有过期信息的key;2. 删除其中已经过期的key;3. 如果超过25%的key被删除,则重复执行步骤1;
这是一个简单的概率算法(trivial probabilistic algorithm),基于假设我们随机抽取的key代表了全部的key空间。
Redis命令大全
redis英文版命令大全:https://redis.io/commands
redis中文版命令大全:http://redisdoc.com/
Redis分布式锁
关于锁,我们并不陌生,比如Java有线程锁,比如:synchroniz/Lock等.锁的目的很简单,在多线程环境下,对共享资源的访问造成的线程安全问题,通过锁的机制实现资源
访问互斥.
什么是分布式锁,为什么我们需要分布式锁?其实最根本的原因就是锁(互斥)的范围发生了变化,因为在分布式架构中,所有的服务都是集群部署,这些应用是隔离的,在多进程访问共享资源的同时,我们需要满足互斥性就需要一个所有进程都看得到的范围,而这个范围可以使用Redis本身或者Zookeeperh或者数据库等外部设施.
Redis里面提供了一些能够实现互斥特性的命令,比如SETNX (在key不存在的情况下为key设置值,key存在的话就不设置值),那么我们可以基于这些命令来去实现锁;
利用Redis实现分布式锁主要用到三个命令
1、SETNX 设置key及key的值,如果key存在就设置失败,key不存在就设置成功;2、EXPIRE 设置key的过期时间3、DEL 删除key