谈起 Redis,相信大家都不会陌生,做过云平台开发的程序员多多少少会接触到它,Redis 英文全称:Remote Dictionary Server,也被称之为远程字典服务.
Redis 由一个叫 Salvatore Sanfilippo 的人开发而闻名世界,此人来自意大利的西西里岛,网名叫 antirez,如果你有兴趣,可以去他的博客逛逛,地址是 antirez.com.
Redis 是当下互联网技术中使用最为广泛的缓存中间件之一,随着它在新浪微博中的使用而逐渐风靡国内.
虽然开源软件市场上也有很多优秀的缓存服务中间件,比如 memcache,但是和 redis 对比起来,redis 还是显得格外的突出,优势如下:
数据类型丰富:支持 String,Hash,List,Set,Sorted Set 等数据类型的操作
支持原子性操作:Redis 的每条命令操作都是原子性的,Redis 的操作之所以是原子性的,是因为每条命令的执行都是单线程的,不存在线程竞争问题
存储方式多样化:memecache 把数据全部存在内存之中,断电后会挂掉;redis 支持数据的持久化,同时也支持数据的备份,即 master-slave 模式的数据备份
功能丰富:Redis 还支持 publish/subscribe,通知,key 过期等等特性
在分布式的架构环境下,Redis 基本上是缺一不可的缓存中间件,它能很好的解决服务与服务之间数据共享的问题,并且性能不受影响.
说了这么多,如何使用呢?我们一起来看看!
因为 redis 目前官方只支持 LINUX 系统,所以呢没有 Windows 版本的软件包,但是好在微软团队维护了开源的 windows 版本,虽然更新不算及时,但是对于普通测试使用足够了.
https://github.com/tporadowski/redis/releases
打开文件夹,内容如下:
然后,打开一个 cmd 窗口,使用 cd 命令切换目录到C:\redis,并且输入如下命令:
redis-server.exe redis.windows.conf
出现以上界面,表示redis服务器已经成功启动了.
另启一个 cmd 窗口,原来的窗口不要关闭,不然就无法访问服务端了.
使用 cd 命令切换目录到C:\redis,并且输入如下命令:
redis-cli.exe -h 12⑦0.0.1 -p 6379
连接到服务器之后,输入写命令和取命令,相关命令如下:
#写数据测试
set myKey abc
#取数据测试
get myKey
http://redis.io/download
# wget https://download.redis.io/releases/redis-⑥2.⑥tar.gz
# tar xzf redis-⑥2.⑥tar.gz
# cd redis-⑥2.6
# make
执行下面的脚本,启动 redis 服务器.
# cd src
# ./redis-server
需要注意的地方是,这种方式启动 redis 使用的是默认配置,也可以通过参数告诉 redis 使用指定配置文件来启动服务,其中redis.conf是一个默认的配置文件,我们可以根据需要使用自己的自定义配置文件.
# cd src
# ./redis-server ../redis.conf
当出现Ready to accept connections时,表示服务已经启动成功.
# cd src
# ./redis-cli
redis> set foo bar
OK
redis> get foo
"bar"
可能有的同学会发出一个疑问,如何将 Redis 改成后台服务?
也就是将窗体关闭也能正常提供服务,答案就藏在redis.conf这个配置文件里.
打开redis.conf文件,常用配置如下:
#绑定ip
bind 0.0.0.0
#启动端口
port 6379
# 是否运行远程访问
protected-mode yes
# 是否允许后台运行,默认no,将其改成yes
daemonize yes
# redis访问密码,根据需要设置,如果要打开,将#去掉
# requirepass foobared
# 数据库的数量
databases 16
修改配置,然后重启服务即可生效,操作如下:
# 寻找redis相关进程
ps -ef|grep redis
# 杀掉进程
kill -9
# 重新启动redis
./redis-server ../redis.conf
redis.conf详细配置项说明如下:
include /path/to/local.conf
然后本地解压,后续的操作跟linux一样,在此就不过多的介绍了!
$ ./redis-cli
比如,连接本地的 redis 服务器(前提是已经启动成功).
$ ./redis-cli
redis 12⑦0.0.1:6379>
redis 12⑦0.0.1:6379> PING
PONG
如果 redis 设置了密码,通过AUTH命令输入密码即可进入,方式如下:
$ ./redis-cli
redis 12⑦0.0.1:6379> AUTH "password"
redis 12⑦0.0.1:6379> PING
PONG
如果我们想连接远程 redis 服务器,可以通过如下语法方式实现.
$ ./redis-cli -h host -p port -a password
$redis-cli -h 192.16⑧121.1 -p 6379 -a "mypass"
redis 192.16⑧121.1:6379>
redis 192.16⑧121.1:6379> PING
PONG
默认连接的数据库是0,如果我们想切换数据库,可以通过如下方式实现切换!
# 使用 1 号数据库
redis 192.16⑧121.1:6379>SELECT 1
如果想要关闭当前连接,通过如下方式即可实现!
redis 192.16⑧121.1:6379>QUIT
以字符串为例,增删改查操作如下!
①.、设置指定 key 的值, SET 在设置操作成功完成时,返回 OK.
redis 12⑦0.0.1:6379>SET mykey redis
OK
redis 12⑦0.0.1:6379>GET mykey
"redis"
redis 12⑦0.0.1:6379>EXISTS mykey
(integer) 1
redis 12⑦0.0.1:6379>DEL mykey
(integer) 1
# 设置 mykey,60秒过期
redis 12⑦0.0.1:6379>EXPIRE mykey 60
(integer) 1
redis 12⑦0.0.1:6379>TTL mykey
(integer) 60
redis 12⑦0.0.1:6379>INCR mykey
(integer) 1
当然,也可以在设置阶段,指定某个初始值数字,比如将mykey的自增初始值设置为10.
redis 12⑦0.0.1:6379>INCR mykey 10
(integer) 11
Redis 也支持事务操作,Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
①批量操作在发送 EXEC 命令前被放入队列缓存
一个事务从开始到执行会经历以下三个阶段:
①开始事务
以某个事务操作为例, 我们先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令,过程如下:
redis 12⑦0.0.1:6379> multi
OK
redis 12⑦0.0.1:6379> set a aaa
QUEUED
redis 12⑦0.0.1:6379> set b bbb
QUEUED
redis 12⑦0.0.1:6379> set c ccc
QUEUED
redis 12⑦0.0.1:6379> exec
1) OK
2) OK
3) OK
特别注意的地方是:单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的.
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做.
也就是说,如果在set b bbb处失败,set a aaa已成功不会回滚,set c ccc还会继续执行,当set b bbb处执行失败,这个事务是不会回滚的.
在上面我们也介绍到了,Redis 事务的执行并不能完全保证原子性,那么如何将一批命令操作做到原子性操作呢?
Redis 支持通过 Lua 脚本来实现一批命令原子性操作,执行脚本的常用命令为 EVAL.
Eval 命令的基本语法如下:
redis 12⑦0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]
比如简单的赋值操作如下:
redis 12⑦0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
redis 12⑦0.0.1:6379>EVAL "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end" 1 key1 hello 60
(integer) 1
获取指定key的值,如果存在就删除key,实现原子性操作,如果操作成功就返回 1,否则返回 0,内容如下:
redis 12⑦0.0.1:6379>EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 key1 hello
(integer) 1