Redis的基本使用和一些常见问题

redis的安装和基本使用

1、redis是什么?

Redis是一个非关系型的数据库,是一个基于键值对的存储系统,即:key value Map结构。

2、redis能干什么?

因为resia是基于内存的,而且以键值对的形式存储数据,所以效率非常高。在一些并发量比较高的程序中,为了减轻数据库的压力,我们通常将一些数据安全要求不高的数据存储于缓存中,也就是redis中。reids的作用非常广泛:
1、购物车数据

2、评论的存储

3、抽奖

4、商城中评分

5、最热的商品

6、秒杀

7、好友关注

8、实现session共享

9、分布式锁

3、redis的特点

1、redis是基于内存的,所以速度快。但是如果断电,redis执行Kill -9操作,那么内存数据会发生丢失,所以redis的使用场景一点是对数据要求不严格的。
2、为了应对数据丢失问题,redis中提供了三种持久化模式来保证数据的持久性(将缓存中的数据放到硬盘)
3、redis中还提供了多种淘汰策略来满足缓存的数据一定是最新的
4、提供了大量的命令集、来完成开发操作
5、redis中有5中不同的数据类型来满足不同的开发场景:String Hash List Set Sorted Set
6、为了提高可用性,redis中提供了三种架构(主从、哨兵、集群)

4、redis的安装

1、将redis的安装文件复制到 /usr/local目录下去
cp redis-5.0.7.tar.gz /usr/local/
2、下载Redis运行的时候所需要的运行环境
yum install gcc
3、解压上面的Redis文件
tar -zxvf redis-5.0.7.tar.gz
4、进入Redis的根目录进行编译
cd redis-5.0.7
make
5、进入到src目录下进行安装
cd /usr/local/redis-5.0.7/src
make install
6、创建运行的命令的目录和配置文件的目录
mkdir -p /usr/local/redis/bin
mkdir -p /usr/local/redis/etc
7、移动配置文件到 /usr/local/redis/etc目录下
cp redis.conf /usr/local/redis/etc/
8、将运行命令放到 /usr/local/redis/bin目录下去
cp redis-server /usr/local/redis/bin/
cp redis-cli /usr/local/redis/bin/
    
redis-server :Redis的服务端的启动程序
redis-cli:Redis的客户端的启动程序

客户端启动之后 就可以对数据库的数据进行操作
cd /usr/local/redis/bin
./redis-server /usr/local/redis/etc/redis.conf

netstat -apn | grep 6379   :查看6379的端口使用情况

4.1redis中默认有16个数据库,下标为0—15,默认选中0号,切换命令:select [index]

5、常用命令:

5.1、和可以相关的

key *:查看当前数据库中存在的键
select【index】选中某一个数据库
del key:删除某一条数据
exists key :判定某一个key是否存在
注:这个token需要使用
所有缓存的地方都需要使用这个命令
expire key 过期时间 :这个命令可以用在前后分离的项目中设置token的过期时间 ,过期后Key会被删除(当然对应的值也没有了)
ttl key :查看这个key的剩余时间
场景:这个主要就是key如果需要续期的话就可以使用这个命令
返回-2表示Key不存在
返回-1表示没有过期时间永远有效(默认就是永远有效)
move key 【数据库index】:将一个Key–value移动到另一个数据库中
randomkey 随即返回一个Key

5.2和string相关的

set key value :在数据库中设置一个键值对的数据
get key:获取某一个值
场景:存储对象数据
set user:1:username julia
set user:1:password 123
set user:1:count 300
get user:1:username 只取用户名
mset k v k1 v1:同时设置多个键值对
mget k k1…:同时获取多个键值对数据
incr key:自增
decr key:自减
incrby key 步长:一次性自增多少
decrby key 步长:一次性自减多少
setnx key value:表示这个Key不存在的话就设置这个键值对
场景:常用在分布式锁上面

5.3和hash相关的

hset 集合的名字 key value
hget 集合的名字 key value
hlen 集合的名字 获取集合的长度
hdel集合名字 键的名字
hincrby 集合的名字 间的名字 增加的数量
hgetall 集合的名字 实现全选功能
hexists 集合的名字 键的名字 判断某个键是否存在(判断某个人是否有购物车)
hkeys 集合的名字 获取当前这个人所有的购物车的商品
hvals 集合的名字 取出当前集合中所有的值
hset cart:100 10001 1
hmset
hmget
存储对象数据:
hmset user 1:username ls 1:password 123

5.4和list相关的(有序的)

lpush key value:表示将一个或多个值 插入列表的表头
lpop 键 :移除并返回这个列表的头元素
rpush 键 值 :在列表的表位添加元素
rpop 键 从列表的右侧弹出元素
lrange 键 start stop 获取列表一段区域元素
BLPOP 键:从列表的表头弹出一个元素 如果列表的表头没有元素 那么就阻塞等待
BRPOP 键:从列表的右侧弹出一个元素 如果没有元素 那么就阻塞等待
lpush+lpop是栈的结构:先进后出
lpush+rpop是队列结构:先进先出
从左往右为正数索引,从0开始,从右往左为负数索引,从-1开始

5.5和set相关的(无序的)

sadd 键 值 :就是向set集合中添加一个值 (可以用在点赞上)
srem 键 值 :删除这个键中的某一个值 (可以用在取消点赞上
sismember 键 值 检查某一个值是否在这个集合中存在
smembers key :表示的是获取这个集合中的所有数据
srandmemebr key count :从集合中选出count个元素 ,元素不从key中删除(值是随机的)
spop key count :从集合中选中count个元素 元素从集合中删除
sinter key :做做交集运算
sinterstore desternation key:将交集的结果存入新的集合
sunion key :并集运算
sunionstore desternation key :将并集的结果存入这个集合
sdiff key :差集运算
adiffstore desternation key :将差集的结果存入这个集合
scard key :计算当前set集合中的元素的个数

5.6和sorted set相关的(给值打分,以分数排序)

zadd 集合的名字 打分 键的名字 :向Sorted Set中添加一个数据
zrange 集合的名字 开始的位置 结束的位置 获取集合中某一个区间的值
zincrby 集合的名字 加的分值 key的名字 //给某一个值添加分值
zrevrank 集合的名字 键的值 :查看当前数据的排名
zrem 集合的名字 键的名字 :删除某一条数据
zscore 集合的名字 键的名字
zcount 集合的名字 开始 结束 :获取得分在某一个区间类的数据的个数

6、redis的使用

6.1发布订阅模式

subscribe 订阅频道的名称
publish 频道名称 发送内容

6.2事务

multi 开启事务


exec 提交事务
注:redis中的事务无法保证原子性,所以没啥用

6.3持久化

redis是基于内存的,所以当redis重启、宕机、断电时,会发生数据丢失,所以redis中就提供了三种持久化模式,将数据存储到硬盘中。

6.3.1第一种rdb模式

rdb模式又称快照模式,是redis数据库的默认持久化模式(我们不配置,它也存在),这个模式是将内存的数据内容 直接保存到 dump.rdb这样的一个二进制文件中的。

优点:因为保存的是二进制文件、所以做数据的恢复是相当的快的—适合于做数据的备份。

rdb到底是如何保存我们的数据库的:rdb每一次在保存这个数据的时候、首先都会清空原有的dump.rdb文件、然后将整个内存的数据全部写入到这个文件中 rbd-------保存的是redis内存中某一个时刻的数据(适合备份、不适合开发用)

缺点:假设刚好清空dump.rdb这个文件、现在断电了------------数据全丢了

什么时候 rdb模式会触发内存的数据和硬盘进行同步呢?

触发同步的策略:
save 900 1 在900秒的时间内如果有1和key发生改变 那么将触发内存和硬盘同步

save 300 10 在300秒的事件内如果有10个key发生改变 那么将会触发内存和硬盘同步

save 60 10000 在60秒的时间类假设有10000个key发生改变那么也变触发内存和硬盘同步

6.3.2aof实现持久化

aof模式是在redis1.1的版本的时候、才增加的一种持久化模式

aof模式在使用的时候 保存的不是数据 是我们操作的时候的一条一条的命令

只要调用了Redis 那么只要有命令的使用那么都会被记录到aof文件中

aof模式如果是在数据恢复还原的时候 效率并不高 数据恢复的话采用rdb文件恢复是最快的
aof模式如何使用:
在redis.conf文件中配置
appendonly yes :表示的是开启aof的模式
开启后输入命令:set email xxxxx
进入aof文件中是这样的:

*3
$3
set
$5
email
$5
xxxxx
解释:*代表的是命令的开始   3 :这个表示的是命令中一共有3块内容
$使用修饰命令中的每一个参数的 3代表的是下面的这个命令一共有3个字符

注:如果rdb和aof模式同时存在,以aof优先。

aof模式的触发策略:

appendfsync always :只要有键发生改变 立马同步(每一次都触发IO操作、速度就慢下来、这种情况是不会丢数据)-----一般不用(效率太低了)

appendfsync everysec :每一秒钟进行数据同步一次(开发的时候一般选用他----速度上也比较快 即使出现数据的丢失也只会丢失1秒钟的数据)

appendfsync no :永远不同步、数据只是放到缓存里面 速度快 但是数据容易丢失

aof模式是如何同步数据的呢?
每一次在进行数据同步的时候 使用的是 追加的模式 以前的数据不用删除 只需要追加新的操作即可

aof模式消息的重写:
重写策略:

no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100  (这个表示的是必须达到100%的增加才重写  64M+64M=128M )
auto-aof-rewrite-min-size 64mb   aof文件(简单的说就是至少aof文件达到64M才重写)

手动重写
bgrewriteaof :这个命令就是手动重写 
重写的好处是对aof文件进行优化(最终的结果都是一样的)

如果你要去手动重写(需要关闭混合持久化的开关才能看到功能)
aof-use-rdb-preamble no

### 6.3.3混合持久化的问题
注意:混合持久化是4.0才出的模式

使用混合持久化后,每次将缓存以命令形式追加到aof中,每一次出现重写,会将aof中所有命令写成二进制形式,这样集合了aof和rdb的优点,既保证数据安全又提高了恢复数据的效率。
## 6.4缓存的淘汰策略

当redis中内存已经满了,怎么保证redis中的数据一定是最新的呢?

这个时候就需要配置缓存的淘汰策略了
同样是在redis.conf中:
```xml
noeviction:只要缓存满了、那么就不继续服务器里面的写的请求、读的请求是可以完成的、这种模式缓存里面的所有数据 都不会丢失、这种情况会导致参与Redis的业务会失败

volatile-lru:他会优先淘汰掉 设置了过期时间的这个key、然后第二步才淘汰掉使用的比较少的key 假设我们的key没有设置过期时间的话 那么不会优先淘汰

这种模式也是咋们在开发中使用的比较多的一种缓存策略模式

allkeys-lfu:和lru是有区别的、这个在淘汰的时候、淘汰的是全体key的集合、不是过期的key的集合(过期这一说法没有)、这就意味着你没有设置过期时间的key 只要使用的比较少那么依然会被淘汰

volatile-ttl:这个淘汰策略不是LRU 、而是key剩余的寿命的ttl值  ttl值越小  越先被淘汰

allkeys-random:使用这个淘汰策略的时候  淘汰的是随机的key

maxmemory-policy volatile-lru  这个就是配置缓存的淘汰策略的

maxmemory <bytes> :这个是配置Redis的缓存的大小


## 6.5redis的架构
### 6.5.1 主从架构

当访问并发量很高时,一台redis服务器可能承受不住这么高的压力,那么我们就可以使用主从架构解决这个问题。即设置一台为主服务器,另一台为从服务器,主服务器上进行写操作,从服务器只进行读的操作,也就是所谓的读写分离。这样就能提高应对并发的能力。

那么问题来了,写在主服务器上的数据如何同步给从服务器呢?

主从复制就解决了这个问题:也就是写入到主服务器的数据会自动同步到从服务器。

注意:从服务器只能都不能写,但是主服务器可读可写。不过主服务器上的读其实是路由到从服务器上的,换句话说其实还是从服务器上读。

实操:
可以使用两台云服务器,或者一台机器上将redis用两个不同端口开启。

在主服务器中更改配置:

daemonize yes    //后台启动
bind 0.0.0.0     //表示的是允许所有人访问

从服务器配置的更改:

daemonize yes    //后台启动
bind 0.0.0.0     //表示的是允许所有人访问
slaveof 主服务器的ip地址  主服务器端口

使用命令检查是否配置好:
./redis-cli
info

6.5.2哨兵模式

主从模式的问题:从服务器都是连接在主服务器上,一旦主服务器宕机,那么所有redis都无法使用。

解决:在配置哨兵,监听主服务器的状态,简单地说就是监听主服务器是否宕机。主服务器每隔一定时间需要向哨兵发送心跳(Keep alive),如果在规定时间内,没有向哨兵发送心跳,哨兵就会认为主服务器死了,就会开始投票从从服务器中选出新的主服务器(所以一般哨兵需要配成单数需要)

注:哨兵是安装在任意一台服务器上 、跟咋们的主服务器 并没有任何的关联

哨兵的配置:

配置sentinal.xml文件(redis解压目录下的):

dir /usr/local/zhucong/
#配置的是监听主服务器信息  最后一个参数很重要 一般设置为1  多少票通过
sentinel monitor mymaster 39.99.200.54 6379 1
#配置的是意思是心跳信号发给你了 多久没回应就认为主服务器死了...
sentinel down-after-milliseconds mymaster 5000
    
哨兵的启动命令
./redis-server /usr/local/zhucong/sentinel.conf  --sentinel &

6.5.3集群模式

哨兵模式也存在问题,那就是如果光是写的并发量就达到了redis服务器的极限那怎么办?

很简单,我们的主服务器也可以配置多台,也就是我们的集群模式。

集群模式的特点:
当在一台主服务器上写入一定次数后,再次写入就会转到另外的服务器上达到负载均衡。
在任意一台服务器上写入的值在其他服务器上也可以读出,也就是数据共享。当主服务器宕机了,就会投票选出新的主服务器(横向拓容,纵向分压)。

集群的实操(不太好写就不写了)

7redis在开发中常见的问题

7.1缓存穿透问题

在开发时,假设用户第一次访问数据会先访问redis(当然是要求不严格的数据),redis中找不到再去数据库找,如果后面每一个线程进来都要访问数据库,那么数据库压力就会很大,甚至崩溃,这就是缓存穿透问题。

解决:当第一次访问redis没找到数据,在访问数据库还是没找到数据,那么就在redis中将这个数据设置为""值,那么下次进来访问redis后就不会再访问数据库了。

7.2缓存雪崩问题

造成原因:1、大量的key同时过期
2、某一时间redis服务器大量故障
这些原因都会造成大量请求直接访问数据库导致数据库崩溃。

解决办法:针对原因1的因对方案:在计算出key的过期时间后动态的加上一个范围内的随机数将过期时间错开。
针对原因2的因对方案:做缓存的高可用,例如:集群模式。
还可以做缓存的预热,即在使用这个数据前,先将数据库中要缓存的数据存到redis中

7.3脑裂问题

场景:当写入redis主服务器时,主服务器还没将数据同步到从服务器就因为某些原因宕机了,这样数据就即使后来连上了也是作为从服务器,也没有办法进行数据同步。这就是脑裂问题。

解决方案:

min-slaves-to-write 1 这个表示的意思是:在我们客户端写入数据的时候 至少保证 主服务器上有一个从服务器 处于正常连接才能写入这个数据

min-slaves-max-lag 10 :这个表示的的意思是 主从同步的时间 10s

8springboot整合redis

第一步、添加redis的依赖:

  <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.11.1</version>
        </dependency>

第二步、编写redis的配置类:


package com.redis.springbootredis.config;


import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

@SpringBootConfiguration
public class RedisConfig {

    @Bean
    public RedissonClient getRedissonClient(){


        RedissonClient redissonClient = null;

        Config config = new Config();

        String url = "192.168.232.130:6379";

        config.useSingleServer().setAddress(url);

        try {
            redissonClient = Redisson.create(config);

            return redissonClient;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

}

第三步、在application.properties或着application.yml配置文件中配置redis参数

spring.redis.host=192.168.232.130
spring.redis.port=6379
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.password=123

最后、编写redis的管理类

package com.redis.springbootredis.mapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisManager {

    private Logger logger = LoggerFactory.getLogger(RedisManager.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void setKeyAndValue(String key, String value) {

        stringRedisTemplate.opsForValue().set(key,value);

        logger.info("操作成功");
    }


    public String getValueByKey(String key){


        return stringRedisTemplate.opsForValue().get(key);
    }

}

```java

   /**
         * stringRedisTemplate.opsForValue(); 这个就是用来操作 String类型的
         * stringRedisTemplate.opsForList(); 这个主要就用来操作list的
         * stringRedisTemplate.opsForZSet(); 这个主要用来操作sorted set
         * stringRedisTemplate.opsForHash(); 用来操作hash结构的
         * stringRedisTemplate.opsForSet();  这个就是用来操作Set数据类型的
         */
/**
     * 常用的API的意思
     * //设置key过期的API
     * stringRedisTemplate.expire("NZ1904",60, TimeUnit.SECONDS);
     * //ttl :获取一个键的过期时间
     * stringRedisTemplate.getExpire()
     * //  exists :判断一个键是否存在
     * stringRedisTemplate.hasKey("");
     * //del :删除一个键值对
     * stringRedisTemplate.delete("key");
     *incrby 这个命令
     * stringRedisTemplate.opsForValue().increment("key",1);
     *decrby这个命令
     * stringRedisTemplate.opsForValue().increment("key",-1);
     *hmget这个命令
     *stringRedisTemplate.opsForHash().entries("");
     *hmset
     *stringRedisTemplate.opsForHash().putAll("",null);
     *hset这个命令
     *stringRedisTemplate.opsForHash().put();
     * hdel命令
     *stringRedisTemplate.opsForHash().delete()
     * 判断hash结构中这个键是否存在
     * stringRedisTemplate.opsForHash().hasKey()
     * Set集合中获取某一个值
     * stringRedisTemplate.opsForSet().members()
     * 判断set集合中是否存在某一个值
     *stringRedisTemplate.opsForSet().isMember()
     * set集合设置值
     * stringRedisTemplate.opsForSet().add()
     */






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值