Redis

1.redis的安装

Redis的安装分为windows版和linux版

windows直接下载安装包即可

linux安装如下:

第一步:下载redis安装包

node01服务器执行以下命令下载redis安装包

cd /export/softwares

wget http://download.redis.io/releases/redis-3.2.8.tar.gz

第二步:解压redis压缩包到指定目录

node01执行以下命令进行解压redis

cd /export/softwares

tar -zxvf redis-3.2.8.tar.gz -C ../servers/

第三步安装C程序运行环境

node01执行以下命令安装C程序运行环境

yum -y install gcc-c++

第四步:安装较新版本的tcl

下载安装较新版本的tcl

第一种方式:使用压缩包进行安装

node01执行以下命令下载tcl安装包

cd /export/softwares

wget Download tcl8.6.1-src.tar.gz (Tcl)

解压tcl

tar -zxvf tcl8.6.1-src.tar.gz -C ../servers/

进入指定目录

cd ../servers/tcl8.6.1/unix/

./configure

make  && make  install

第二种方式在线安装tcl

node01执行以下命令在线安装tcl

yum  -y  install  tcl

第五步:进行编译redis

node01执行以下命令进行编译:

cd /export/servers/redis-3.2.8/

make MALLOC=libc   或者使用命令  make  进行编译

make test && make install

第六步:修改redis配置文件

node01执行以下命令修改redis配置文件

cd /export/servers/redis-3.2.8/

mkdir -p /export/servers/redis-3.2.8/logs

mkdir -p /export/servers/redis-3.2.8/redisdata

vim redis.conf

bind node01

daemonize yes

pidfile /var/run/redis_6379.pid

logfile "/export/servers/redis-3.2.8/logs/redis.log"

dir /export/servers/redis-3.2.8/redisdata

第七步:启动redis

node01执行以下命令启动redis

cd  /export/servers/redis-3.2.8/

src/redis-server 

可以使用grep查看一下

ps -ef | grep redis

第八步:连接redis客户端

node01执行以下命令连接redis客户端

cd /export/servers/redis-3.2.8/src

redis-cli -h node01

2.redis的数据类型

redis当中一共支持五种数据类型,分别是string字符串类型,list列表类型,集合set类型,hash表类型以及有序集合zset类型,通过这五种不同的数据类型,我们可以实现各种不同的功能,也可以应用与各种不同的场景,

Redis_第1张图片

redis的各种数据类型结构如上图:

Redis_第2张图片

2.1  redis当中对字符串string的操作

SETkey value 设置指定key值 set hello world
get key 获取指定key值 get hello
getrange key start end

返回key中字符串的子字符

getrange hello 0 3
getset key value 将给定的key的值设置为value 并返回key的旧值(old value) getset hello world2
mget key1 key2 获取一个或多个key值 mget hello hello2
setex key seconds value 将值value关联到key,并将key的过期时间设定为seconds(以秒为单位) setex hello 10 world3
setnx key value 只有key不存在时设置key的值 setnx itcast redisvalue

setrange key offset value

用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始

setrange itcast 0 hello redis 
strlen key 返回key所储存的字符串值长度 strlen itcast
mset key value [key value]

同时设置一个或多个 key-value 对。

mset hello world[hello1 world1]
msetnx key value[]key value

同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。

msetnx hello world[hello1 world1]
psetex key millisconds value

这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。

pset itcast6 6000 itcast6value
incr key 将key中储存的数字值增一

set itcast7 1

incr itcast7

incrby key increment 将key 所存储的值加上给定的增量(increment) increby itcast7 2
incrbyfloat key increment

将 key 所储存的值加上给定的浮点增量值(increment)

incrbyfloat itcast7 0.5
decr key

将 key 中储存的数字值减一

set itcast8 2

decr itcast8

decrby key increment 将key 所存储的值减去给定的增量(increment) decreby itcast7 2
append key value

如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。

append itcast8 hello

2.2  redis当中对hash列表的操作 

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。

hset key field value

将哈希表 key 中的字段 field 的值设为 value 。

hset key1 field1 value1

hsetnx key field value

只有在字段 field 不存在时,设置哈希表字段的值。

hsetnx key1 field1 value1

hmset key field1 value1 [field2 value2]

同时将多个 field-value (域-值)对设置到哈希表 key 中。

hmset key1 field1 value1 field2 value2
hexists key field  查看哈希表key中,指定字段是否存在 hexists key1 field1
hget key field 

获取存储在哈希表中指定字段的值。

hget key1 field1
hgetall key 获取在哈希表中指定key的所有字段和值 hgetall key1
hkeys key  获取所有哈希表中的字段 hkeys key1
hlen key  获取哈希表中字段的数量 hlen key1
hmet key field[field2] 获取所有给定字段的值 hmget key1 field1 field2
hincrby key field increment

为哈希表 key 中的指定字段的整数值加上增量 increment 。

hset key2 field1 1

hincrby key2 field1 1

hget key2 field1

hincrbyfloat key field increment

为哈希表 key 中的指定字段的浮点数值加上增量 increment

hincrbyfloat key2 field1 0.5
hvals key 获取哈希表中所有值 hvals key1
hdel key field1[field2] 删除一个或多个哈希表字段

hdel key1 field1 

hvals key1

2.3redis当中对list列表的操作

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

lpush key value1[value2 ] 将一个或多个值插入到列表头部 lpush list1 value1 value2
lrange key start stop

查看list当中所有的数据

lrange list 0 1
lpush key value

将一个值插入到已存在的列表头部

lpush list1 value3
rpush key value1 [value2] 在列表尾部添加一个值或多个值 lpush list1 value3
rpushx key value 为已存在的列表添加值

rpushx list1 value6

linsert key before/after  value 在列表的元素前或者后插入元素 linsert list1 before value3 beforevalue3
lindex key index 通过索引获取列表的元素(索引从0开始) lindex list1 2
lset key index value 通过索引设置列表元素的值(覆盖) lset list1 0 hello
llen key 获取列表长度 llen list1
lpop key 移除并获取列表的第一个元素

lpop list1

rpop key 移除并获取列表的第一个元素 rpop list1
blpop key1[key2] timeout

移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

blpop list1 2000

rpoplpush key1 key2

移除列表的最后一个元素,并将该元素添加到另一个列表并返回

rpoplpush list1 list2
brpoplpush key1 key2 timeout

从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

brpoplpush list1 list2 2000
ltrim key start stop

对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除

ltrim list1 0 2

del key1 key2

删除指定key的列表 del list1

4redis操作set集合

redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
 

sadd keymember1 [member2] 向集合中添加一个或多个成员 sadd set1 setvalue1 setvalue2
smembers key 返回集合中的所有元素 smembers set1
scard key 获取集合的成员数 scard set1

sdiff key1 [key2]

返回给定集合的差集 sdiff set1 set2
sdiffstore destination key1[key2] 返回给定所有集合的差集并存储在destination中 sdiffstore set3 set1 set2
sinter key1 [key2] 返回给定所有集合的交集 sinter set1 set2
sinterstore destination key1[key2] 返回给定所有集合的交集并存储在destination中 sinterstore set4 set1 set2
sismember key member

判断 member 元素是否是集合 key 的成员

sismember set1 setvalue1
smove source distination member 将member元素从source集合移动到distination smove set1 set2 setvalue1
spop key 移除并返回集合中一个随机元素 spop set2
srandmember key [count]  返回集合中一个或多个随机数 srandmember set2 2
srem key member1 [member2] 移除集合中一个或多个成员 srem set2 setvalue1
sunion key1[key2] 返回所有给定集合的并集 sunion set1 set2
sunionstore destination key1 [key2] 所有给定结合的并集存储在destination集合中 sunionstore set2 set1 set2

5、redis中对key的操作

del key 

该命令用于在 key 存在时删除 key。

del itcast5
dump key 序列化给定key,并返回序列化的值 dump key1
exists key 检查给定key是否存在 exists key1 
expire key  second 为给定key设定过期时间,以秒计 expire itcast5
pexpire key milliseconds 设置key的过期时间以毫秒计 pexpire set2 300000
keys pattern

查找所有符合给定模式( pattern)的 key

keys *

persist key

移除 key 的过期时间,key 将持久保持。

persist set2
pttl key

以毫秒为单位返回 key 的剩余的过期时间

pttl set2
ttl key

以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。

ttl set2
randomkey

从当前数据库中随机返回一个 key 。

randomkey
rename key newkey 修改key的名字 rename set5 set6
renamenx key newkey

仅当 newkey 不存在时,将 key 改名为 newkey

renamenx set8 set10

type key 返回key所存储的值的类型 type set10

3.redis的持久化

由于redis是一个内存数据库,所有的数据都是保存在内存当中的,内存当中的数据极易丢失,所以redis的数据持久化就显得尤为重要,在redis当中 ,提供了两种数据持久化的方法,分别为RDB和AOF且redis默认开启的数据持久化方式为RDB方式,

1、RDB持久化方案

Redis会定期保存数据快照至一个rdb文件中,并且启动时自动加载rdb文件,恢复之前保存的数据。可以在配置文件中配置redis进行快照保存的时机

修改redis的配置文件

vim redis.conf

save 900 1
save 300 10
save 60 10000
save 5 1

2、AOF持久化方案

采用AOF持久化的时候,Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录 的所有写操作顺序执行一遍,确保数据恢复到最新。AOF默认是关闭的,如果要开启,要进行以下配置

appendonly yes

AOF提供了三种fsync配置,always/everysec/no,通过配置项[appendfsync]指定:

appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢

appendfsync everysec:折中的做法,交由后台线程每秒fsync一次

配置redis的AOF持久化机制方式:

vim redis.conf

appendonly yes
# appendfsync always
appendfsync everysec
# appendfsync no

2、redis集群环境搭建

由于redis集群当中最少需要三个主节点,每个主节点,最少需要一个对应的从节点,所以搭建redis集群最少需要三主三从的配置,所以redis集群最少需要6台redis的实例,我们这里使用三台机器,每台服务器上面运行两个redis的实例。我们这里使用node01服务器,通过配置不同的端口,实现redis集群的环境搭建

第一步node01服务器解压redis压缩包

node01执行以下命令重新解压redis压缩包到/export路径下

cd /export/softwares/

tar -zxf redis-5.0.8.tar.gz -C /export/

yum -y install gcc-c++ tcl

第二步安装redis必须依赖环境并进行编译

可以创建软连接方便使用,并配置环境变量、

# node01, 编译、安装、创建软连接

# 进入源码目录

cd /export/server/redis-5.0.8

# 编译

make

# 安装至指定目录

make PREFIX=/export/server/redis-5.0.8-bin install

# 创建安装目录软连接

cd /export/server

ln -s redis-5.0.8-bin redis

配置环境变量(如果以前安装过Redis,配置过环境变量,就不用配置)。

# 配置环境变量

vim /etc/profile

# ======================== 添加如下内容 ========================

    # REDIS HOME

export REDIS_HOME=/export/server/redis

export PATH=:$PATH:$REDIS_HOME/bin

# 执行生效

source /etc/profile

 第三步,拷贝配置文件

从Redis-5.0.8源码目录下拷贝配置文件:redis.conf至Redis 安装目录。

# ====================== node01 上操作 ======================

# 拷贝配置文件

cd /export/server/redis-5.0.8

cp redis.conf /export/server/redis

  1. 修改配置文件

每台机器上启动2个Redis服务,一个主节点服务:7001,一个从节点服务:7002,如下图所示:

在Redis安装目录下创建7001和7002目录,分别存储Redis服务配置文件、日志及数据文件。

# 创建目录:7001和7002

cd /export/server/redis

mkdir -p 7001 7002

拷贝配置文件:redis.conf至7001目录,并重命名为redis_7001.conf

cd /export/server/redis

cp redis.conf 7001/redis_7001.conf

编辑配置文件:redis_7001.conf,内容如下:

cd /export/server/redis/7001

vim redis_7001.conf

## =========================== 修改内容说明如下 ===========================

## 69行,配置redis服务器接受链接的网卡

bind 0.0.0.0

## 88行,关闭保护模式

protected-mode no

## 92行,设置端口号

port 7001

## 136行,redis后台运行

daemonize yes

## 158行,Redis服务进程PID存储文件名称

pidfile /var/run/redis_7001.pid

## 171行,设置redis服务日志存储路径

logfile "/export/server/redis-5.0.8-bin/7001/log/redis.log"

## 263行,设置redis持久化数据存储目录

dir /export/server/redis-5.0.8-bin/7001/data/

## 699行,启动AOF方式持久化

appendonly yes

## 832行,启动Redis Cluster

cluster-enabled yes

## 840行,Redis服务配置保存文件名称

cluster-config-file nodes-7001.conf

## 847行,超时时间

cluster-node-timeout 15000

创建日志目录和数据目录:

mkdir -p /export/server/redis/7001/log

mkdir -p /export/server/redis/7001/data

配置7002端口号启动Redis服务,操作命令如下:

## 拷贝配置文件

cd /export/server/redis

cp 7001/redis_7001.conf 7002/redis_7002.conf

## 修改配置文件:redis_7002.conf

cd /export/server/redis/7002

vim redis_7002.conf

# 进入vim编辑之后,执行以下代码将7001全部替换成7002

:%s/7001/7002/g   # 表示:%s/old/new/g  g表示全部替换

# 创建目录

mkdir -p /export/server/redis/7002/log

mkdir -p /export/server/redis/7002/data

 2.发送安装包

将node01上配置好的Redis安装包,发送至node02,node03,每台机器运行2个Redis服务,端口号分别为7001和7002,具体命令如下:

# 发送安装包

cd /export/server

scp -r redis-5.0.8-bin [email protected]:$PWD

scp -r redis-5.0.8-bin [email protected]:$PWD

# 在node2和node3创建软连接

cd /export/server

ln -s redis-5.0.8-bin redis

# 配置环境变量

vim /etc/profile

# ======================== 添加如下内容 ========================

    # REDIS HOME

export REDIS_HOME=/export/server/redis

export PATH=:$PATH:$REDIS_HOME/bin

# 执行生效

source /etc/profile

第四步 启动Redis服务

 

在三台机器node01、node02和node03,分别启动6个Redis服务,命令如下:

# 启动7001端口Redis服务

/export/server/redis/bin/redis-server /export/server/redis/7001/redis_7001.conf

# 启动7002端口Redis服务

/export/server/redis/bin/redis-server /export/server/redis/7002/redis_7002.conf

启动完成后用ps -ef | grep redis

  Redis_第3张图片

第五步  启动集群 

Redis5.x版本之后,通过redis-cli客户端命令来进行创建集群,注意:Redis对主机名解析不友好,使用IP地址

# 任意选择一台机器执行如下命令,创建集群

redis-cli -a 123456 --cluster create 192.168.23.100:7001 192.168.23.100:7002 192.168.23.110:7001 192.168.23.120:7002 192.168.23.120:7001 192.168.23.120:7002  --cluster-replicas 1

成功如下:

Redis_第4张图片 

第六步  测试集群 

在任意一台机器,使用redis-cli客户端命令连接Redis服务:

redis-cli -c -h node01 -p 7001 -a 123456

第七步 编写脚本方便启动和关闭集群

编写脚本,方便启动和关闭Redis集群:redis-cluster-start.shredis-cluster-stop.sh

  1.  进入Redis安装目录中bin目录,创建脚本文件

cd /export/server/redis-5.0.8-bin/bin/

touch redis-cluster-start.sh

touch redis-cluster-stop.sh

# 给以执行权限

chmod u+x redis-cluster-start.sh

chmod u+x redis-cluster-stop.sh

  1.  启动集群:redis-cluster-start.sh

vim redis-cluster-start.sh

#!/bin/bash

REDIS_HOME=/export/server/redis

# Start Server

## node1.itcast.cn

ssh node1.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7001/redis_7001.conf"

ssh node1.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7002/redis_7002.conf"

## node02

ssh node2.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7001/redis_7001.conf"

ssh node2.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7002/redis_7002.conf"

## node03

ssh node3.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7001/redis_7001.conf"

ssh node3.itcast.cn "${REDIS_HOME}/bin/redis-server /export/server/redis/7002/redis_7002.conf"

  1.  关闭集群:redis-cluster-stop.sh

vim redis-cluster-stop.sh

#!/bin/bash

REDIS_HOME=/export/server/redis

# Stop Server

## node01

${REDIS_HOME}/bin/redis-cli -h node1.itcast.cn -p 7001 -a 123456 SHUTDOWN

${REDIS_HOME}/bin/redis-cli -h node1.itcast.cn -p 7002 -a 123456 SHUTDOWN

## node02

${REDIS_HOME}/bin/redis-cli -h node2.itcast.cn -p 7001 -a 123456 SHUTDOWN

${REDIS_HOME}/bin/redis-cli -h node2.itcast.cn -p 7002 -a 123456 SHUTDOWN

## node03

${REDIS_HOME}/bin/redis-cli -h node3.itcast.cn -p 7001 -a 123456 SHUTDOWN

${REDIS_HOME}/bin/redis-cli -h node3.itcast.cn -p 7002 -a 123456 SHUTDOWN

第八步  Redis Cluster 管理

在实际项目中可能由于Redis Cluster中节点宕机或者增加新节点,需要操作命令管理,主要操作如下。

Redis_第5张图片

JavaApi操作redis集群

连接Redis集群,需要使用JedisCluster来获取Redis连接。

实现步骤:

  1. 在cn.itcast.redis.api_test包下创建一个新的类:RedisClusterTest
  2. 创建一个HashSet,用于保存集群中所有节点的机器名和端口号
  3. 创建JedisPoolConfig对象,用于配置Redis连接池配置
  4. 创建JedisCluster对象
  5. 使用JedisCluster对象设置一个key,然后获取key对应的值
    Redis_第6张图片

 

Redis集群面试题

从Redis 3.0发布提供Redis Cluster以后,经历Redis 4.x、Redis5.x和Redis 6.x一系列版本,Redis Cluster更加成熟、稳定,推荐企业使用此种架构,通常公司也是使用此种架构。如果使用Redis Cluster集群,面试中碰到的问题有一些坑,还望注意。

  1.  问题一:Redis的多数据库机制,了解多少?
    Redis_第7张图片
  2.  问题二:懂Redis的批量操作么?
  3. 问题三:Redis集群机制中,你觉得有什么不足的地方吗?
  4.  问题四:在Redis集群模式下,如何进行批量操作
    Redis_第8张图片
  5.  问题五:懂Redis事务么?
    Redis_第9张图片


    Redis高频面试题

在应用程序和MySQL数据库中建立一个中间层:Redis缓存,通过Redis缓存可以有效减少查询数据库的时间消耗,但是引入redis又有可能出现缓存穿透、缓存击穿、缓存雪崩等问题。

Redis_第10张图片

缓存穿透

缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。

一言以蔽之:查询Key,缓存和数据源都没有,频繁查询数据源

比如用一个不存在的用户id获取用户信息,无论论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决缓存穿透的方案主要有两种:

  1.  方案一:当查询不存在时,也将结果保存在缓存中。但是这可能会存在一种问题:大量没有查询结果的请求保存在缓存中,这时我们就可以将这些请求的key设置得更短一些;
  2.  方案二:提前过滤掉不合法的请求,可以使用Redis中布隆过滤器
      1. 缓存击穿

缓存击穿:key对应的数据库存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

一言以蔽之:查询Key,缓存过期,大量并发,频繁查询数据源

业界比较常用的做法:使用互斥锁。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db(查询数据库),而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,就是只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据。

String get(String key) {  
   String value = redis.get(key);  
   if (value  == null) {  

// 如果key不存在则设置为1
    if (redis.setnx(key_mutex, "1")) {  
        // 设置key的过期时间为3分钟  
        redis.expire(key_mutex, 3 * 60)  

// 从db中加载数据但注意只有一个线程能进入到这里其他线程访问的时候已有课key_mutex
        value = db.get(key);  

// 从数据库中加载成功则设置对应的数据
        redis.set(key, value);  
        redis.delete(key_mutex);  
    } else {  
        //其他线程休息50毫秒后重试  
        Thread.sleep(50);  
        get(key);  
    }  
  }  
}  

      1. 缓存雪崩

缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

一言以蔽之:缓存不可用(服务器重启或缓存失效),频繁查询数据源

与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。缓存正常从Redis中获取,示意图如下:

Redis_第11张图片

缓存失效瞬间示意图如下:

Redis_第12张图片

缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

 

你可能感兴趣的:(redis,数据库,缓存)