redis entry to give up - 2

Posted by ForgotMyPass on Tue, 04 Jan 2022 06:41:51 +0100

8. Spring boot integrates redis

Import dependency

 <!--redis rely on-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
<!--            <version>2.1.6.RELEASE</version>-->
        </dependency>
        <!--Spring2.x integrate redis what is needed common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
<!--            <version>2.6.2</version>-->
        </dependency>

Configure redis information (application.properties)

# REDIS (RedisProperties)
# Redis database index (0 by default)
spring.redis.database=0
# Redis server address
spring.redis.host=
# Redis server connection port
spring.redis.port=
# Redis server connection password (blank by default)
spring.redis.password= 
# Maximum number of connections in the connection pool (negative value indicates no limit)
spring.redis.jedis.pool.max-active=8
# Maximum blocking wait time of connection pool (negative value indicates no limit)
spring.redis.jedis.pool.max-wait=-1
# Maximum free connections in the connection pool
spring.redis.jedis.pool.max-idle=8
# Minimum free connections in connection pool
spring.redis.jedis.pool.min-idle=0
# Connection timeout (MS)
spring.redis.timeout=5000
#
#redis:
## Redis database index (0 by default)
#database: 0
## Redis server address
#host: 127.0.0.1
## Redis server connection port
#port: 6379
## Redis server connection password (blank by default)
#password:
## Maximum number of connections in the connection pool (negative value indicates no limit)
#jedis:
#pool:
#max-active: 8
## Maximum blocking wait time of connection pool (negative value indicates no limit)
#max-idle: 8
## Maximum free connections in the connection pool
#max-wait: -1
## Minimum free connections in connection pool
#min-idle: 0
## Connection timeout (MS)
#timeout: 0

Configure redis tool class

package com.example.springbootredis.util;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.CachingConfigurerSupport;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.jackson2JsonRedisSerializer();

        //String serialization
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //The key is serialized by string
        template.setKeySerializer(stringRedisSerializer);
        //The key of hash is serialized by string
        template.setHashKeySerializer(stringRedisSerializer);
        //jackson is also used for value serialization
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //The value of hash is also jackson
        template.setHashValueSerializer( jackson2JsonRedisSerializer);
        template.afterPropertiesSet();

        return template;
    }

    /**
     * Custom jackson2JsonRedisSerializer object
     * @return
     */
    private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
                new Jackson2JsonRedisSerializer<>(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // This item must be configured, otherwise it will report Java lang.ClassCastException: java. util. LinkedHashMap cannot be cast to XXX
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL
                , JsonTypeInfo.As.PROPERTY);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

}

Control layer

package com.example.springbootredis.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author wzh
 * @date 2021/12/22 10:47
 */
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping
    public String testRedis(){
        //Set value to redis
        redisTemplate.opsForValue().set("name","lucy");
        //Get value from redis
        String name = (String) redisTemplate.opsForValue().get("name");
        return name;
    }
}

9. Redis transaction operation

Redis transaction definition

Redis transaction is a separate isolation operation: all commands in the transaction will be serialized and executed sequentially. During the execution of the transaction, it will not be interrupted by command requests sent by other clients.

The main function of Redis transaction is to concatenate multiple commands to prevent other commands from jumping in the queue

Multi,Exec,discard

Starting from entering the Multi command, the entered commands will enter the command queue in turn, but will not be executed. After entering Exec, Redis will execute the commands in the previous command queue in turn

In the process of team formation, you can give up team formation through discard

Error handling of case transactions

Team successfully submitted

An error is reported in the queue forming stage, and the submission fails: when an error occurs in a command in the queue, all queues of the whole queue will be cancelled during execution

Teaming success and submission failure: if an error is reported in a command in the execution phase, only the error reported command will not be executed, and other commands will be executed

Transaction conflict problem

Pessimistic lock

Every time I go to get the data, I think others will modify it, so I lock it every time I get the data, so that others will block the data until they get the lock. Many such locking mechanisms are used in traditional relational databases, such as row lock, table lock, read lock and write lock, which are locked before operation

Optimistic lock

Every time I go to get the data, I think others will not modify it, so it will not be locked. However, when updating, I will judge whether others have updated the whole data during this period. I can use mechanisms such as version number. Optimistic locking is suitable for multi read applications, which can improve throughput. Redis uses this check and set mechanism to implement transactions

WATCH key [key ...]

Before executing multi, execute watch key1 [key2] to listen to one (or more) keys. If this (or these) key is changed by other commands before the transaction is executed, the transaction will be interrupted

unwatch

Cancel the monitoring of all key s by the watch command

If the EXEC command or DISCARD command is executed first after the watch command is executed, there is no need to execute UNWATCH.

Redis transaction three features

  • Separate isolation operation

    All commands in a transaction are serialized and executed sequentially. During the re execution of the transaction, it will not be interrupted by the command request sent by other clients.

  • There is no concept of isolation level

    The commands in the queue will not be actually executed until the transaction is committed, because any instructions will not be actually executed until the transaction is committed

  • Atomicity is not guaranteed

    If a command fails to execute in a transaction, the subsequent commands will still be executed without rollback

10. Second kill case

Stand alone version

package com.example.springbootredis.controller;


import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;

/**
 * @author wzh
 * @date 2021/12/22 10:47
 */
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping
    public String testRedis(){
        //Set value to redis
        redisTemplate.opsForValue().set("name","lucy");
        //Get value from redis
        String name = (String) redisTemplate.opsForValue().get("name");
        return name;
    }

    //Second kill process
    public static boolean doSecKill(String uid,String prodid) throws IOException{
        //1. Judgment of uid and prodid non null
        if (uid == null || prodid == null){
            return false;
        }
        //2. Connect to redis. Everyone's privacy is not shown
        Jedis jedis = new Jedis("*****", &&&&&);
        jedis.auth("****");

        //3 splicing key
            //3.1 inventory key
        String kcKey = "sk:"+prodid+":qt";
            //3.2 second kill successful user key
        String userKey = "sk:" + prodid+":user";
        //4. Get the inventory. If the inventory is null, the second kill has not started yet
        String kc = jedis.get(kcKey);
        if(kc == null){
            System.out.println("The second kill has not started yet. The request failed");
            jedis.close();
            return false;
        }
        //5 judge whether the user repeats the second kill operation
        if (jedis.sismember(userKey,uid)){
            System.out.println("The second kill has been successful. You can't repeat the second kill");
            jedis.close();
            return false;
        }
        //6. Judge if the commodity quantity and inventory quantity are less than 1, the second kill is over
        if (Integer.parseInt(kc)<=0){
            System.out.println("The second kill is over");
            jedis.close();
            return false;
        }
        //7 second kill process
        //7.1 inventory-1
        jedis.decr(kcKey);
        //7.2 add successful users to the list
        jedis.sadd(userKey,uid);
        System.out.println("Second kill success");
        jedis.close();
        return true;
    }
}

test

 @Test
    public void test1() throws IOException {
        Random random = new Random();
        int j;
        for (int e = 0; e < 10; e++) {
            String uid = "";
            for (int i = 0; i <10 ; i++) {
                j = random.nextInt(10);
                uid += j;
            }
            RedisTestController.doSecKill(uid,"0101");
        }

    }

Second kill concurrent resolution

Install ab
Install on ECS
yum install httpd-tools
ab --help
 Ask for help and you can see many ways to use it
Install this machine on the official website and configure environment variables

https://www.apachehaus.com/cgi-bin/download.plx

Use ab
ab -c concurrency   Concurrency
Number of multiple requests to make at a time The number of concurrent multiple requests issued at one time

ab -n requests request
Number of requests to perform Number of requests executed

-p postfile     Publish file
File containing data to POST. Remember also to set -T Include to POST File of data. Also remember the settings-T

 -T content-type 
 Content-type header to use for POST/PUT data, eg.
 'application/x-www-form-urlencoded'Default is 'text/plain'be used for POST/PUT The content type header of the data, for example. “ application/ x-www-form-urlencoded"The default is text/"Normal"
 
 ab -n 1000 -c 100 -p /home/test/postfile -T application/x-www-form-urlencoded http://172.16.17.225:8080/redisTest/doSecKill

ab -n 1000 -c 100 -p /home/test/postfile -T application/x-www-form-urlencoded localhost:8080/redisTest/doSecKill

Connection timeout problem handling

After increasing the concurrency of ab test and the total number of requests, there will be a connection timeout problem due to optimistic lock. The first point does not arrive in seconds, and the second point grabs it.

processing method
1. Create JedisPoolUtils tool class

package com.example.springbootredis.util;

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

public class JedisPoolUtils {
    private static volatile JedisPool jedisPool = null;

    private JedisPoolUtils(){

    }

    public static JedisPool getJedisPoolInstance() {
        if(null == jedisPool) {
            synchronized (JedisPoolUtils.class) {
                if(null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxIdle(32);
                    poolConfig.setMaxWaitMillis(100*1000);
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig,"8.130.16.99",7777,60000,"123qwe");
                }
            }
        }
        return jedisPool;
    }

    public static void release(JedisPool jedisPool, Jedis jedis) {
        if(null != jedis) {
            jedisPool.returnResource(jedis);
        }
    }
}


2. Get jedis object using connection pool

//Get jedis object through connection pool
        JedisPool jedisPoolInstance = JedisPoolUtils.getJedisPoolInstance();
        Jedis jedis = jedisPoolInstance.getResource();
Oversold problem


View inventory as - 190


resolvent

1. Monitor inventory
jedis.watch(kcKey);

2. Use transaction

//Use transaction
        Transaction multi = jedis.multi();

        //Team operation
        multi.decr(kcKey);
        multi.sadd(userKey,uid);
        //implement
        List<Object> results = multi.exec();

        if (results == null || results.size() ==0){
            System.out.println("The second kill failed....");
            jedis.close();
            return false;
        }
Solve inventory problems
LUA script

Lua is a small script language that can be called by C + + code or C + + functions in turn. Lua does not provide a powerful library. A complete Lua interpreter is only 200k, so Lua is not suitable for developing applications independently, but an embedded script language.


Topics: Database Redis Cache