Redis简介
Redis全称:Remote Dictionary Server(远程数据服务)。Redis
是一个开源的使用ANSI C
语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value
数据库,并提供多种语言的API
。和Memcached
类似,它支持存储的value
类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set
--有序集合)和hash(哈希类型)。这些数据类型都支持push/pop
、add/remove
及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis
支持各种不同方式的排序。与memcached
一样,为了保证效率,数据都是缓存在内存中。区别的是redis
会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis安装配置(Linux平台)
Redis编译与安装
在进行redis
的编译安装需要先进行 apt-get install make
1.将Redis
开发包上传到Linux
系统之中,但是需要注意,由于给出的开发包属于源代码,所以建议解压缩到/usr/local/src
目录之中;
tar -xzvf /srv/ftp/redis-3.2.9.tar.gz -C /usr/local/src/
2.进入到redis源代码所在的安装目录:cd /usr/local/src/redis-3.2.9/
3.进行程序的编译处理,输入:make
4.编译完成之后要进行Redis
安装,输入:make install
5.Redis
属于内存缓存数据库,那么如果你现在是一台单独的Redis服务器,则应该考虑将所有的可用内存都交给Redis
来进行支配,所以理论上还需要执行如下的一行代码:
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
本次的操作指的是进行一次内存的分配策略,在进行设置的时候vm.overcommit_memory属性有如下三个取值:
- 0:表示在进行处理的时候首先要检查是否有足够的内存供应, 如果现在没有足够的内存供应,则无法分配,内存申请失败,如果有可用内存则直接进行申请开辟;
- 1:表示将所有的内存都交给应用使用,而不关心当前的内存状态如何;
- 2:表示允许分配超过所有物理内存和交换空间的内存的总和;
6.将以上的配置写入到内核参数之中:/sbin/sysctl -p
7.为了方便使用Redis数据库,那么建立一个Redis
支持的命令工具目录:
mkdir -p /usr/local/redis/{bin,conf}
8.通过源代码目录拷贝出Redis
所需要的程序运行文件:
- 拷贝
Redis
服务启动程序:cp /usr/local/src/redis-3.2.9/src/redis-server /usr/local/redis/bin/
- 拷贝Redis命令行客户端:
cp /usr/local/src/redis-3.2.9/src/redis-cli /usr/local/redis/bin/
- 性能测试工具:
cp /usr/local/src/redis-3.2.9/src/redis-benchmark /usr/local/redis/bin/
9.拷贝出一个配置文件:
cp /usr/local/src/redis-3.2.9/redis.conf /usr/local/redis/conf/
Redis数据库配置
如果要想配置Redis
数据库,主要的配置文件就是redis.conf,所有的配置项一定要在此处完成。
-
Redis
作为一个具备有持久化功能的缓存数据库,所以其一定会有一个用于数据存储的目录,那么一般在Redis
处理的时候会有三类文件需要做保存:Redis
运行时的pid
、Redis
相关处理日志、Redis
的数据文件,所以建立一个目录用于存放这些数据:
mkdir -p /usr/data/redis/{run,logs,dbcache}
2.修改redis.conf的配置文件:vim /usr/local/redis/conf/redis.conf
- 配置
Redis
运行端口:port 6379
- 配置
Redis
是否为后台运行:daemonize yes
- 设置进程保存路径:
pidfile /usr/data/redis/run/redis_6379.pid
- 设置日志保存目录:
logfile "/usr/data/redis/logs/redis.log"
- 该
Redis
支持的数据库个数:databases 16
- 保存数据文件目录:
dir /usr/data/redis/dbcache
3.启动Redis服务:/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
- 如果要启动
Redis-Server
就必须明确的指明要使用的redis.conf
配置文件;
4.Redis
启动会占用6379
的端口,所以查看端口:netstat -nptl
;
- 此时发现Redis运行的时候是在6379本机下才可以执行,所以无法对外提供服务;
5.启动Redis
客户端:
方式一:连接本机6739
端口的Redis
: /usr/local/redis/bin/redis-cli
方式二:连接远程的格式 : /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379
6.设置一个数据:set myredis java
;
7.取得数据:get myredis
8.关闭Redis
服务:
- 取得要关闭的
Redis
服务的进程,而后使用kill
直接杀死; - 直接使用
killall redis-server
干掉所有的Redis
服务。
9、redis
日志查看目录:/usr/data/redis/logs
cat redis.log
Redis数据操作
Redis
支持各种的数据类型,而且Redis
操作的速度很快的,在Redis
数据库里面有一个redis-benchmark性能测试工具,可以直接使用这个工具来观察Redis
使用,该命令所需要的参数如下:
root@redis-single:~# /usr/local/redis/bin/redis-benchmark --help
Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
-h <hostname> Server hostname (default 127.0.0.1)
-p <port> Server port (default 6379)
-s <socket> Server socket (overrides host and port)
-a <password> Password for Redis Auth
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
-dbnum <db> SELECT the specified db number (default 0)
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
Using this option the benchmark will expand the string __rand_int__
inside an argument with a 12 digits number in the specified range
from 0 to keyspacelen-1. The substitution changes every time a command
is executed. Default tests use this to hit random keys in the
specified range.
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-e If server replies with errors, show them on stdout.
(no more than 1 error per second is displayed)
-q Quiet. Just show query/sec values
--csv Output in CSV format
-l Loop. Run the tests forever
-t <tests> Only run the comma separated list of tests. The test
names are the same as the ones produced as output.
-I Idle mode. Just open N idle connections and wait.
Examples:
Run the benchmark with the default configuration against 127.0.0.1:6379:
$ redis-benchmark
Use 20 parallel clients, for a total of 100k requests, against 192.168.1.1:
$ redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20
Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:
$ redis-benchmark -t set -n 1000000 -r 100000000
Benchmark 127.0.0.1:6379 for a few commands producing CSV output:
$ redis-benchmark -t ping,set,get -n 100000 --csv
Benchmark a specific command line:
$ redis-benchmark -r 10000 -n 10000 eval 'return redis.call("ping")' 0
Fill a list with 10000 random elements:
$ redis-benchmark -r 10000 -n 10000 lpush mylist __rand_int__
On user specified command lines __rand_int__ is replaced with a random integer
with a range of values selected by the -r option.
范例:下面模拟1000个客户端进行数据的处理
/usr/local/redis/bin/redis-benchmark -h 127.0.0.1 -p 6379 -c 1000 -d 10 -n 10000
此时的命令之中的具体参数含义如下:
- -h:要连接的Redis服务器的地址;
- -p:要连接Redis的运行端口;
- -c:指的是模拟的客户端数量;
- -d:每一次操作的数据长度;
- -n:每一个用户发出的请求数量。
随后来观察一下当前的测试结果,会包含有如下的信息内容:
- PING_INLINE: 44247.79 requests per second;
- SET: 42918.46 requests per second;
- GET: 43478.26 requests per second;
- INCR: 42372.88 requests per second;
- LPUSH: 43290.04 requests per second;
- RPUSH: 41666.67 requests per second;
- LPOP: 42918.46 requests per second;
- RPOP: 44052.86 requests per second;
-
SADD: 43859.65 requests per second;
...
字符串类型
在Redis
里面有一个特别重要的命令keys,可以进行全部数据的列出。其中后面的*****表示数据的匹配。
1、设置新的数据:set KEY VALUE
set username tom
2、取得对应的数据:get KEY
get username
- 如果在进行数据查询的时候没有对应的key的内容,则返回的是(nil)数据;
- 在数据取得的时候没有*****的通配,只有**keys ***命令提供有这一操作。
3.清空仓库:flushdb
;
4.不覆盖设置内容:setnx KEY VALUE
setnx username JAMES
setnx username JAMES
- 对于
setnx
的返回结果有如下两类:0(表示没有设置成功)、1(设置成功); - 如果你现在设置的两个数据的key的内容是相同的,默认情况下是会发生有覆盖的问题的;
set uname james
set uname tom
5.设置数据保存的有效时间:setnx KEY VALUE
setex wechat_code 60 3452
- 现在就表示该设置的内容在60秒之后就会自动销毁。
- 在实际的使用之中验证码的信息保存就使用了此类数据类型,因为该类型的数据到点后自动消失。
- 在某一个
key
具备有指定的有效时间设置之后实际上可以使用ttl key查看当前剩余有效时间,如果该内容已经消失则返回-2,如果没有消失,则返回剩余的时间,或者在有效期内使用persist key,让该key取消有效时间,这个时候如果使用ttl命令查看则返回的结果是-1;
6.设置多个key
的内容:mset KYE1 VALUE1 KEY2 VALUE2...
mset username-110 hello username-120 world username-119 cry
那么此时同时设置有三个key
的信息,如果此时设置有相同的key
的信息,那么默认会出现覆盖的问题:
mset username-110 hello1 username-120 world1 username-119 cry1
7.不覆盖设置多个key
:msetnx KEY1 VALUE1 KEY2 VALUE2...
- 包含有一个重复的内容以及两个不重复的内容,因为有一个存在所以返回的是0,并且所有的内容都不允许设置:
msetnx username-110 hello2 username-1 hello username-2 world
- 包含全部新的内容:现在表示成功返回1。
msetnx username-1 hello username-2 world
8.内容追加:a1end KEY CONTENT
a1end username-110 world
返回的是当前的内容的长度;
9.取得指定key
的内容长度:strlen KEY
strlen username-110
10.删除指定的数据内容:del KEY1 KEY2 ...
del 110-code username-1 username-99
如果现在指定的key
不存在,也不会影响到程序的执行,只会删除掉存在的key的信息。
以下为redis执行代码:
127.0.0.1:6379> set username tom
OK
127.0.0.1:6379> get username
"tom"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> setnx username JAMES
(integer) 1
127.0.0.1:6379> setnx username JAMES
(integer) 0
127.0.0.1:6379> get username
"best"
127.0.0.1:6379> set uname james
OK
127.0.0.1:6379> set uname tom
OK
127.0.0.1:6379> get uname
"tom"
127.0.0.1:6379> setex wechat_code 60 3452
OK
127.0.0.1:6379> get wechat_code
"3452"
127.0.0.1:6379> get wechat_code
(nil)
127.0.0.1:6379> mset username-110 hello username-120 world username-119 cry
OK
127.0.0.1:6379> mset username-110 hello1 username-120 world1 username-119 cry1
OK
127.0.0.1:6379> get username-110
"hello1"
127.0.0.1:6379> msetnx username-110 hello2 username-1 hello username-2 world
(integer) 0
127.0.0.1:6379> msetnx username-1 hello username-2 world
(integer) 1
127.0.0.1:6379> a1end username-110 world
(integer) 11
127.0.0.1:6379> del 110-code username-1 username-99
(integer) 1
Hash数据类型
Hash是一种最为常见的数据类型,其保存的数据结构为key = value,但是需要提醒的是这个时候的key
与value
并不是redis
中的key
和valu
e,hash
是作为一种类型,可以这样理解关系:RedisKey = HashValue,利用Hash
类型可以保存更多的数据。
1.存放Hash
数据:hset hash-key sub-key1 value1
设置一个Hash
类型,保存一个用户的用户名和真实姓名:
结构:mid
为用户名的保存的属性名称、7396
为真实的用户名;
hset member mid 7396
hset member name tom
2.取得散列包含的所有键值内容:hgetall hash-key
它在进行数据排列的时候采用的模式为:hash-key、hash-value、hash-key、hash-value
。
hgetall member
取得指定key
的内容:
- 取得指定
key
中的mid
的数据:hget member mid
; - 取得指定
key
中的name
的数据:hget member name
;
3.默认情况下hset
会进行覆盖设置,那么使用hsetnx
就可以避免掉这种覆盖设置的问题:
- 设置重复数据:
hsetnx member mid hello
,返回的结果为0(false
); - 设置不重复的数据:
hsetnx member-aa mid hello
,返回结果为1(true
)。 - 这个时候所有的**keys * **可以见到的内容只是所有的
key
的名称。
4.数据批量设置:hmset member-1 name wusheng age 55 province hb
;
5.判断某个key
的某个属性是否存在:hexists member-1 school
;
6.取得全部的数据的成员个数:hlen member
;
7.删除指定的key
的内容:hdel member-1 age,name
;
8.取得一个hash
中的所有的key
(成员)内容:hkeys member-1
;
9.取得指定hash
中的所有内容:hvals member
;
以下为具体代码操作:
127.0.0.1:6379> hset member mid 7396
(integer) 1
127.0.0.1:6379> hset member name tom
(integer) 1
127.0.0.1:6379> hgetall member
1) "mid"
2) "7396"
3) "name"
4) "tom"
127.0.0.1:6379> hget member mid
"7396"
127.0.0.1:6379> hsetnx member mid hello
(integer) 0
127.0.0.1:6379> hsetnx member-aa mid hello
(integer) 1
127.0.0.1:6379> keys *
1) "username-120"
2) "username-110"
3) "member"
4) "username-2"
5) "username"
6) "member-aa"
7) "uname"
8) "username-119"
127.0.0.1:6379> hmset member-1 name wusheng age 15 province beijing
OK
127.0.0.1:6379> hexists member-1 school
(integer) 0
127.0.0.1:6379> hlen member
(integer) 2
127.0.0.1:6379> hdel member-1 age,name
(integer) 0
127.0.0.1:6379> hkeys member-1
1) "name"
2) "age"
3) "province"
127.0.0.1:6379> hvals member
1) "7396"
2) "tom"
数字操作
普通数据类型
- 自增处理:
incr KEY
- 自增指定数据:
incrby KEY num
- 自减处理:
decr KEY
- 自减指定数据:
decrby KEY
数据类型 - 数据加法:
hincrby
对象KEY
数字
1.如果要进行数字的操作,那么肯定要设置两个数字的内容:
- 设置一个基本类型:
set shopcar-pid 100
; - 设置一个Hash类型:
hset sc pid-72378 100
;
2.进行普通数据类型的数字操作:
- 自增1处理:
incr shopcar-pid
,随后会返回当前增长后的数据内容。 - 默认增长为1,现在要求增长为5:
incrby shopcar-pid 5
; - 自减1处理:
decr shopcar-pid
; - 自减指定的数据:
decrby shopcar-pid 100
;
3.进行Hash
数据类型的数字操作:hincrby sc pid-72378 1
实际上整个数字操作里面只需要记住两个命令:incrby
、hincrby
就够了。
127.0.0.1:6379> set shopcar-pid 100
OK
127.0.0.1:6379> hset sc pid-72378 100
(integer) 1
127.0.0.1:6379> incr shopcar-pid
(integer) 101
127.0.0.1:6379> incrby shopcar-pid 200
(integer) 301
127.0.0.1:6379> incrby shopcar-pid 5
(integer) 306
127.0.0.1:6379> decr shopcar-pid
(integer) 305
127.0.0.1:6379> decrby shopcar-pid 100
(integer) 205
127.0.0.1:6379> hincrby sc pid-72378 1
(integer) 101
List数据类型
List数据类型是一种比较麻烦的处理操作。在实际的项目开发里面,List就是一个链表结构,那么链表结构的时间复杂度是n,而且在进行链表数据处理的时候主要是进行内容的保存、节点的设置、递归遍历。
1.左边压入创建一个描述关键字的List集合:lpush javaee redis java hello happy word cloud
;
push
属于入栈,栈的特点是先进后出;
2.进行指定范围的链表数据输出:lrange javaee 0 -1
,如果设置为-1则表示输出全部的内容。
3.右边压入进行入栈处理:rpush javaee 1 2 3 4 5 6 7
;
4.在指定元素(hello
)上追加内容:
在指定元素前追加:linsert javaee before hello hello-before
;
- 在指定元素后追加:
linsert javaee after hello hello-after
; - 如果此时你保存的集合内容存放有重复的数据,则以第一个数据为准进行保存。
5.删除数据:lrem javaee 5 hello
;
6.保留指定范围的数据:ltrim javaee 0 9
,范围编号不在0 ~ 9
之间的所有数据将被删除掉;
7.栈顶元素出栈:lpop javaee
;
8.栈底元素出栈:rpop javaee
。
9.将移除的数据保存到另一个集合:rpoplpush javaee new_javaee
表示将javaee
的集合中的栈底的一个元素出栈,而后压入到new_javaee
这个集合的栈顶。
10.取得指定索引对应的数据:lindex javaee 0
;
11.取得集合个数:llen javaee
;
127.0.0.1:6379> lpush javaee redis java hello happy word cloud
(integer) 6
127.0.0.1:6379> lrange javaee 0 -1
1) "cloud"
2) "word"
3) "happy"
4) "hello"
5) "java"
6) "redis"
127.0.0.1:6379> rpush javaee 1 2 3 4 5 6 7
(integer) 13
127.0.0.1:6379> linsert javaee before hello hello-before
(integer) 14
127.0.0.1:6379> linsert javaee after hello hello-after
(integer) 15
127.0.0.1:6379> lrange javaee 0 -1
1) "cloud"
2) "word"
3) "happy"
4) "hello-before"
5) "hello"
6) "hello-after"
7) "java"
8) "redis"
9) "1"
10) "2"
11) "3"
12) "4"
13) "5"
14) "6"
15) "7"
127.0.0.1:6379> lrem javaee 5 hello
(integer) 1
127.0.0.1:6379> ltrim javaee 0 9
OK
127.0.0.1:6379> lrange javaee 0 -1
1) "cloud"
2) "word"
3) "happy"
4) "hello-before"
5) "hello-after"
6) "java"
7) "redis"
8) "1"
9) "2"
10) "3"
127.0.0.1:6379> lpop javaee
"cloud"
127.0.0.1:6379> rpop javaee
"3"
127.0.0.1:6379> rpoplpush javaee new_javaee
"2"
127.0.0.1:6379> lrange new_javaee 0 -1
1) "2"
127.0.0.1:6379> lindex javaee 0
"word"
127.0.0.1:6379> llen javaee
(integer) 7
Set数据类型
Set也是一种常见的数据类型,其最大的特征是基于数据的集合比对处理,例如:可以实现数据的交集、并集、差集。
1.向集合之中追加新元素:sadd user-redis a b c d e
;
此时向该集合之中追加有五个元素,可以把每一个元素想象为一个用户名;
2.查询set
集合处理:smembers user-redis
,List
集合是有序的,而Set
集合是无序的。
3.删除set
集合元素:srem user-redis a
;
4.从集合中弹出元素(该元素会自动进行删除处理):spop user-redis
;
5.返回两个集合的差集合:
准备出第一个集合:sadd user-redis a b c d e
准备出第二个集合:sadd user-admin a c e x y z
进行差运算:sdiff user-redis user-admin
6.保存差集的运行结果到其它集合:sdiffstore user-admin-redis user-admin user-redis
将user-admin与user-redis两个用户的数据进行差集的计算处理,并且将结果保存到user-admin-redis集合中;
查看差集的保存:smembers user-admin-redis
7.交集运算:sinter user-redis user-admin
;
将交集保存到指定的集合里面去:sinterstore user-admin-redis-inter user-admin user-redis
;
8.并集运算:sunion user-admin user-redis
;
将并集保存到指定的集合里面:sunionstore user-admin-redis-union user-admin user-redis
;
9.弹出数据到另外的集合中:smove user-redis user-redis-tmp a
;
10.返回集合个数:scard user-redis
;
11.判断指定的集合中是否包含有指定的元素存在:sismember user-redis b
,如果存在返回 1,不存在返回 0;
12.虽然返回集合中的数据:srandmember user-redis 3
;
其中后面可以设置返回的数据个数,如果不设置默认为 1;
SortedSet集合
Set集合的最大特征是可以进行数据比对,但是Set数据本身是属于无序的保存,所以如果需要进行数据的顺序保存,那么可以采用SortedSet,这个也不算是一个顺序保存,更多的情况下该集合可以保存有一个分数,而这个分数的操作就可以作为一些数据的统计结果出现。
1.增加SortedSet
数据:
zadd user-redis 1 pid-1
zadd user-redis 1 pid-2
zadd user-redis 1 pid-3
现在假设这些商品的信息该用户只看了一次,所以每一个数据的分数为1。
2.取得sortedSet
集合中的全部数据:
显示所有的数据的元素:zrange user-redis 0 -1
;
显示每一个元素和其对应的分数:zrange user-redis 0 -1 withscores
;
也可以输出指定范围的数据:zrange user-redis 0 2 withscores
;
3.从集合里面删除数据:zrem user-redis pid-
;
4.元素分数的增长:zincrby user-redis 5 pid-1
,会返回有当前增长后的数据内容;
5.取得指定元素的索引内容:zrank user-redis pid-1
,索引值从0
开始;
6.数据反转处理取得索引:zrevrank user-redis pid-1
;
7.反转后取得数据:zrevrange user-redis 0 -1 withscores
;
8.根据分数范围取得数据:
闭区间处理:zrangebyscore user-redis 3 6 withscores
,包含了3
和6
开区间处理:zrangebyscore user-redis (3 (6 withscores
;
设置一个范围:zrangebyscore user-redis 1 10 withscores limit 0 2
;
9.取得指定分数范围的数据量:zcount user-redis 2 8
;
10.取得指定key中的集合数量:zcard user-redis
;
取得指定的分析的key
:keys *
;
11.根据索引下标删除数据:zremrangebyrank user-redis 0 5
;
总结
1.基本类型(
String
、int
):基本类型的操作更加适合于用户进行短期的数据存储,因为在实际的开发之中,字符串可以进行各种复杂操作,而且字符串也可以描述出各种数据的含义。那么在实际的开发之中,可以利用此类型使用Nginx
的集群数据保存、Shiro
的集群数据保存、SpringData
数据保存(序列化)、JSON数据的保存;
2.hash
类型:hash
类型更多的情况下描述的是一个结构化的信息,但是这种结构化的信息个人认为不如对象序列化好用,但是至少需要知道Hash这样的类型可以进行内容的详细分类;
3.List
(栈、队列):在实际的开发之中可以利用此类型实现消息队列的功能,或者进行缓冲的功能,很多公司有可能不直接使用消息队列中间件,而直接利用Redis代替。
4.Set
数据类型:最大的支持功能在于集合的运算上,例如:相似度检测、好友推荐等等,都可以通过这种集合的处理方式来完成,应用案例:新浪微博。
5.SortedSet
:主要进行数据的流式分析;
就以用户浏览商品操作为例。通过分数来进行商品推荐。
Redis事务处理
Redis本身支持事务处理,但是这种支持的事务处理本身是存在有设计缺陷的,而且与传统的关系型数据库的事务处理有些不同,首先先来看一下Redis
中的事务支持命令:
- 打开事务:multi;
- 取消事务:discard;
- 提交事务:exec。
范例:观察Redis
中的事务
设置一个数据:
set age 30
打开事务支持:multi
QUEUED进行数据操作:set age 300
QUEUED进行数据操作:set age 3000
关闭事务:discard
一旦开启了Redis
的事务控制,则表示所有的更新操作都要追加到一个更新队列之中。由于现在在执行完更新之后发现数据本身出现有问题了,所以选择了关闭事务,一旦事务关闭之后那么该操作将会回滚到最初的状态。
范例:执行事务提交
设置一个数据:
set age 30
打开事务支持:multi
QUEUED进行数据操作:set age 50
提交事务:exec
如果在事务开启状态下进行了更新处理,随后只有执行了exec
指令后才表示事务真正提交,才会真正影响到原始数据。 但是需要提醒的是,Redis
设计之初就是不考虑事务的,所以以上的事务只能够说是Redis
的一个玩笑,因为这种事务本身设计的并不完善。
设置一个数据:
set id redis
打开事务支持:multi
QUEUED进行数据操作:incr id
QUEUED进行数据操作:set age 500
提交事务:exec
这个时候一旦提交事务一定会出现错误信息ERR value is not an integer or out of range,因为id
的数据不是数字,所以无法进行数字的增长。而且一旦出现了错误之后,其它的更新操作依然可以正常完成。
Redis乐观锁
在数据库执行操作的时候,为了保证数据的一致性,即:A用户更新数据的时候B用户不能够更新。所谓的锁在数据库设计上分为两种:
- 悲观锁:基于数据库的操作实现;
SELECT * FROM member WHERE mid=1 FOR UPDATE ;
- 乐观锁:基于算法的实现,在数据表上追加一个锁的处理列; 在
Redis
里面是直接支持有乐观锁的,如果要想观察乐观锁的处理,则可以打开两个不同的Session来进行处理。
1.第一个Session执行如下的操作:
设置一个数据:
set age 30
进行该数据的监听:watch age
启用事务:multi
这个时候并没有对age数据做任何的修改;
2.第二个session对数据进行修改操作:
覆盖
age
数据:set age 500
取得age
数据:get age
3.第一个session对数据修改:
修改数据:
set age 60
提交事务:exec
此时由于第二个Session
已经更新了原始的数据,那么就表示该原始数据上的一个标记列更新,这样当第一个session
再进行更新的时候会发现返回了(nil),意味着本次更新失败。
Redis密码配置
如果说你现在的Redis
没有进行认证的处理操作,那么所有的程序都可以进行连接。直接使用redis-cli
命令只需要设置上主机名称和端口号就可以进行连接处理。那么为了安全必须要设置密码。 在Redis
数据库设计的时候并没有像其它数据库那样准备了一堆复杂的密码或者权限的概念,在Redis
里面只需要设置一个认证密码就可以解决问题。
1.修改redis.conf
配置文件:vim /usr/local/redis/conf/redis.conf
,追加以下内容:
requirepass redisjava
2.随后关闭掉redis
服务并且重新启动:
- 关闭
redis
服务:killall redis-server
; - 重新启动
redis
服务:/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
;
3.登录redis
服务器:/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379
;
- 这个时候发现可以正常登录
Redis
数据库,但是一旦执行数据操作**keys ***,那么就会出现如下错误信息:
(error) NOAUTH Authentication required.
- 此时可以执行如下命令进行认证处理:
auth redisjava
;
4.直接在登录客户端的时候进行认证编写,使用一个-a的参数即可:
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a redisjava
所有的Redis
服务一定要有认证密码,而且作为Redis
集群设计的时候一定要将所有密码统一。
Redis性能监控
Redis
是作为缓存数据库使用,那么一旦在开发之中使用了Redis
,就表示有可能会大面积的去向Redis
里面保存数据,那么现在如果要想知道当前的运行状态,那么就需要对其进行监控处理,如果要进行Redis监控,必须通过其它组件完成,本次使用一个redis-stat工具实现Redis
监控操作,这个工具可以直接通过github
找到。
-
redis-stat下载地址:https://github.com/junegunn/redis-stat。
1.为了更加清楚的发现redis-stat
特点,下面建立三个Redis
运行进程,模拟方式很简单,配置不同的Redis端口即可,也就是说你需要准备出不同的redis.conf
配置文件;
2.建立redis
数据的保存目录,要求可以同时保存三个Redis
进程;
mkdir -p /usr/data/redis/{redis-6379,redis-6380,redis-6381}/{run,logs,dbcache}
3.将之前的redis.conf
配置文件拷贝一份:
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf//redis-6379.conf
4.编辑每一个配置文件,修改各自的内容,以redis-6379
为例:vim /usr/local/redis/conf/redis-6379.conf
取消外网访问限制:
# bind 127.0.0.1
设置端口:port 6379
设置pid
保存路径:pidfile /usr/data/redis/redis-6379/run/redis_6379.pid
设置日志文件路径:logfile "/usr/data/redis/redis-6379/logs/redis.log"
数据文件目录:dir /usr/data/redis/redis-6379/dbcache
5.将redis-6379.conf
复制为redis-6380.conf、redis-6381.conf
cp /usr/local/redis/conf/redis-6379.conf /usr/local/redis/conf//redis-6380.conf
cp /usr/local/redis/conf/redis-6379.conf /usr/local/redis/conf//redis-6381.conf
随后进入到每一个配置文件进行6379
内容的更新:1,$s/6379/6380/g
,1,$s/6379/6381/g
6.启动所有的Redis
服务:
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf
7.通过GITHUB
下载redis-stat
开发包:
- 如果要想使用
redis-stat
检测包必须下载ruby
相关环境:apt-get install ruby ruby-dev rubygems
; - 将该工具下载到/usr/local目录之中:
cd /usr/local/
; - 进行
redis-stat
的下载:git clone https://github.com/junegunn/redis-stat.git
;
8.下载下来的redis-stat
里面实际上只有一个执行命令:/usr/local/redis-stat/bin/redis-stat
;
- 进入到
redis-stat
所在目录:cd /usr/local/redis-stat/bin
; 如果要想使用这个命令则必须使用ruby
进行该命令的处理:gem install redis-stat
;
9.启动 redis-stat
工具进行监听控制:
/usr/local/redis-stat/bin/redis-stat 192.168.125.136:6379 192.168.125.136:6380 192.168.125.136:6381 -a redisjava

10.该工具还支持WEB启动查看,也就是说它内部自动提供有一个HttpServer
:
/usr/local/redis-stat/bin/redis-stat 192.168.125.136:6379 192.168.125.136:6380 192.168.125.136:6381 -a redisjava --server=80 --daemon --verbose
启动浏览器:http://192.168.125.136
;

11.使用redis
提供的工具来做测试:
/usr/local/redis/bin/redis-benchmark -h 192.168.125.136 -p 6379 -a redisjava -c 1000 -d 10 -n 10000
/usr/local/redis/bin/redis-benchmark -h 192.168.125.136 -p 6380 -a redisjava -c 1000 -d 10 -n 10000
/usr/local/redis/bin/redis-benchmark -h 192.168.125.136 -p 6381 -a redisjava -c 1000 -d 10 -n 10000

网友评论