Redis数据库个人学习笔记

简介

AUTOBEAR的NOSQL型数据库的个人学习笔记,本笔记随时增添,用来巩固知识,查缺补漏。

基础概念

BSD协议:BSD开源免费、而且允许自由使用,修改源代码,无版权问题,比如LINUX也是。
NOSQL数据库:泛指区别于关系型数据库的非关系型数据库。

NOSQL为什么兴起 (解决大数据的难题):
网站和用户做数据交互,超大规模和高并发的SNS类型的WEB2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题:
1.High performance 高并发读写的需求。
2.Huge Storage 对海量数据的高效率存储和访问的需求。
3.High Scalability && High Availability 对数据高可拓展性和高可用性的需求。

Redis:远程字典服务器Remote Dictionary Server,是一个高性能的key-value存储系统
特点:键值存储,哈希表,简单易部署,但是如果只对部分值进行查询更新就比较效率低下。
典型应用:内容缓存、处理大数据的高访问负载。数据缺少结构化。
优势:查询速度快。每秒10万级别的读存速度。

与其他KV缓存产品的区别:
1.支持数据持久化
2.不仅仅支持简单的KV类型数据,还提供list/set/zset/hash等数据结构的存储
3.支持数据的备份,即master-slave模式的数据备份

CAP原则:
C:consistency一致性
A:availablity可用性
P:partition tolerance分区容错性,是指系统能够容忍节点之间的网络通信的故障。
指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

CA-传统数据库
AP-大多数网站架构
CP-非关系型数据库

比如说,Redis的架构是分布式的,现实世界中网络通信故障必然存在,因此必须满足分区容错性,否则就无法顺畅工作。在满足P的基础上网络故障时,追求一致性就会导致不可用,反之如果想做到高可用就只能牺牲一致性,CA不能共存,最后选择一致性放弃一部分可用率,所以最后Redis就满足CP,放弃了A。
手册链接:
https://redis.io/
www.redis.cn
https://www.runoob.com/redis/redis-tutorial.html

基础语法

安装命令:redis-server.exe --service-install redis.windows.conf --loglevel verbose

启动服务命令:redis-server.exe  --service-start

关闭服务命令:redis-server.exe  --service-stop   / shutdown

登陆服务命令:redis-cli.exe -h 127.0.0.1 -p 6379

进行压力测试:redis-benchmark.exe

DB

查看数据库个数:config get databases ,默认16个
切换数据库: select 0-15
数据库内键值对数 :dbsize  
查看所有键名:keys * 
删全部库和删单库:flushall/flushdb

KEY

关于set的使用http://doc.redisfans.com/string/set.html其中解释到:

SET key value [EX seconds] [PX milliseconds] [NX|XX]
1.EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
2.PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
3.NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
4.XX :只在键已经存在时,才对键进行设置操作。

因为 SET 命令可以通过参数来实现和 SETNX 、 SETEX 和 PSETEX 三个命令的效果,所以将来的 Redis 版本可能会废弃并最终移除 SETNX 、 SETEX 和 PSETEX 这三个命令。

增改:set key value
查:get key 
删:del key  
查看是否存在:exists key 
给key设置过期时间:expire key 10
查看键值生命ttl key
把key移动到别的库里:move key 0-15 
查看值类型:type key 

String

字符串拼接:append  KEY NEWVALUE
字符串长度:strlen KEY
自增1和带步数的:incr/incrby 10 
自减1和带步数的:decr/decrby 10 
得到k1全部字符 :getrange k1 0 -1 
得到k1,0-2字符:getrange k1 0 2  
范围内设值:setrange k1 0 xxx 
如果存在if exist设置生命为10秒:setex key 10 v123
如果不存在if not exist才设值:setnx key v123
多个键值做操作:mset/msetne/mget k1 k2 k3 k4 (遵从原子性,不会部分成功的。)

List链表

左插入:lpush list value
右边插入:rpush list value
从左往右遍历:lrange
左右栈顶出栈:lpop/rpop
使用脚标获取元素:lindex
链表长度:llen
删除指定个数的指定元素:lrem key count value
右出左入可是是同一链表也可以不是:rpoplpush  list1 list2
指定脚标元素设值:lset key index value 
在指定元素(最左边的一个v1)前后插入元素:linsert key before/after v1 v2 

Set无序集合(元素不可重复)

添加元素:sadd
获取全部元素:smembers
是否存在:sismember
获取元素个数:scard 
删除集合中的元素:srem key value 
随机出3个元素:srandmember key 3  
随机出栈:spop key 
移动元素:smove key1 key2  
数学集合:
差集:sdiff   交集:sinter   并集:sunion

Hash哈希(field不可重复)

添加元素:hset/hsetnx key field value 
是否存在:hexists key field
散列长度:hlen  key 
查:hget key field
多设置多查询:hmset/hmget
获得全部键值对:hgetall
删除:hdel key field 
获取全部键或值:hkeys/hvals
元素自增:hincrbt/hincrbyfloat

Zset(sorted set有序集合,通过score自动排序,score可重复)

添加元素:zadd zset01 60 v1 70 v2 80 v3 90 v4 100 v5
获取指定范围元素:zrange zset01 0 -1 (withscores)   //zrevrange zset01 0 -1 逆向拿
获取指定score范围元素:
zrangebyscore zset01 60 90
zrangebyscore zset01 (60 (90    60<x<90
zrangebyscore zset01 limit 2 2  分页
删除元素:zrem zset01 v5
统计个数:zcard zset01  
统计区间个数:zcount zset01 60 80 
获取下标 zrank zset01 v4  
逆向获取下标:zrevrank zset01 v4 
获取分数 :zscore zset01 v4 

配置项

daemonized daemonize设置成yes时,代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程。Windows系统的Redis没有此项。

日志级别从多到少:
1.debug
2.vervose
3.notice
4.warning

查看默认密码:config get requirepass
密码设置:config set requirepass "123456"
命令:auth + 密码 进行安全校验,登陆。
在config文件中修改requirepass ,去掉注释的#,把foobared替换成自己的密码即可

5种清理缓存策略 config set maxmemory-policy volatile-lru
volatile-lru:只对设置了过期时间的key进行LRU(默认值)
allkeys-lru : 删除lru算法的key
volatile-random:随机删除即将过期key
allkeys-random:随机删除
volatile-ttl : 删除即将过期的
noeviction : 永不过期,返回错误
建议使用默认值
相关政策:https://www.jianshu.com/p/ca7e15348323

持久化

由于Redis是干内存的,因此关闭进程后内存释放数据丢失,所以需要进行持久化到磁盘。

RDB:在指定间隔时间内将内存中的数据Snapshot快照写入磁盘

REDIS会单独创建(fork)一个子进程来进行持久化,只在子进程和临时文件上做IO操作,不影响主进程。好处就是保障高可用,坏处就是需要额外的一份内存和CPU占用。
适合进行大规模数据恢复,高效但是有可能丢失最后一次持久化后的数据。
保存为dump.rdb文件,具体可以在配置文件中修改。
命令:save/bgsave(后台异步进行快照操作)进行手动保存。lastsave获得最后一次快照时间。

AOF:以日志形式记录每一个写操作。

重启时把AOF文件执行一遍,比较低效。
AOF和RDB同时存在时,优先进行AOF数据恢复。
使用redis-check-aof 的 --fix 进行AOF文件修复
重写机制,AOF文件命令压缩,只保留可以恢复数据的最小指令集,可以使用bgrewriteaof命令进行。
默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。
AOF策略:每秒同步、每修改同步、不同步。
优势:数据保存得比较完整、恢复日志可读性高
劣势:运行效率慢

事务

multi  //开启事务
语句1
QUEUED
语句2
QUEUED
.
.
.
EXEC提交执行  DISCARD取消事务

事务中语句出错,全错。抛异常时,部分错。不保证原子性。

WATCH监控,加锁,有加塞的情况操作被打断。UNWATCH释放锁。
一旦执行EXEC之前的监控锁都失效。

悲观锁:其他操作拿数据时block直到它拿到锁,行表锁,读写锁,都是在别人操作前加锁。

乐观锁:不上锁,使用版本号机制,只能对上一版本号的数据做写操作。适用于多读的应用类型。

发布和订阅

一般用MQ做消息中间件,Redis虽然有这个功能但是不常见。
进程间的一种消息通信模式,pub发送、sub接收。
subscribe订阅 ,publish发布
一般可以利用java端口监听订阅redis事件,从而对达到定时中断的效果。
详细见:https://www.cnblogs.com/chen-lhx/p/6626371.html
1.订阅 subscribe keyevent@0:expired 通道
2.配置config set notify-keyspace-events Ex
当一个key生命周期结束就会向订阅者发送一条消息,从而模仿定时器。

主从复制

修改conf文件:开启守护进程daemonize=yes,pid号指定名字,指定port,log文件重命名,dump.rdb重命名
指令:1.SLAVEOF IP PORT 2.SLAVEOF NO ONE 3.查看主从关系info replication

配置哨兵模式:
1.新建sentinel.conf
2.修改文件内容:sentinel monitor <master-name> <ip> <redis-port> <quorum>
告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效。master-name只能包含英文字母,数字,和“-“这三个字符需要注意的是master-ip 要写真实的ip地址而不要用回环地址(127.0.0.1)。
3.启动哨兵:
sentinel monitor mymaster 192.168.0.5 6379 2
redis-sentinel ../sentinel.conf开启监控

这里有一个需要注意的地方是:

尽量把启动顺序调整为:1+2+3的模式。
也就是先启动主(master)接着启动两个从(slave),并且使用SLAVEOF把他们连接起来形成一主二从的局势。
接着修改哨兵配置文件,使得每个哨兵都去监视主(master),然后启动。
这个时三个哨兵都在主这里,当主死亡,哨兵群会另立新主,在此之后第一任主人回来后也只是普通公民了。

Jedis连接池

使用单例模式创建一个Redis连接工具类,依赖包:Jedis + commons-pool2 + slf4j-api
代码:


import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolUtil {
    private static volatile JedisPool jedisPool =null;
    private JedisPoolUtil() {}
    public static JedisPool getJedisPollInstance() {
        if(null==jedisPool) {
            synchronized (JedisPoolUtil.class) {
                if(null==jedisPool) {
                    JedisPoolConfig config=new JedisPoolConfig();
                    config.setMaxTotal(1000);
                    config.setMaxIdle(32);
                    config.setMaxWaitMillis(10*1000);
                    config.setTestOnBorrow(true);
                    jedisPool=new JedisPool(config,"127.0.0.1",6379);
                }
            }
        }
        return jedisPool;
    }
    public static void release(Jedis jedis) {
        if(null!=jedis) {
            jedis.quit();
            jedis.close();
        }
        
    }
}

Jedis2.9以上版本禁用了returnResourceObject()方法,因此返还连接到连接池时应该直接quite+close,close方法内有自动释放连接到连接池的代码机制,请勿关闭连接池。

相关链接:
https://www.jianshu.com/p/b9154316227e

Windows端Redis集群以及哨兵的部署

第一步

到Redis官网中下载压缩包,解压缩后得到一个文件夹。

第二步

我们可以用一台电脑模拟一个集群的情况,但是生产环节建议还是把Redis服务和哨兵服务分别部署到三台机器上面。
复制并修改第一部的文件夹为6379,6380,6381三个文件夹。

第三步

分别修改配置文件。
redis.windows.conf(这里只列出需要修改的字段)

port 6379     port 6380     port 6381
如果需要密码:
 修改 requirepass foobared 这个字段,三台应该保持一致
 提起决定主从关系
 slaveof <masterip> 6379
 masterauth <master-password>

接着修改sentinel.conf文件

# 这个是Redis6379配置内容,其他文件同理新增然后改一下端口即可,26380,和 26381。
#当前Sentinel服务运行的端口
port 26379  port 26380  port 26381
# 哨兵监听的主服务器 
sentinel monitor mymaster <masterip> 6379 2
# 3s内mymaster无响应,则认为mymaster宕机了
sentinel down-after-milliseconds mymaster 2000
#如果10秒后,mysater仍没启动过来,则启动failover  
sentinel failover-timeout mymaster 10000  
# 执行故障转移时, 最多有1个从服务器同时对新的主服务器进行同步
sentinel parallel-syncs mymaster 1

这里有一个坑需要注意,sentinel.conf文件在启动后# Generated by CONFIG REWRITE下面会跟上一堆指令,这些是程序自动生成的,如果你的配置文件是迁移过来的需要把这些删除清空,因为他就像缓存一样会影响你的运行(笔者最近在生产环境部署的时候就出现过,下面专门开一个章节讲一下)。
然后为了启动方便需要写一下启动脚本Linux端是shell脚本,Windows就是bat文件。
startRedisServer

@echo off
redis-server.exe redis.windows.conf
@pause

startRedisSentinel.bat

@echo off
redis-server.exe sentinel.conf --sentinel 
@pause

分别放到三个文件夹内。

第四步

1.双击startRedisServer.bat三个,启动Redis服务。
2.决定主从关系,登陆从服务,进行SLAVEOF指令。
3.双击startRedisSentinel.bat三个,启动哨兵服务。
至此,一个(一主二从的Redis带有哨兵的集群就部署好了)

Linux端Redis集群以及哨兵的部署

Linux端的部署方法与Windows端的类似,配置文件也大同小异。
只是哨兵部署指令可以学习一下:

nohup ./redis-sentinel ../conf/sentinel.conf >../logs/sentinel.log 2>&1 &
这个指令的意思是启动哨兵服务并使得哨兵服务在后台挂起运行,运行日志打在../logs/sentinel.log里面

Redis异常情况排查

这个环节就是积累环节,以后会经常更新。

sentinel.conf文件未清空脏数据导致的哨兵失效

前面说,sentinel.conf文件在启动后# Generated by CONFIG REWRITE下面会跟上一堆指令,这些是程序自动生成的,如果没有清空这些脏数据,那么如果配有别的known-sentinel这个时候在哨兵里面执行info sentinel指令时会看到master的sentinel数量大于3。
Q:要怎么知道是不是有除了自己部署的哨兵以外的哨兵在监视自己的服务呢?
A:我们知道,哨兵会定时地向master的“sentinel:hello”通道发(192.168.253.128,26380,f045caf25980a8d0b9e88a4bfaa7e2f700a9f0e0,1,mymaster,192.168.253.128,6381,1)数据。这个时候我们就知道,哦,有一个26380端口的哨兵在通道里公布master是6381。有两种办法可以得到这条数据,一个方法就是订阅这个通达,另一个指令就是执行MONITOR指令(他可以实时打印出服务的数据交互情况)。
确认完实际哨兵数,再看INFO SENTINEL的哨兵数就可以判断是不是真的有问题了。
所以建议还是要对Redis服务加密码,避免其它哨兵加入导致公民投票大会的混乱发生。

Springboot中Redis配置

这里推荐使用REDISSON客户端组件,他们的网站是:https://github.com/redisson
以哨兵配置为例:
首先使用IOC容器注入客户端

@Configuration
public class RedissonConfig  {
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() throws IOException {
        // 本例子使用的是yaml格式的配置文件,读取使用Config.fromYAML,如果是Json文件,则使用Config.fromJSON
        Config config = Config.fromYAML(
        RedissonConfig.class.getClassLoader().getResource("redisson-config.yml"));
        return Redisson.create(config);
    }
}

并在redisson-config.yml文件中配置

sentinelServersConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  password: null
  subscriptionsPerConnection: 5
  clientName: null
  loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
  slaveSubscriptionConnectionMinimumIdleSize: 1
  slaveSubscriptionConnectionPoolSize: 50
  slaveConnectionMinimumIdleSize: 32
  slaveConnectionPoolSize: 64
  masterConnectionMinimumIdleSize: 32
  masterConnectionPoolSize: 64
  readMode: "SLAVE"
  sentinelAddresses:
  - "redis://127.0.0.1:26379"
  - "redis://127.0.0.1:26380"
  - "redis://127.0.0.1:26381"
  masterName: "master"
  database: 0
threads: 0
nettyThreads: 0
codec:
  class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"

并在服务中直接使用
@Autowired
RedissonClient redisson;
注入Redisson客户端。
当然他的缺陷也是有的,就是集成度太高,有些指令不好做。

关于危险命令

https://blog.csdn.net/elesos/article/details/81280291

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352