Basic use and advanced knowledge of Redis

Basic use and advanced knowledge of Redis

Redis is a non-relational database that uses key-value pairs key and value to store data. Because its data is stored in memory, it has high read and write efficiency. Commonly used scenarios include: reading and writing of massive data, high data Concurrent reading and writing, data caching, etc.

1. Basic data types

The Redis database has five basic data types, and now the new version of Redis adds three new data types Bitmaps, HyperLogLog, Geospatial, which are not explained here, but only briefly explain the five basic data types.

1. String

字符串类型,存储的 value 数据为字符串。

2. List

列表类型,存储的 value 数据为一个列表,有序列表,其数据排列的顺序与数据添加的顺序相同。

3. Hash

哈希类型,存储的 value 数据为一个对象,对象内也是采用 key 和 value 进行存储数据的,类似于Java中的 map 数据类型或者Python中的字典 dict 类型。

4. Set

集合类型,存储的 value 数据为一个集合,该集合是 无序 的,集合中不允许有重复值,会自动去重。

5. Zset

有序集合类型,存储的 value 数据也是集合,该集合是 `有序` 的,通过给每个 value 设置 score 值,按照每个 value 的 score 值进行排序,同时该集合也是不包含重复值的,自动去重。

2. Basic operation commands

1.String

Common command operations in the String string type

# 设置key为k1,值为10
set k1 10

# 获取key为k1的值
get k1

# 对key为k1的value值进行+1
incr k1

# 对key为k1的value值进行+20
incrby k1 20 

# 对key为k1的value值进行-1
decr k1

# 对key为k1的value值进行-20
decrby k1 20 

# 设置k1的过期时间为20s
expire k1 20

# 设置k2的值为v2,过期时间为30s
setex k2 30 v2

# 查看k2的过期时间(-1表示永久有效,-2表示已失效,其他数字表示剩余过期时间)
ttl k2

# 设置k2的值为v2,若k2已存在,则不设置,否则设置。
setnx k2 v2

# 同时设置多个key和value
mset k1 v1 k2 v2

# 同时获取多个key的value
mget k1 k2

2.List

Common command operations in the List list type

# 从左边依次添加数据至t1列表中,结果为 3 2 1
lpush t1 1 2 3

# 从右边依次添加数据至t2列表中,结果为 1 2 3
rpush t2 1 2 3

# 从t1列表中获取索引从0到-1的所有value值,索引0代表第一个,索引-1代表最后一个
lrange t1 0 -1

# 从左边依次删除t1列表中的值
lpop t1

# 从右边依次删除t1列表中的值
rpop t1

# 获取t1列表的长度
llen t1

3.Hash

Common command operations in the Hash type

# 设置key为k1中的id值等于1001,一次只能设置一个
hset k1 id 1001

# 设置key为k1中的name=lucy,age=20,一次可以设置多个值
hmset k1 name lucy age 20

# 获取k1中id的值
hget k1 id

# 一次性获取k1中的id、name、age值
hmget k1 id name age

# 查看key为k1中的所有属性key 结果-> id name age
hkeys k1

# 查看key为k1中的所有属性key所对应的值 结果-> 1001 lucy 20
hvals k1

# 对key为k1中的age值+2
hincrby k1 age 2

4.Set

Common command operations in the Set collection type

# 添加 1 2 3 元素到t1集合中
sadd t1 1 2 3

# 删除t1集合中的3元素
srem t1 3

# 查看t1集合中是否包含4这个元素
sismember t1 4

# 查看t1集合中的所有元素
smembers t1

5.Zset

Common command operations in Zset ordered collection types

# 添加 java c++ php 到t1集合中,并指定相应的score值为 100 200 300
zadd t1 100 java 200 c++ 300 php

# 删除t1集合中的java元素
zrem t1 java

# 查看t1集合中索引从0到-1的所有元素(索引0代表第一个元素,索引-1代表最后一个元素)
# 结果 "java" "c++" "php" (按照score值进行从小到大排序)
zrange t1 0 -1

# 查看t1集合中索引从0到-1的所有元素,并显示相应的score值。
# 结果 "java" 100 "c++" 200 "php" 300
zrange t1 0 -1 withscores

# 查看t1集合中索引从0到-1的所有元素,并按倒序(从大到小)排序
# 结果 "php" "c++" "java"
zrevrange t1 0 -1

# 查看t1集合中索引从0到-1的所有元素,按倒序(从大到小)排序,并显示相应的score值。
# 结果 "php" 300 "c++" 200 "java" 100
zrevrange t1 0 -1 withscores

Supplement other common commands

# 查看符合正则表达式的所有key -> (keys pattern)
# 查看所有的key
keys *

# 删除对应的key
del key

# 设置key的过期时间为20s
expire key 20

# 查看key的过期时间(-1表示永久有效,-2表示已失效,其他数字表示剩余过期时间)
ttl key

3. Advanced knowledge

1. Data persistence

Since the data of Redis is written into the memory, the data is not persisted. When the server restarts, the data will be lost. Therefore, the data needs to be persisted and written to the disk.

  • RDB模式: According to the time interval set by the user, write the data that meets the conditions to the disk for backup.

    ​ Advantages and disadvantages: high efficiency, but the data in the last time interval may be lost.

  • AOF模式: Record all write operations into the log file, and restore data according to the log file when the server restarts.

    ​ Advantages and disadvantages: It can fully guarantee the reliability of data, but data recovery is relatively slow.

2. Master-slave replication

One server acts as the master server and is only responsible for writing operations, and the other servers act as slave servers of the master server and are only responsible for reading data.

Advantages: read-write separation, disaster recovery and fast recovery

Disadvantage: Replication delay (slave synchronization data has a certain delay)

  • 一仆二主: One master is connected to multiple slaves

  • 薪火相传: A master is connected to a slave, and a slave is connected under the slave

  • 反客为主: When the master machine is down, one of the slave machines slaveof no onewill upgrade (you can use the sentinel mode to automatically

    action completed)

  • 哨兵模式: Monitor the running status of the master, when the master is down, upgrade one of the slaves to the master.

3. Cluster

The cluster is to ensure the high availability of the service. When some servers go down, the service can continue to be provided.

advantage:

1. Can solve the problem of insufficient capacity.

  	  2. 能够解决高并发读写的问题,分摊服务器压力。
  	  2.  去中心化配置(任何一台服务器都可以作为入口服务器来进行读写)

4. Cache penetration

Cache penetration means that when querying a non-existent data, because Redis misses, the data will be queried in the database. When the data cannot be queried by the database, it will not be written into the cache, resulting in the non-existent data being queried every time. , will access the database, resulting in cache penetration.

Solution:

  1. Set the queried null value to the cache (set expiration time)
  2. Set up an accessible whitelist
  3. Bloom filter

5. Cache breakdown

Cache breakdown means that when some popular keys are accessed, the keys expire at this time, resulting in a large number of requests to the database and the database goes down.

6. Cache Avalanche

Cache avalanche means that in a very short period of time, a large number of queried keys expire, resulting in a large number of requests to the database and the database goes down.

7. Distributed lock

Distributed locks can guarantee synchronous operations, such as snap-up, spike, and ensure that there will be no problems such as overselling. The JAVA code is as follows:

public class SellServiceImpl implements SellService {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 库存总量
     */
    private static final Integer TOTAL = 1000;

    /**
     * 例如国庆大甩卖 图书大甩卖 库存 1000 件
     * 存放商品信息
     */
    static Map<String, Integer> products;

    /**
     * 抢购成功者信息
     */
    static Map<String, String> orders;

    static {
    
    
        products = new HashMap<>();
        orders = new HashMap<>();
        // 设置商品名称及库存
        products.put("book", TOTAL);
    }

    /**
     * 第一种方法 synchronized 锁机制,解决高并发产生的超卖问题 但效率大大降低 不推荐使用
     * 第二种方法 使用 Redis 分布式锁,解决高并发产生的超卖问题 并且效率相对高很多
     */
    @Override
    public String orderGoods(String productId) {
    
    
        String lockValue = UUID.randomUUID().toString();
        // 设置锁,并设置3s过期时间,防止手动释放锁之前程序出错,导致锁一直未释放。
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", lockValue, 3, TimeUnit.SECONDS);
        // 加锁失败 说明有人正在使用
        if (!lock) {
    
    
            return "抢购失败,请再试试吧...";
        }
        //先获取商品余量
        int number = products.get(productId);
        if(number <= 0){
    
    
            return "商品已抢购完,请您下次再来,谢谢您的理解...";
        }else {
    
    
            //模拟下单(不同用户拥有不同ID)
            orders.put(UUID.randomUUID().toString(), productId);
            //减库存
            number = number - 1;
            //模拟延迟
            try {
    
    
                Thread.sleep(200);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            products.put(productId, number);
        }
        log.info("共抢购 {} 件,抢购详情:{}", orders.size(), orders);
        // 手动解锁
        String value = (String) redisTemplate.opsForValue().get("lock");
        // 确保释放的锁是同一次设置的锁
        if (lockValue.equals(value)){
    
    
            redisTemplate.opsForValue().getOperations().delete("lock");
        }
        return "抢购成功!";
    }

    @Override
    public String queryGoods(String productId) {
    
    
        return "国庆图书大甩卖,库存 " +
                TOTAL + " 件,现余 " +
                products.get(productId) + " 件,已被抢购 " +
                orders.size() + " 件";
    }
}

Four, Redis integrated SpringBoot use

1. Introduce dependencies

<!-- Redis依赖 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. Configure the YML file

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    database: 0

3. Configure RedisTemplate

RedisTemplate can also be used without configuration, but the key and value are not serialized, which will cause the data stored in the Redis database to be in hexadecimal encoding format.

package cn.quicklyweb.flea.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * 自定义RedisTemplate
 */
@Configuration
public class RedisTemplateConfig {
    
    

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    
    
        // 创建RedisTemplate实例
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        
		// 创建Redis的String字符串序列化对象
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        // 创建Redis的Json字符串序列化对象
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        
        // key采用String的序列化方式
        redisTemplate.setKeySerializer(stringSerializer);
        // hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(stringSerializer);
        // value采用Jackson的Json序列化方式
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        // hash的value也采用Jackson的Json序列化方式
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        
		// 设置默认的序列化器为Jackson的Json序列化方式
        redisTemplate.setDefaultSerializer(genericJackson2JsonRedisSerializer);
        
		// 设置连接工厂
        redisTemplate.setConnectionFactory(factory);

        return redisTemplate;
    }
}

4. use

// 直接注入后便可操作Redis数据库了
@Autowired
private RedisTemplate redisTemplate

redisTemplate.opsForValue.set("key", "value")
redisTemplate.opsForValue.get("key")

Guess you like

Origin blog.csdn.net/L28298129/article/details/122146148