Redis
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
# 操作系统:CentOS 6.8# Redis 版本:redis-3.2.5# 虚拟机网路:Nat模式
0 安装
访问或 下载对应版本的Redis。
0.1 解压
解压下载的tar包
tar -zxcf redis-3.2.5.tar.gz
安装C、C++支持
yum install -y gcc gcc-c++
进入解压后的目录中的src目录执行make && make install
命令
0.2 启动
进入解压的目录,执行redis-server
命令
使用redis-server [配置文件位置]
即可启动一个redis的数据库,命令默认为当前目录下的配置文件redis.conf
命令可以在任意目录执行,当启动时需要指定配置文件。
0.3 连接
使用redis-cli
命令即可连接已启动的redis数据库。
1 基本命令
1.1 启动命令
redis-server redis.conf 启动命令 后跟配置文件位置redis-cli -p 6379 默认端口为6379
1.2 数据库基本操作
redis-cli -p 6379 进入数据库select [num] 选择库DBSIZE 查看key数量FLUSHDB 清空当前库FLUSHALL 清空所有库默认端口6379 默认16个库
1.3 五大数数据类型
String
- 基本数据类型,一个key对应一个value
- 二进制安全,可以包含任何数据(图片或序列化对象)
- 最大值为512M
Hash
- 键值对集合
- String类型的field和value的映射表,适合存储对象
- 类似Java中的 Map<String,Object>
List
- 简单的字符串列表,按照插入顺序排序。
- 可以添加元素到头部或尾部
- 底层为链表
Set
- 无序无重复集合
- 通过底层为HashTable
Zset
- sorted set
- 每个元素关联一个double类型的分数排序
1.4 常用命令
key
keys *#查看所有keyexists [key_name]#判断key是否存在move [key_name] [db_num]#移动key到某个库expire [key_name] [时间s]#设置key过期时间 单位秒ttl [key_name]#查看过期时间type [key_name]#查看key类型
String
set/get/del/append/strlen#数据操作Incr/decr/incrby/decrby#自增自减 自增自减某值 数字getrange/setrange#设置/获取子串setex#设置过期时间sentnx#避免覆盖添加值mset/mget/msetnx#批量设置获取(重复失效)
List
Lpush/Rpush/Lrange #左右进入\查看 左栈右队 Lpop/rpop #出栈\出队 Lindex #按照索引获取 Llen #获取长度 Lren key [n] [value] #删除多个值 Ltrim key #截取子串 Rpoplpush [list_org] [list_dist] #出队压栈 Lset key index value #给某位置赋值 Linsert key befor/after "" #在某字符前/后插值
Set
sadd #不重复/重复自动去除smemebers #查看集合所有元素sismember #检测是否为成员scard #获取集合元素个数srem key value #删除元素srandmember key int #随机出N个整数spop key #随机出栈smove key1 key2 #随机出一个值给集合sdiff/sinter/sunion #差集/交集/并集
Hash
hset/hget/hmset/hmget/hgetall/hdel #获取添加移除单个/多个customer: id: 11 name: Lee age: 20hmset customer id 11 name Lee age 20hle #获取长度hexists key #获取某个keyhkeys/hvals #获取键\值hincrby/hincrbyfloat #自增某个值hstnx #避免覆盖插值
Zset
zadd/zrange #添加/查看zdd zset 1 v1 2 v2 3 v3zrangbyscore [begin_s] [end_s] #区域查看(不包含 limitzrem key #删除某个值zcard/zcount #统计个数zrank #取值的下表zscore #取值的分数zrevrank #取下标zrevrangezrevrangebyscore #结束分数到开始分数
1.5 配置文件
#守护进程方式daemonize yes#默认写入pidpidfile /var/run/redis_6379.pid#默认端口port 6379# include /path/to/other.confbind 127.0.0.1#超时关闭连接timeout 0#日志级别# Specify the server verbosity level.# This can be one of:# debug (a lot of information, useful for # development/testing)# verbose (many rarely useful info, but not a mess like the # debug level)# notice (moderately verbose, what you want in production # probably)# warning (only very important / critical messages are # logged)loglevel notice# output for logging but daemonize, logs will be sent to # /dev/nulllogfile ""#默认数据库数量databases 16#同步数据文件save#默认提供三个条件 1 in 900s 10 in 300 1000 in 60save 900 1save 300 10save 60 10000#缓存级别# volatile-lru -> Evict using approximated LRU among the # keys with an expire set.# allkeys-lru -> Evict any key using approximated LRU.# volatile-lfu -> Evict using approximated LFU among the # keys with an expire set.# allkeys-lfu -> Evict any key using approximated LFU.# volatile-random -> Remove a random key among the ones with# an expire set.# allkeys-random -> Remove a random key, any key.# volatile-ttl -> Remove the key with the nearest expire# time (minor TTL)# noeviction -> Don't evict anything, just return an error# on write operations.# maxmemory-policy noeviction#数据库路径dir ./#默认密码# requirepass foobared#默认最大连接数# maxclients 10000#最大内存# maxmemory
2 持久化
2.1 RDB(Redis Database)
在指定时间间隔内将内存中的数据集快照写入磁盘中即Snapshot快照,恢复时直接将快照导入内存。持久化由Fork进程进行,主进程不进行IO擦破做,对数据完整性不敏感,最后一次持久化的数据可能丢失。Fork为原进程的复制,所有数据与原进程完全一致,并作为原进程的子进程。保存形式为 dump.rdb配置
############### SNAPSHOTTING ############################ Save the DB on disk:## save# In the example below the behaviour will be to save:# after 900 sec (15 min) if at least 1 key changed# after 300 sec (5 min) if at least 10 keys changed# after 60 sec if at least 10000 keys changed## Note: you can disable saving completely by commenting# out all "save" lines.## It is also possible to remove all the previously # configured save# points by adding a save directive with a single empty # string argument like in the following example:# save "" #save 命令可手动保存(阻塞式) bgsave 异步不阻塞# 在设置时间内改动后自动分片存储,触发快照,备份文件自动恢复save 900 1save 300 10save 60 10000#恢复文件位置dir ./#默认恢复文件# The filename where to dump the DBdbfilename dump.rdb#数据一致性stop-writes-on-bgsave-error yes#压缩算法使用rdbcompression yes#数据校验(为增加性能可关闭 不推荐关闭)rdbchecksum yes
优点:适合大规模的数据恢复,对数据完整性和一致性要求不高
缺点:意外宕机只有最后一次快照,fork进程导致两倍程序消耗
2.2 AOF(Append Only File)
通过日志的形式记录每个写操作。
#默认关闭appendonly no#默认文件名appendfilename "appendonly.aof"# Redis supports three different modes:## no: don't fsync, just let the OS flush the data when it # wants. Faster. #不设置# always: fsync after every write to the append only log.# Slow, Safest. #总是使用# everysec: fsync only one time every second. Compromise.# The default is "everysec" #默认。appendfsync everysec#重写时运用appendsyncno-appendfsync-on-rewrite no#重写比例和重写日志大小auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb #通常3GB+
优点:每秒同步 修改同步 不同步
缺点:恢复速度慢 存储空间大
推荐使用两种共用,启动时优先载入AOF备份,AOF数据丢失不超过2秒的数据
3 事务
串行执行一组命令,命令会被序列化,不许阻塞,即一个事务。没有隔离级别的概念,不保证原子性,没有回滚,部分支持事务。
3.1 基本命令
DISCARD 放弃事务EXEC 执行事务块MULTI 标记开始UNWATCH 取消监视所有键WATCH KEY [key ...] 开启监视
3.2 事务使用步骤
MULTI //开启事务,返回OKOperationes //入队不操作,返回QUEUE,出现错误直接取消EXEC/MULTI //执行或取消执行,单个语句出错,其他可以执行
3.3 WATCH监控
悲观锁:如表级锁,当修改时加锁,其他修改无法执行(高一致,低并发)乐观锁:不锁+版本号 在修改时读取版本号,执行修改时版本号>=读取时版本CAS:即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
WATCH使用步骤
WATCH balance MULTL Operations EXEC //乐观锁已经被修改的版本将无法执行事务 //执行后锁已被清除 已被修改 --> UNWATCH取消监控 --> WATCH -->
4 发布与订阅
进程间的一种消息通信模式:发送者(pub)与订阅者(sub) 主题模式
使用命令
PSBUSCRIBE pattern[pattern ...] 订阅PUBSUB subcommand[arg [arg]] 查看订阅状态PUBLISH channel message 发布消息到主题PUNSUBSCRIBE pattern 取消订阅SUBSCRIBE channel[channel ...] 订阅多个UNSUBSCRIBE[channel[channel]] 退订多个
使用步骤
订阅消息即进入消息监听状态,消息发布时自动接收消息发布者发布消息到对应频道,消息监听处即受到消息
5 主从复制
5.1 配置方法
info replication 查看数据库信息SLAVEOF IP Port 隶属于主机
5.2 info replication
#从机role:slavemaster_host:127.0.0.1master_port:6379#主机role:masterconnected_slaves:2slave0:ip=127.0.0.1,port=6381,state=online,offset=1321,lag=0slave1:ip=127.0.0.1,port=6380,state=online,offset=1321,lag=1#主机可读可写、从机可读不可写#只需要在从机上使用命令SLAVEOF IP port 命令即可#从机可以访问所有缓存中数据 主机宕机后可重开 从机依旧 反之不行
中心化配置,主机宕机系统瘫痪,从机宕机需要重新配置,一主二从。
5.3 SLAVEOF no one
将从机转换为主机,从机需要重新配置
5.4 复制原理
首次全量复制,而后增量复制,重连全量复制。
5.5 哨兵模式
创建`sentinel.conf`配置文件,加入哨兵监视器
sentinel monitor host-main 127.0.0.1 6379 1 监视名 IP 端口 票数
命令启动:`redis-sentinel sentinel.conf`自动监视,当主机宕机自动选举主机,原主机恢复后自动设置为从机待机
缺点: 有延迟,当系统使用高时,延迟现象比较严重
6 创建集群
6.1 配置文件修改
将解压目录中的redis.conf
文件复制一份到存放集群配置文件的目录(任意目录中),并创建集群中的每一个数据库的配置文件(新建文件)。
修改配置文件中集群相关的参数,将配置设置为集群模式,以目录中的redis-6379.conf
为例如下书写。
include /opt/software/redis/cluster/configure/conf/redis.conf# 引入默认配置文件port 6379# 端口号指定dir /opt/software/redis/cluster/configure/dbdump# dump 文件目录指定dbfilename dump-6379.dump# dump文件名称指定pidfile /var/run/redis_6379.pid# 指定piddaemonize yes# 守护进程(后台运行)logfile /opt/software/redis/cluster/configure/log/redis-6379.log# 日志存放目录cluster-enabled yes# 集群开启cluster-config-file nodes-6379.conf# 集群配置文件名称cluster-node-timeout 15000# 集群超时时间
6.2 安装ruby支持
执行yum install ruby rubygems -y
安装ruby支持。
需要redis-3.2.0.gem
包,
在gem包所在目录执行gem install --local redis-3.2.0.gem
命令
6.3 启动集群
6.3.1 启动redis
redis-server /opt/software/redis/cluster/configure/conf/redis-6379.confredis-server /opt/software/redis/cluster/configure/conf/redis-6380.confredis-server /opt/software/redis/cluster/configure/conf/redis-6381.confredis-server /opt/software/redis/cluster/configure/conf/redis-6389.confredis-server /opt/software/redis/cluster/configure/conf/redis-6390.confredis-server /opt/software/redis/cluster/configure/conf/redis-6391.conf
6.3.2 查看启动
所有启动中的服务均为cluster即启动成功
6.3.3 组成集群
进入redis解压目录中的src文件夹,执行命令
./redis-trib.rb create --replicas 1 192.168.111.3:6379 192.168.111.3:6380 192.168.111.3:6381 192.168.111.3:6389 192.168.111.3:6390 192.168.111.3:6391
出现下图即创建成功。
redis-cli -c ...
注意连接时需要添加一个-c
参数。
7 Java中使用
Jedis jedis = new Jedis(url,port);//事务Transaction transaction = jedis.multi();transaction.set(); ...transaction.discard(); //取消执行//开启watchint now;jedis.watch("key");int value = Integer.paraseInt(jedis.get("key"));if(value < now){ jedis.unwatch(); soutp("redo"); return false}else{ Transaction tr = jedis.multi(); transaction.method("",""); transaction.exex()}jedis.unwatch();//主从复制Jedis jedis_master = new Jedis(url,port);Jedis jedis_salve = new Jedis(url,port);//主从复制 读写分离jedis_salve.slaveof(url,port);jedis_master.set(...);String result = jedis_salve.get(...);//JedisPoolpublic class JedisPoolUtil{ private static volatile JedisPool jedisPool = null; private JedisPoolUtrl(){} public static JedisPool getJedisPoolInstance() { if(null == jedisPool) { synchronized (JedisPoolUtil.class) { if(null == jedisPool) { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.set(...); jedisPool = new JedisPool(poolConfig,url,port); return JedisPool; } } } } public static voie relase(JedisPool jedisPool,Jedis jedis) { if(null != jedis) { jedisPool.returnResourceObject(jedis); } }}