redis的完整学习

news2024/11/20 7:07:08

Redis

1.Nosql

  1. 单机mysql
  2. 缓存机制
  3. 分库分表+水平拆分+mysql集群:本质上是数据库的读写
    • MyISAM:表锁,效率低
    • Innodb:行锁

特点

解耦!

1.方便扩展

2.大数据量高性能

3.数据类型是多样型的(不需要设计数据库,随取随用)

4.传统RDBMS和NoSQL

  • 传统的RDBMS
    • 结构化组织
    • 数据和关系存在单独的表中
    • 严格的一致性
    • 基础的事务
  • Nosql
    • 不仅仅是数据
    • 没有固定的查询语言
    • 键值对存储,列存储,文档存储,图形数据库
    • 最终一致性
    • CAP定理和BASE
    • 高性能,高可用,高可扩
  1. 3V+3高
  • 海量Volume
  • 多样Variety
  • 实时Velocity
  • 高并发
  • 高可用
  • 高性能

四大分类

KV键值对:

  • Redis、Tair、memacache

文档型数据库(bson和json一样):

  • mongoDB:基于分布式文件存储的数据库,用来处理大量的文档
  • mongoDB是一个介于关系型数据库和非关系型数据库之间的产品。
  • ConthDB

列存储数据库:

  • HBase
  • 分布式文件系统

图关系数据库:

  • 存放的是关系(如朋友圈社交网络)

  • Neo4j,InfoGrid

2.Redis入门

概述

Redis(Remote Dictionary Server):远程字典服务

作用:

  1. 内存存储,持久化,内存是断电即失,持久化(rdb、aof)
  2. 效率高,可用用于高速缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器、计数器

特性:

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

配置:

  1. https://redis.io/

3.Windows安装

github地址

在这里插入图片描述

开启redis,开启服务

在这里插入图片描述

使用客户端连接redis

在这里插入图片描述

redis-benchmark性能测试

在这里插入图片描述

4.基础知识

端口号:6379

127.0.0.1:6379> select 3 //切换数据库
OK
127.0.0.1:6379[3]> DBSIZE //db大小
(integer) 0
127.0.0.1:6379[3]> keys * //查询所有的db数
1) "name"
127.0.0.1:6379[3]> flushdb //清空当前数据库
OK
127.0.0.1:6379[3]> FLUSHALL //清空所有数据库
OK
127.0.0.1:6379[3]> keys *
(empty list or set)

redis是单线程的

  • redis是基于内存操作的,CPU不是redis的性能瓶颈,是根据机器的内存和网络带宽

单线程为什么这么快?

  • redis是c语言写的,官方的数据是10万+的QPS
  • 将所有的数据放在内存中的,多线程(CPU会上下文切换:耗时),低于内存系统来说,没有上下文切换效率就是最高的,多次读写都是在一个CPU上,在内存情况下单线程就是最好的。

5.五大数据类型

Redis-key

127.0.0.1:6379> set name liuxiang //设置key
OK
127.0.0.1:6379> EXISTS name //判断是否存在
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
127.0.0.1:6379> move name 1 //移除
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"1"
127.0.0.1:6379> EXPIRE age 10 //设置key过期时间 单位s
(integer) 1
127.0.0.1:6379> ttl age //查看当前key的剩余时间
(integer) 7
127.0.0.1:6379> ttl age
(integer) 0
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> type name //查看当前key的类型
string
127.0.0.1:6379> type age
string

String(字符串)

127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get v1
(nil)
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> EXISTS key1
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" //追加字符串 当前key不存在相当于set一个key
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> strlen key1 //获取字符串的长度
(integer) 16
127.0.0.1:6379> APPEND key1 ",liuxiang"
(integer) 16
127.0.0.1:6379> get key1
"v1hello,liuxiang"
    
=====================================================================
127.0.0.1:6379> set views 0 //设置浏览量
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views //增加1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views //减少1 
(integer) 1
127.0.0.1:6379> incrby views 10 //自增 设置步长
(integer) 11
127.0.0.1:6379> decrby views 5 //自减 设置步长
(integer) 6
    ============================================================
127.0.0.1:6379> set key1 "hello liuxaing" //设置key1值
OK
127.0.0.1:6379> get key1
"hello liuxaing"
127.0.0.1:6379> getrange key1 0 3 //截取字符串【0,3】
"hell"
127.0.0.1:6379> getrange key1 0 -1 //获取全部的字符串
"hello liuxaing"
  ==============================================================
127.0.0.1:6379> set key1 abcdefg
OK
127.0.0.1:6379> get key1
"abcdefg"
127.0.0.1:6379> setrange key1 1 xx //替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key1
"axxdefg"
    ===========================================================
127.0.0.1:6379> setex key1 30 "hello" //设置key1值 30s后过期
OK
127.0.0.1:6379> ttl key1
(integer) 26
127.0.0.1:6379> get key1
"hello"
127.0.0.1:6379> setnx mykey "redis" //设置过期时间
(integer) 1
127.0.0.1:6379> keys *
1) "mykey"
127.0.0.1:6379> setnx mykey "mongdb" //不存在再设置(在分布式锁常用)如果mykey存在 创建失败
(integer) 0
127.0.0.1:6379> keys *
1) "mykey"
127.0.0.1:6379> get mykey
"redis"
 =================================================================
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 //同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 //同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 //原子性操作 k4创建失败
(integer) 0
127.0.0.1:6379> get k4
(nil)
 ==================================================================
//key的设计:user:{id}:{filed}
127.0.0.1:6379> mset user:1:name liuxiang user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "liuxiang"
2) "2"
 ==================================================================
 //先get后set
127.0.0.1:6379> getset db redis //如果不存在值则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb //如果存在值 获取原来的值 并设置新的值
"redis"
127.0.0.1:6379> get db
"mongodb"

List

基本的数据类型,列表

127.0.0.1:6379> lpush list one #左插值
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 #通过区间获取具体的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1
1) "three"
2) "two"
127.0.0.1:6379> rpush list right #右插值
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list #左弹值
"three"
127.0.0.1:6379> rpop list #右弹值
"right"
127.0.0.1:6379> lrange list 0 -1 
1) "two"
2) "one"
127.0.0.1:6379> lindex list 0 #通过下表获得list中的某个值
"two"
127.0.0.1:6379> llen list #获得list的长度
(integer) 2
127.0.0.1:6379> lrem list 1 one #移除list集合中指定个数的value
(integer) 1
=====================================================================
127.0.0.1:6379> rpush list "hello"
(integer) 1
127.0.0.1:6379> rpush list "hello1"
(integer) 2
127.0.0.1:6379> rpush list "hello2"
(integer) 3
127.0.0.1:6379> ltrim list 1 2 #通过下表截取指定的长度
OK
127.0.0.1:6379> lrange list 0 -1
1) "hello1"
2) "hello2"
=====================================================================
127.0.0.1:6379> rpush list "hello"
(integer) 1
127.0.0.1:6379> rpush list "hello1"
(integer) 2
127.0.0.1:6379> rpush list "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush list otherlist #移除列表的最后一个元素移动到新的列表中
"hello2"
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "hello1"
127.0.0.1:6379> lrange otherlist 0 -1
1) "hello2"
=====================================================================
127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> lset list 0 okk #替换当前索引位置的值,若无值会报错
OK
127.0.0.1:6379> lrange list 0 0
1) "okk"
127.0.0.1:6379> lpush list "hello"
(integer) 2
127.0.0.1:6379> linsert list before "okk" other #在指定字符位置前插入值
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "okk"

Set集合

127.0.0.1:6379> sadd myset "hello" #添加值
(integer) 1 
127.0.0.1:6379> smembers myset #查set中的所有值
1) "hello"
127.0.0.1:6379> sismember myset "hello" #判断某个值是不是在set集合中
(integer) 1
127.0.0.1:6379> srem myset "hello" #移除set中的指定值
(integer) 1
127.0.0.1:6379> scard myset #查询set集合中值的个数
(integer) 0
127.0.0.1:6379> srandmember myset #随机抽取一个值
"hello"
127.0.0.1:6379> spop myset #随机删除set集合中的一个值
"hello"
====================================================================
127.0.0.1:6379> sdiff k1 k2 #差集
1) "b"
127.0.0.1:6379> sinter k1 k2 #交集
1) "a"
2) "c"
127.0.0.1:6379> sunion k1 k2 #并集
1) "a"
2) "b"
3) "c"
4) "e"

Hash map集合

key-map形式

127.0.0.1:6379> hset myhash field liuxiang #set一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash field
"liuxiang"
127.0.0.1:6379> hmset myhash field hello field1 world #set多个key-value
OK
127.0.0.1:6379> hmget myhash field field1 #获取多个值
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash #获取全部的数据
1) "field"
2) "hello"
3) "field1"
4) "world"
127.0.0.1:6379> hdel myhash field1 #删除指定字段及value值
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field"
2) "hello"
127.0.0.1:6379> hlen myhash #获取hash表的字段数量
(integer) 1
127.0.0.1:6379> hexists myhash field #判断是否存在
(integer) 1
127.0.0.1:6379> hkeys myhash #获取所有字段
1) "field"
127.0.0.1:6379> hvals myhash #获取所有值
1) "hello"
127.0.0.1:6379> hincrby myhash field1 1 #自增
(integer) 2
127.0.0.1:6379> hsetnx myhash field hello #如果存在则不能设置
(integer) 0

Zset有序集合

127.0.0.1:6379> zadd salary 2500 xiaohong #添加用户
(integer) 1
127.0.0.1:6379> zadd salary 3000 xiaoming
(integer) 1
127.0.0.1:6379> zadd salary 500 xiaocong
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf inf #显示全部用户从小到大
1) "xiaocong"
2) "xiaohong"
3) "xiaoming"
127.0.0.1:6379> zrangebyscore salary -inf inf withscores #显示用户并带成绩
1) "xiaocong"
2) "500"
3) "xiaohong"
4) "2500"
5) "xiaoming"
6) "3000"
127.0.0.1:6379> zrem salary xiaohong #移除有序集合中的key
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "xiaocong"
2) "xiaoming"
127.0.0.1:6379> zcard salary #获取有序集合中的个数
(integer) 2

6.Geospatial地理位置

基于Zset实现!

#geoadd 添加地理位置 参数: 纬度 经度 名称
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijin
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqi 114.05 22.52 shenzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
(integer) 1
#geopos 获取指定地点的经纬度
127.0.0.1:6379> geopos china:city beijin chongqi
1) 1) "116.39999896287918"
   2) "39.900000091670925"
2) 1) "106.49999767541885"
   2) "29.529999579006592"
#geodist 获取两地的直线距离
127.0.0.1:6379> geodist china:city hangzhou shenzhen
"1052108.2563"
# georadius 获取指定经纬度半径范围内的地点
127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "chongqi"
2) "xian"
3) "shenzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord
1) 1) "chongqi"
   2) 1) "106.49999767541885"
      2) "29.529999579006592"
2) 1) "xian"
   2) 1) "108.96000176668167"
      2) "34.2599996441893"
#georadiusbymember 获取指定地方周围半径的城市
127.0.0.1:6379> georadiusbymember china:city shenzhen 500 km
1) "shenzhen"

7.Hyperloglog

传统的方式,set保存用户的id,可用统计set中的元素数量作为判断标准,这个方式如果保存大量的用户id就会比较麻烦。

Redis Hyperloglog基数统计法。

127.0.0.1:6379> pfadd mykey a b c d e f g h i j k
(integer) 1
127.0.0.1:6379> pfcount mykey #统计mykey元素的基数数量
(integer) 11
127.0.0.1:6379> pfadd mykey2 i z x g h o l
(integer) 1
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 #合并两组
OK
127.0.0.1:6379> pfcount mykey3 #查看并集的数量
(integer) 15

8.Bitmaps

两个状态的均可用,如打卡和登录等!

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 5
(integer) 0
127.0.0.1:6379> bitcount sign #统计打卡记录
(integer) 4

9.事务操作

redis单条命令保持原子性,但事务不保证原子性!没有隔离性

事务本质:一组命令的集合!

所有命令在事务中并没有直接执行,只有发起执行命令的时候才会执行!

redis事务:

  • 开启事务:multi
  • 命令入队
  • 执行事务:exec
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discrad #取消事务
OK
127.0.0.1:6379> exec #取消的事务不会被执行
1) OK
2) OK
3) "v1"
4) OK

编译型错误:代码错误 ;运行时异常:语法错误

10.redis乐观锁

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money #监视
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动这个时候正常启动事务
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
=================================================================
# 测试多线程修改值,执行前另外一个线程修改了值,事务exec执行失败
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> exec
(nil)
==================================================================
# 执行失败,先解锁,再监控再做事务操作
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> exec
1) (integer) 980
2) (integer) 40

11.Jedis

Jedis是Redis官方推荐的Java连接开发工具,使用java操作redis中间件。

1.导入对应的依赖

<dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
    </dependencies>

2.编码测试

  • 连接数据库
  • 操作
  • 断开连接

操作事务:

public class TestPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        jedis.flushDB();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","liuxiang");
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        try {
            multi.set("user1",result);
            multi.set("user2",result);
            int i = 1/0; //运行时异常
            multi.exec(); //执行事务
        } catch (Exception e) {
            multi.discard(); //放弃事务
            e.printStackTrace();
        } finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }
    }
}

12.SpringBoot整合

原来的Jedis被替换为了lettuce!

jedis:采用的直连,多个线程操作不安全,避免不安全可用使用jedis pool线程池

lettuce:采用netty,实例可用在多个线程中共享,不存在线程不安全!

1.导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.配置

#配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

3.连接测试

@Autowired
    private RedisTemplate redisTemplate;
    @Test
     void contextLoads() {
        //opsForValue() 操作字符串 类似String
        //opsForList() 操作list集合
        //opsForSet() 操作set集合
//        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//        connection.flushDb();
//        connection.flushAll();
        redisTemplate.opsForValue().set("mykey","liuxiang");
        System.out.println(redisTemplate.opsForValue().get("mykey"));

    }

自定义RedisTemplate模板

@Configuration
public class RedisConfig {
    //编写自己的redisTemplate

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key采用string的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key采用string的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value采用jackson2JsonRedisSerializer
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash 的value采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

13.Redis配置文件详解

单位

大小写不敏感

在这里插入图片描述

包含

在这里插入图片描述

如spring中的import,include,将其他配置文件加进来

网络

bind 127.0.0.1  //绑定的ip
protected-mode yes  //保护模式
port 6379  //端口设置

通用

windows不支持!

NOT SUPPORTED ON WINDOWS daemonize no //默认是no 以守护进程的方式运行
NOT SUPPORTED ON WINDOWS pidfile /var/run/redis.pid //如果以后台的方式运行需要指定一个pid文件
//日志
# 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
logfile "" //日志的输出文件名
databases 16 //数据库的数量 ,默认16个

快照SNAPSHOTTING

在规定的时间内执行多少次操作则会持久化到文件.rdb .aof(持久化文件)

redis是内存数据库,如果没有持久化那么数据断电即失!

save 900 1 //如果900s内,如果有一个key修改就进行持久化操作
save 300 10//如果300s内,如果有十个key修改就进行持久化操作
save 60 10000//如果900s内,如果有一万个key修改就进行持久化操作

stop-writes-on-bgsave-error yes //持久化出错是否还需要继续工作
rdbcompression yes //是否压缩rdb文件,需要消耗一些CPU资源
rdbchecksum yes //保存edb文件时候进行错误的校验
dbfilename dump.rdb //rdb文件保存的目录

主从复制REPLICATION

在主从复制一节当中!

安全

设置密码:

config set requirepass "123456" #设置密码
auth 123456 #登录
ping
config get requirepass #获得密码
requirepass foobared

限制 客户端

maxclients 10000 #设置连接上redis的最大客户端数量
maxmemory <bytes> #最大的内存容量
maxmemory-policy noeviction #内存到达上限的处理策略 
 1.volatile-lru 只对设置了过期时间的key进行lru
 2.allkeys-lru 删除lru算法的key
 3.volatile-random 随机删除过期的key
 4.allkeys-random 随机删除
 5.volatile-ttl 删除即将过期的
 6.noeviction 永不过期 返回错误

APPEND ONLY MODE

appendonly no #默认不开启aof模式,默认使用rdb方式持久化(大部分情况够用)
appendfilename "appendonly.aof" #持久化文件
# appendfsync always 每次修改都会sync 消耗性能
appendfsync everysec  #每秒执行一次sync 可能会丢失数据
# appendfsync no 不执行同步,操作系统自己同步数据

14.redis持久化

redis是内存数据库,不保存就会断电即失!

RDB(Redis DateBase)

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入一个临时文件中,等持久化过程结束后替换上次持久化的文件。

进行大规模的数据恢复RDB比AOF更加高效,因为不进行IO操作

缺点:最后一次持久化的数据可能会丢失,默认是RDB

rdb保存的文件是dump.rdb

127.0.0.1:6379> config get dir
1) "dir"
2) "D:\\Environment\\Redis-x64-3.2.100" #如果在这个目录下存在dump.rdb文件,启动就自动恢复数据

优点:

1、适合大规模的数据恢复

2、对数据的完整性要求不高

缺点:

1、需要一定的时间间隔进程操作,redis意外宕机了最后一次数据就没有

2、fork进程的时候会占用一定的空间

AOF(Append Only File)

aof文件大于64M,fork新进程重写文件!将所有命令都记录下来。

在这里插入图片描述

默认不开启:

appendonly no #改为yes就开启
appendfilename "appendonly.aof" #持久化的文件名
appendfsync always #每次修改都会sync 消耗性能
appendsync everysec #每秒执行一次sync
appendsync no #不执行sync,操作系统自己同步数据

如果aof文件有错误,redis是启动不起来,利用

redis-check-aof --fix appendonly.aof修复文件

缺点:

1、相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢!

2、aof运行效率慢!有IO操作!

扩展:

  1. 只做缓存可以不适用任何持久化
  2. 同时开启两种持久化方式,优先载入AOF,因为数据更完整

15.Redis订阅发布

Redis发布订阅(pub/sub)是一种消息通信模式:发送者pub发送消息,订阅者sub接收消息

Redis客户端可以订阅任意数量的频道。

在这里插入图片描述

在这里插入图片描述

SUBSCRIBE liuxiang #订阅一个频道
PUBLISH liuxiang "hello,man" #发布者发布消息到频道

原理:

使用C实现

在这里插入图片描述

16.Redis主从复制

概念:

主从复制指将一台redis服务器的数据复制到其他redis服务器(主机到从机)

主机以写为主,从机以读为主

主从复制的作用:

  1. 数据冗余:实现了数据的热备份,是持久化之外的另一种数据冗余方式
  2. 故障恢复:当主节点出现问题时由从节点提供服务,实现快速的故障恢复
  3. 负载均衡:在主从复制的基础上配合读写分离,可以由主节点提供写服务,从节点提供读服务,分担服务器负载。
  4. 高可用基石:主从复制是哨兵集群能够实施的基础

主从复制:复制配置文件修改pid、dump文件、log日志以及端口即可!

基本的要求:一主二从,默认情况下每台redis服务器都是主节点

配置从机即可(命令):

SLAVEOF 127.0.0.1 6379

如果重启后会变成主机,再次变成从机还是会获取所有信息!

在配置文件中永久配置:

在这里插入图片描述

Redis最大使用内存不应该超过20G

127.0.0.1:6379> info replication #查看当前库的信息
# Replication
role:master #主机
connected_slaves:0 #从机数
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>

复制原理:

  1. slave启动成功连接到master后会发送一个sync同步命令
  2. master接到命令启动后台的存盘进程同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次同步
  3. 全量复制:slave服务接收到数据库文件后存盘并加载到内存中
  4. 增量复制:master继续将新的修改命令依次传给slave,完成同步

层层递进模式:

中间的服务器既当从节点又当主节点,当主节点崩了,此时变成主节点

slaveof no one #自己成为主节点

17.哨兵模式

哨兵是一个独立的进程,独立运行,原理是哨兵通过发送命令等待redis服务器响应,从而监控运行的多个redis实例!

在这里插入图片描述

两个作用:

  1. 通过发送命令让redis服务器返回监控其运行状态包括主服务器和从服务器
  2. 当哨兵监测到master宕机,自动切换slaver到master,通过发布订阅模式通知其他从服务器修改配置文件

多哨兵模式:除了监控redis服务器,哨兵之间也互相监控

在这里插入图片描述

1.配置哨兵配置文件sentinel.conf

sentinel monitor myredis 127.0.0.1 6379 1 #1代表主机宕机投票选举主机

2.启动哨兵

redis-sentinel kconfig/sentinel.conf

主机宕机,临时选举变成主机,如果主机恢复,只能继续变回从机!

缺点:

1.扩容麻烦

2.实现哨兵模式的配置复杂

哨兵模式的配置

端口:26379,如果有哨兵集群,需要配置多个端口

18.缓存穿透和雪崩

缓存穿透(查不到)

用户想要查询一个数据,发现redis内存数据库没有。也就是缓存没有命中,于是向持久层数据库查询,发现也没有,查询失败。当用户很多的时候,缓存都没有命中,于是都去持久层数据库查询,带来很大压力,就会出现缓存穿透。

解决:

1.布隆过滤器

一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免对底层存储系统的查询压力。

在这里插入图片描述

2.缓存空对象

当存储器不命中后,即使返回的空对象也缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护后端数据源。

存在问题:

  1. 如果空值被缓存,无意义
  2. 对空值设置过期时间,还是会存在不一致

缓存击穿(量太大)

一个key非常热点,在不停的扛着大并发,集中对一个点进行访问,当缓存失效(缓存过期)的瞬间,持续的大并发穿破缓存直接请求数据库。

解决:

  1. 设置缓存不过期
  2. 加互斥锁:
    • 分布式锁:保证每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限

缓存雪崩

指在某一个时间段,缓存集中过期失效,redis宕机!

解决方案:

  1. redis高可用:多增加redis服务器
  2. 限流降级:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,对某一个key只允许一个线程查询数据和写缓存
  3. 数据预热:在正式部署之前,先把可能的数据先访问一遍,设置不同的过期时间,让缓存失效的时间点尽量均匀。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/191350.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言 预处理

int main() {//printf("%s\n", __FILE__);//打印所在文件夹位置//printf("%d\n", __LINE__);//打印当前所在行号//printf("%s\n", __DATE__);//打印当前系统日期//printf("%s\n", __TIME__);//时间//printf("%s\n", __FUNCT…

分享155个ASP源码,总有一款适合您

ASP源码 分享155个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 154个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/12oYeESSXJCd32n463LBt4w?pwd5i1n 提取码&#x…

Java线程池中的execute和submit

一、概述 execute和submit都是线程池中执行任务的方法。 execute是Executor接口中的方法 public interface Executor {void execute(Runnable command); }submit是ExecuteService接口中的方法。 public interface ExecutorService extends Executor {<T> Future<T…

vue+element模仿腾讯视频电影网站(二),增加视频播放详情页

一.前言 1. 本项目在线预览&#xff1a;点击访问 2. 作者其他博客成品汇总预览&#xff1a;点击访问 3. 接上一篇&#xff1a;《vueelement模仿腾讯视频电影网站》 暂时源码并没有提供其他获取渠道&#xff0c;私聊作者获取即可&#xff0c;或通过博客后面名片添加作者&#…

【SSM】Mybatis小技巧汇总

Mybatis技巧一&#xff1a;#{} 和 ${} 的区别使用 ${} 特例一&#xff08;排序&#xff09;使用 ${} 特例二&#xff08;表连接&#xff09;使用 ${} 特例三&#xff08;批量删除&#xff09;技巧二&#xff1a;typeAliases 别名机制别名 Alias 性质技巧三&#xff1a;mappersm…

串级PID控制原理-1

串级计算机控制系统的典型结构如图1所示&#xff0c;系统中有两个PID控制器&#xff0c;Gc2(s)称为副调节器传递函数&#xff0c;包围Gc2(s)的内环称为副回路。Gc1(s)称为主调节器传递函数&#xff0c;包围Gc1(s)的外环称为主回路。主调节器的输出控制量u1作为副回路的给定量R2…

Vuex基本概念

一、基本概念vuex&#xff1a;为了解决不关联的组件整个网站状态数据共享问题&#xff0c;专为Vue.js开发的状态管理模式。采用集中式存储管理应用的所有组件状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。vuex有5个主要成员&#xff1a;state&#xff1…

DAMA数据管理知识体系指南之数据架构管理

第4章 4.1 简介 数据架构管理是定义和维护如下规范的过程&#xff1a; 提供标准的、通用的业务术语/辞典。 表达战略性的数据需求。 为满足如上需求&#xff0c;概述高层次的整合设计。 使企业战略和相关业务架构相一致。 数据架构是用于定义数据需求、指导对数据资产的整合和…

【C++】从0到1入门C++编程学习笔记 - 提高编程篇:STL常用容器(vector容器)

文章目录一、vector基本概念二、vector构造函数三、vector赋值操作四、vector容量和大小五、vector插入和删除六、vector数据存取七、vector互换容器八、vector预留空间一、vector基本概念 功能&#xff1a; vector数据结构和数组非常相似&#xff0c;也称为单端数组 vector…

Discord多账号抢白名单,如何避免账号关联被封号?

相信玩NFT项目的都不会对Discord陌生&#xff0c;现在NFT的项目都会开Discord伺服器&#xff0c;并且将内容公告在上面、在伺服器里互动&#xff0c;所以如果你想参与NFT的世界&#xff0c;学会使用Discord是一件非常重要的事情。 东哥前2天也出了关于discord如何使用、如何抢白…

很多网站、APP 前段时间一下都变灰了。 先来感受一下变灰后的效果。

很多网站、APP 前段时间一下都变灰了。 先来感受一下变灰后的效果。 这种灰色的效果怎么实现的呢&#xff1f;如何做到图片、文字、按钮都变灰的效果呢&#xff1f; 方案 1&#xff0c;换一套灰色的 UI&#xff0c;那显然成本太大了&#xff0c;用脚指头想一想就知道不太可能…

C语言---选择排序和堆排序

文章目录前言一、简单选择排序1.简介2.算法思路3.代码实现二、堆排序1.简介2.算法思路3.代码实现总结前言 堆排序是选择排序的一种&#xff0c;今天我们讲解一下堆排序和简单选择排序 一、简单选择排序 1.简介 选择排序&#xff08;Selection sort&#xff09;是一种简单直观…

ZoomCharts JavaScript 1.20.2 Crack

深入探索数据 令人惊叹的数据可视化方式 - 这里是 ZoomCharts JavaScript 图表的不同交互可能性和功能。 内容向下钻取和向上钻取 深入研究特定数据点或获得更大的图景。通过放大或缩小与图表进行物理交互&#xff0c;浏览不同的数据级别。 数据过滤 选择一个或多个数据点查看具…

【软件测试面试】他凭什么能在面试中狂揽10个offer?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 小高&#xff1a; 记…

2023年屏蔽iOS16系统更新,去除小红点,最新方法

昨天开始&#xff0c;屏蔽iOS系统更新的旧文件已经过期&#xff0c;许多老粉收到了更新提醒&#xff0c;因此现在给大家带来最新的屏蔽文件 这个文件可以屏蔽iOS系统更新和提醒&#xff0c;防止手机自动下载更新。 这个方法支持所有 iPhone 和 iPad&#xff0c;支持所有 iOS 和…

# Android未来几年发展规划【纵横发展】

前言 如果你是移动开发人员&#xff0c;那么首先要跟上技术的最新发展趋势&#xff0c;并时刻关注新事物&#xff0c;即使有时你甚至需要质疑自己的信仰。应用开发人员一方面一直在努力想办法简化和缩短开发过程&#xff0c;另一方面也在努力构建最佳的设计和用户体验。每年我…

【MPP数据库】StarRocks分区、分桶探索与实践

1.先学习一下StarRocks的架构图&#xff1a; 2.基本概念 2.1 Row & Column 一张表包括行&#xff08;Row&#xff09;和列&#xff08;Column&#xff09;。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。 Column 可以分为两大类&#xff1a;Key 和 Value…

leetcode刷题记录总结-7.递归回溯算法(进行中)

文章目录零、回溯算法理论总览什么是回溯法回溯法的效率回溯法解决的问题如何理解回溯法回溯法模板一、组合问题[77. 组合](https://leetcode.cn/problems/combinations/)题解递归实现组合型枚举&#xff1a;每个点选与不选子集问题模板组合问题解决思路回溯思路&#xff1a;遍…

GAMES101笔记:辐射度量学(上)

Radiometry 辐射度量学 如何描述光照&#xff0c;定义了一系列的方法和单位准确度量光的空间属性&#xff1a; Radiant fluxintensityirradianceradiance 以物理正确的方式进行光照计算 Radiant Energy and Flux (Power) Radiant Energy 定义 Radiant Energy 是电磁辐射的能…

6、数据的合并

目录 一、添加变量即横向合并。 二、添加个案即纵向合并 在实际工作中&#xff0c;为了提高效率&#xff0c;经常需要将一份数据分成几部分分别录入&#xff0c;或为了便于分析&#xff0c;又将几个数据文件合并成一个总的数据文件。为此&#xff0c;SPSS提供了两种合并数据文…