Detailed Explanation of Redis High Frequency Data Types

Table of contents

I. Introduction

2. Redis common data types

2.1 Common data types

3. String type

3.1 Introduction to String type

3.2 String common operation commands

3.2.1 String operation command practice

3.3 Common business scenarios

3.3.1 session sharing

3.3.2 Login failure counter

3.3.3 Current limiting

3.3.4 Multi-thread security control

4. Hash type

4.1 Introduction to hash data structure

4.2 Why use hash structure

4.3 hash common operation commands

4.3.1 Operation demonstration of common commands

4.4 Common hash business scenarios

4.4.1 Store data in object format

4.4.2 Cache hotspot data

4.4.3 Counting function

4.4.4 Data filtering

4.4.5 E-commerce shopping cart

5. List type

5.1 Introduction to list type

5.2 list type characteristics

5.3 Common commands of list type

5.3.1 List command summary

5.3.2 Operational Practices

5.4 list usage scenarios

5.4.1 Implement commonly used distributed data structures

5.4.2 Flash sale

5.4.3 Message queue

5.4.4 Leaderboard

5.4.5 Pagination query effect

5.4.6 Flow clipping

6. Set type

6.1 Introduction to Set

6.2 Common Commands of Set Type

6.3 Operation and usage of Set command

6.3.1 Operation demonstration of common commands

6.3.2 Core APIs

6.4 Set usage scenarios

6.4.1 User attention and recommendation model

6.4.2 Product/user portrait label

6.4.3 Lottery

6.4.4 Number of likes, favorites and likes

6.4.5 Statistical website's independent IP

Seven, SortedSet

7.1 Overview of SortedSet

7.1.1 SortedSet Features

7.2 Common operation commands

7.2 .1 Demonstration of operation commands

7.2.2 Core operation API

7.3 SortedSet usage scenarios

7.3.1 Leaderboard (TOP N)

7.3.2 Weighted message queues

7.3.3 Sliding window current limiting

7.3.4 Precisely set the expiration time data

Eight, written at the end of the text


I. Introduction

In the process of project development, we often encounter various unexpected business scenarios that need to be dealt with, such as counting the recent top 10 account visits of a certain website, or, for example, needing to send points to stimulate consumption according to the activity of the website account, etc. Database and program calculations can be realized, but is this purely programmatic solution the most efficient? Is there a more reasonable solution? This is what this article will introduce next, that is, the reasonable use of different data structures of redis can bring unexpected results to the solution of the problem.

2. Redis common data types

Redis provides a wealth of data structures, which is an important reason why its popularity has not diminished over the years. Different data structures correspond to different usage scenarios, and can be flexibly selected according to actual needs.

2.1 Common data types

Combined with practical experience, the commonly used data types of redis are summarized as follows:

  • String

  • Hash

  • List

  • Set

  • SortedSet

Each type is discussed in depth next.

3. String type

3.1 Introduction to String type

String type, that is, string type, is the simplest storage type in Redis. Its value is a string, but according to the format of the string, it can be divided into three categories:

  • string: ordinary string;

  • int: Integer type, which can perform self-increment and self-decrement operations;

  • float: Floating point type, which can perform self-increment and self-decrement operations;

Regardless of the format, the bottom layer is stored in the form of a byte array, but the encoding method is different. The maximum space of string type cannot exceed 512m

3.2 String common operation commands

The following lists the commonly used operation commands of the String type

  • SET: Add or modify an existing key-value pair of String type;

  • GET: Get the value of String type according to the key;

  • MSET: Add multiple key-value pairs of String type in batches;

  • MGET: Obtain multiple values ​​of String type according to multiple keys;

  • INCR: Increment an integer key by 1;

  • INCRBY: Let an integer key auto-increment and specify the step size, for example: incrby num 2 let the num value auto-increment by 2;

  • INCRBYFLOAT: Increment a floating-point number and specify the step size;

  • SETNX: Add a key-value pair of String type, provided that the key does not exist, otherwise it will not be executed;

  • SETEX: Add a key-value pair of String type and specify the validity period;

3.2.1 String operation command practice

set/get

mset/mget

SETNX

SEVEN

3.3 Common business scenarios

The String type data structure is simple and flexible to use. Based on the common commands listed above and combined with actual business experience, several commonly used business usage scenarios are summarized below;

3.3.1 session sharing

In Internet projects, login is essential. If your project is a multi-node deployment, how to realize session sharing for user login? A common practice is to store key session information generated by login, such as token, in redis, and token is often an encrypted string, so it is very suitable to use the data structure of string type of redis.

3.3.2 Login failure counter

You can use the ability of String self-increment to record the number of user login errors. Specifically, the implementation ideas and steps are as follows:

  • If there is a login error once, call the incr command to execute it once, the key can be the user ID, and the value is the value of incr;

  • When the number of consecutive login errors reaches a certain number, login is restricted;

  • If it does not reach a certain number, the next login is successful, and the current error record key will be cleared;

  • Then start accumulating again;

The following is the pseudo code of the business implementation, and the specific details can be considered in combination with the actual situation;

public String login(User user) {
        String userId = user.getId();
        if(!user.getUserName().equals("jerry") && !user.getPassWord().equals("123456")){
            if (redisTemplate.hasKey(userId)) {
                long failCount = (long)redisTemplate.opsForValue().get(userId);
                if(failCount < 3){
                    //如果密码不正确,登录失败,同时记录错误次数的值
                    redisTemplate.opsForValue().increment(userId,1);
                    return "登录失败";
                }
                return "登录失败错误次数超过3次,账户将会被锁定";
            }
            //首次登录失败
            redisTemplate.opsForValue().increment(userId,1);
            return "登录失败";
        }

        //TODO 执行登录业务 ...

        //如果登录失败的key值存在,则删除
        if(redisTemplate.opsForValue().get(user) != null){
            redisTemplate.delete(userId);
        }
        return "login success";
    }

3.3.3 Current limiting

In some scenarios, if the system recognizes that certain IPs or accounts are abnormal and frequently swipes the interface, the flow can be limited for such accounts or IPs. A common scenario is to send SMS verification codes, in order to prevent users from maliciously swiping SMS , the usual practice is to limit only one post within 1 minute. The general idea is as follows:

  • The first time you submit a request to send a text message, the background will push a verification code to the current mobile phone number, and at the same time, the background will use the IP or user ID as the key to record a piece of data in redis, and set the validity period of the key to 1 minute;

  • The user enters the account information and the correct SMS verification code to submit the request to the background, the verification passes, and the key in redis is deleted;

  • When submitting the request in the second step, if the input of the verification code fails to be submitted to the background, the login fails. At this time, the user clicks to send the verification code request again. The background detects that the key of the current user ID exists in redis, and gives an abnormal prompt, usually sending SMS too frequently;

  • After one minute, the key in redis expires, and the user can submit the request to send the SMS verification code again;

The following is a core pseudo-code, interested students can consider and improve the details

public static final String VERIFY_CODE = "login:verify_code:";

    public String getSmsVerifyCode(String userId,String phone) {
        String smsVerifyCode = getSmsVerifyCode();
        String smsCodeKey = VERIFY_CODE + ":" +userId;
        Object existedSmsCode = redisTemplate.opsForValue().get(smsCodeKey);
        //如果验证码已经存在
        if (Objects.nonNull(existedSmsCode)) {
            Long expireTime = "从redis中获取当前key的过期时间";
            //剩余时间
            long lastTime = "总时间" - expireTime;
            //三分钟内验证码有效,1分钟到3分钟之间,用户可以继续输入验证码,也可以重新获取验证码,新的验证码将覆盖旧的
            if(lastTime > 60 && expireTime >0){
                //调用第三方平台发短信,只有短信发送成功了,才能将短信验证码保存到redis
                System.out.println("此处调用短信发送逻辑......");
                redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, "总的过期时间", TimeUnit.SECONDS);
            }
            //一分钟之内不得多次获取验证码
            if(lastTime < 60){
                throw new RuntimeException("操作过于频繁,请一分钟之后再次点击发送");
            }
        }else {
            System.out.println("此处调用短信发送逻辑......");
            redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, "总的过期时间", TimeUnit.SECONDS);
        }
        return smsVerifyCode;
    }

    /**
     * 随机获取6位短信数字验证码
     *
     * @return
     */
    public static String getSmsVerifyCode() {
        Random random = new Random();
        String code = "";
        for (int i = 0; i < 6; i++) {
            int rand = random.nextInt(10);
            code += rand;
        }
        return code;
    }

3.3.4 Multi-thread security control

Utilizing the atomicity feature of the setnx command, it is used as a lock in a multi-threaded concurrent scenario. In the related distributed lock solution or SDK of redis, the underlying layer uses the characteristics of setnc to implement the lock mechanism.

4. Hash type

4.1 Introduction to hash data structure

Hash type, also called hash, its value is an unordered dictionary, similar to the HashMap structure in Java. In layman's terms, hash is a key-value pair (key-value) collection, which is often used to store object data, similar to Map<String, Object> in Java.

This naming method (hash format) can be adopted: the object category and ID form the key name, and the field is used to represent the attribute of the object, while the field value stores the attribute value.

The following is an example format for storing data of the hash type:

The storage format in redis is as follows: 

4.2 Why use hash structure

When using redis as a cache, using the String type structure can also satisfy most scenarios, and even store the object in the String type format after json serialization, but when the program involves the operation of modifying object properties, use the String type It is more troublesome when modifying field properties. In summary, using hash can help developers solve the following problems:

  • Object data can be stored like Java, and the attribute values ​​in the object can be modified more conveniently;

  • The hash structure can be stored independently for each field in the object, that is, adding, deleting, modifying and checking for a single field;

  • Put the data with the same type of rules into a data container in redis, so that it is easy to find the data;

  • Use hash to save memory. In the hash type, a key can correspond to multiple fields, and a field corresponds to a value. Compared with storing each field as a string type separately, it can save memory.

4.3 hash common operation commands

Common operation commands for hash are as follows:

HSET key field value: add or modify the field value of the hash type key;

HGET key field: get the field value of a hash type key;

HMSET: Add multiple field values ​​of hash type keys in batches;

HMGET: Get the field values ​​of multiple hash type keys in batches;

HGETALL: Get all fields and values ​​in a hash type key;

HKEYS: Get all the fields in a hash type key;

HVALS: Get all the values ​​in a hash type key;

HINCRBY: Let the field value of a hash type key auto-increment and specify the step size;

HSETNX: Add a field value of a hash type key, provided that the field does not exist, otherwise it will not be executed

4.3.1 Operation demonstration of common commands

hset/hget

The data format stored in redis is as follows, is this very similar to the object storage format in Java;

Obtain the object key added above through the command;

HMSET/HMGET

Use this command to batch store multiple attribute values ​​for an object key

 

HGETALL

Get all fields and values ​​in a hash type key

HKEYS/WHALES

Similar to traversing all keys and values ​​in the map

HINCRBY

Increase a certain field in the hash, similar to the self-increment of the field value for the key in the String type, and you can specify the step size

4.4 Common hash business scenarios

4.4.1 Store data in object format

Cache the queried object data in the program. Although you can use the String structure to serialize and store the object in JSON, it is not very convenient when you want to modify a certain attribute later, so you can consider it in this case. Using hash storage, its structure is similar to Java objects, and it is very convenient to modify attribute values. The corresponding code is as follows:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SingleApp.class)
public class RedisHashTest {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    //单个设置
    @Test
    public void saveSingle(){
        redisTemplate.opsForHash().put("user:002","name","jike");
        redisTemplate.opsForHash().put("user:002","age",21);
        redisTemplate.opsForHash().put("user:002","city","广州");
        System.out.println("保存成功");
    }

    @Test
    public void getSingle(){
        Object id = redisTemplate.opsForHash().get("user:001", "id");
        Object name = redisTemplate.opsForHash().get("user:001", "name");
        System.out.println("id:" + id);
        System.out.println("name:"+ name);
    }

    //批量设置多个值
    @Test
    public void saveHashMulti(){
        Map<String,Object> userMap = new HashMap();
        userMap.put("id","001");
        userMap.put("name","jerry");
        userMap.put("age","19");
        redisTemplate.opsForHash().putAll("user:001",userMap);
        System.out.println("保存成功");
    }

    //获取多个值
    @Test
    public void getMultiVal(){
        List<Object> objects = redisTemplate.opsForHash().multiGet("user:001", Arrays.asList("id", "name"));
        objects.forEach(item ->{
            System.out.println(item);
        });
    }

}

The storage format corresponding to redis is as follows, is it similar to object storage

4.4.2 Cache hotspot data

For the following scenarios, you can selectively store hotspot data with frequent access and small field value changes in a hash type structure:

  • User information: basic user information, such as user name, password, email address, mobile phone number and other common fields;

  • Order data: basic order information, such as order number, order time, order status, delivery address, etc., which can be considered in high-concurrency flash sales;

  • Product information: product-related information, such as product name, price, inventory, etc.;

  • Configuration information: application configuration information, such as middleware connection configuration information, cache configuration information, gateway configuration information, etc.;

  • Statistical information: Store the statistical information calculated in the application, such as the number of visits of a certain user on the website, user activity, user purchase times, purchase order quantity, etc.;

4.4.3 Counting function

Many places in the system may involve statistics and counts of certain behaviors of accounts, such as the number of times an account visits product details on an e-commerce website, the number of times orders are placed, the number of purchases, and so on. The hash structure of redis provides a function for counting, so it can be implemented based on this function. The pseudo code is as follows:

//1. Interface request;
//2. Take out the key corresponding to the hash in redis;
//3. Check whether the key exists;
//4. If the key exists, take out the attribute field corresponding to the statistical value and execute the incr function;
//5. Return the latest incr value for display

4.4.4 Data filtering

For example, for those accounts with malicious swiping requests, once captured by the system, the account information can be stored in the hash, and then once the system captures the same malicious request of the account again, it will be filtered or given a relevant risk warning.

4.4.5 E-commerce shopping cart

For example, in an e-commerce shopping cart, in order to speed up the performance of the page, the key data of the account's shopping cart information can be stored in a hash structure. The following is the format and implementation idea of ​​a shopping cart product data stored using hash;

5. List type

5.1 Introduction to list type

The List type is similar to the LinkedList in Java. It can be regarded as a two-way linked list structure, which can support both forward and reverse retrieval. When used, it can be used analogously to LinkedList.

5.2 list type characteristics

  • The list type is used to store multiple ordered strings, each character in the list is regarded as an element, and the internal data can be repeated;

  • One or more elements can be stored in a list, and the redis list supports storing 2^32 power-1 elements;

  • The elements in the list are ordered, and redis can insert (pubsh) and pop (pop) elements from both ends of the list, and supports operations such as reading a set of elements in a specified range, or reading elements with a specified subscript;

  • The redis list is a more flexible linked list data structure, which can act as a queue or a stack;

  • Because its structure is similar to a linked list, data insertion and deletion are faster, and the performance of data retrieval is average;

5.3 Common commands of list type

5.3.1 List command summary

LPUSH key element ...

Insert one or more elements to the left of the list;

LPOP key

Remove and return the first element on the left of the list, or nil if there is none;

RPUSH key element ...

Insert one or more elements to the right of the list

RPOP key

Remove and return the first element on the right side of the list

LRANGE key star end

Returns all elements within a subscript range

BLPOP and BRPOP

Similar to LPOP and RPOP, except that it waits for the specified time when there are no elements, instead of returning nil directly

5.3.2 Operational Practices

lpush

From the data structure effect shown, the effect of using lpush is as follows:

rpush

This is exactly the opposite effect of lpush

LPOP  

Take out elements from the left side of the list list. Taking the above list1 as an example, the elements from left to right are: p5, p4, p3, p2, p1. It is assumed that when using this command, the p5 element will be taken out first, and there are no elements will return nil at this time, and RPOP is the opposite;

LRANGE

Get the data in the specified subscript range

BLPOP

Similar to the effect of a blocking queue, it will block and wait to get elements from the list, and return nil if there is no element. As follows, use BLPOP to wait to get elements from list3. Obviously, list3 does not currently exist and has no elements, so after executing this command, You can see the blocking effect, the third parameter is the blocking waiting time, that is, you don't have to wait infinitely;

At this time, add an element to list3 on another client, and see the following effect

5.4 list usage scenarios

5.4.1 Implement commonly used distributed data structures

Combining the above operation practices and using the characteristics of the list, the following commonly used data structures can be realized

  • Stack (stack): LPUSH + LPOP;

  • Queue (queue): LPUSH + RPOP;

  • Blocking MQ (blocking queue): LPUSH + BRPOP;

The effect of the stack can be clearly seen through the following code and output results

    @Test
    public void saveList(){
        redisTemplate.opsForList().leftPush("user1","jerry");
        redisTemplate.opsForList().leftPush("user1","mike");
        redisTemplate.opsForList().leftPush("user1","hang");

        System.out.println("插入3个元素,分别为:jerry,mike,hang");
        System.out.println("============");
        List<Object> user1 = redisTemplate.opsForList().range("user1", 0, 3);
        user1.forEach(item ->{
            System.out.println("依次取出当前的元素:" + item);
        });
        System.out.println("============");

        Object user11 = redisTemplate.opsForList().leftPop("user1");
        Object user12 = redisTemplate.opsForList().leftPop("user1");
        Object user13 = redisTemplate.opsForList().leftPop("user1");
        System.out.println("取出的元素依次为:" + user11 + "," + user12 + "," + user13);
    }

5.4.2 Flash sale

Students who are familiar with the flash sale business scenario should be familiar with this. Before the official start of a specific product rush purchase, it is necessary to determine the number of products participating in the rush purchase. If the database is directly operated during the rush purchase, this performance is inefficient, so You can consider using the list structure of redis to initialize the list of product IDs participating in the snap-up into the list in advance. When snapping up, the products can be directly taken out of the list. The main implementation ideas are as follows:

1. The products participating in the snap-up are scattered and put into the list;

2. Call the pop command to take out from the list when snapping up;

3. Write the ID records of the users who snapped up successfully and the product IDs to the database;

4. Other follow-up business processing;

The following is a core piece of code about snapping up for reference. The first paragraph is to pre-store the products participating in the snapping up into the list, and the second paragraph is the logic of snapping up

    @Resource
    private RedisTemplate redisTemplate;

    @Scheduled(cron = "0/5 * * * * ?")
    public void startSecKill(){
        List<PromotionSecKill> list  = promotionSecKillMapper.findUnstartSecKill();
        for(PromotionSecKill ps : list){
            System.out.println(ps.getPsId() + "秒杀活动启动");
            //删掉以前重复的活动任务缓存
            redisTemplate.delete("seckill:count:" + ps.getPsId());
            /**
             * 有多少库存商品,则初始化几个list对象
             * 实际业务中,可能是拿出部分商品参与秒杀活动,通过后台的界面进行设置
             */
            for(int i = 0 ; i < ps.getPsCount() ; i++){
                redisTemplate.opsForList().rightPush("seckill:count:" + ps.getPsId() , ps.getGoodsId());
            }
            ps.setStatus(1);
        }
    }

panic buying logic

    @Resource
    private RedisTemplate redisTemplate;

    public void processSecKill(Long psId, String userid, Integer num) throws SecKillException {
        PromotionSecKill ps = promotionSecKillMapper.findById(psId);
        if (ps == null) {
            throw new SecKillException("秒杀活动不存在");
        }
        if (ps.getStatus() == 0) {
            throw new SecKillException("秒杀活动未开始");
        } else if (ps.getStatus() == 2) {
            throw new SecKillException("秒杀活动已结束");
        }
        Integer goodsId = (Integer) redisTemplate.opsForList().leftPop("seckill:count:" + ps.getPsId());
        if (goodsId != null) {
            //判断是否已经抢购过
            boolean isExisted = redisTemplate.opsForSet().isMember("seckill:users:" + ps.getPsId(), userid);
            if (!isExisted) {
                System.out.println("抢到商品啦,快去下单吧");
                redisTemplate.opsForSet().add("seckill:users:" + ps.getPsId(), userid);
            }else{
                redisTemplate.opsForList().rightPush("seckill:count:" + ps.getPsId(), ps.getGoodsId());
                throw new SecKillException("抱歉,您已经参加过此活动,请勿重复抢购!");
            }
        } else {
            throw new SecKillException("抱歉,该商品已被抢光,下次再来吧!");
        }
    }

5.4.3 Message queue

Using the BLPOP feature of redis, a message queue can be implemented. The producer pushes the message to the list, and the consumer obtains the message from the list through BLOP blocking for consumption.

5.4.4 Leaderboard

Utilize the data order of the list and the feature of supporting index access elements, store the sorted elements in the list in advance, such as the player's points, personal learning time, etc., and then the extracted data can be sorted from high to low to achieve a The effect of leaderboards.

5.4.5 Pagination query effect

Based on the feature that list supports index access elements and elements can be accessed through range, data pagination can be realized. Of course, such data is usually the ID or unique element of frequently queried hot data.

5.4.6 Flow clipping

During peak business hours, if the system's server has limited ability to process requests, you can consider putting all the requests in the list, and then open multiple threads to process subsequent requests to reduce server pressure, which can be used to handle some high-concurrency scenarios.

6. Set type

6.1 Introduction to Set

The redis collection (set) type is similar to the list list type and can be used to store a collection of multiple string elements. But unlike list, duplicate elements are not allowed in the set collection. Moreover, the elements in the set collection are out of order, and there is no element subscript.

The set type is constructed using a hash table, so the complexity is O(1). It supports addition, deletion, modification and query within the set, and supports intersection, union, and difference operations between multiple sets. Compared with the set in Java, it can be understood and used, and these set operations can be used to solve problems between many data sets in the development process.

6.2 Common Commands of Set Type

The commonly used operation commands of Set are summarized as follows:

  • SADD key member ... : Add one or more elements to the set;

  • SREM key member ... : Remove the specified element in the set;

  • SCARD key: returns the number of elements in the set;

  • SISMEMBER key member: determine whether an element exists in the set;

  • SMEMBERS: Get all elements in the set;

  • SINTER key1 key2 ... : Find the intersection of key1 and key2;

  • SDIFF key1 key2 ... : Find the difference between key1 and key2;

  • SUNION key1 key2 ..: Find the union of key1 and key2;

6.3 Operation and usage of Set command

6.3.1 Operation demonstration of common commands

sadd/smembers

Add elements and view elements

As you can see, the elements stored in the set are unordered

SHAME

remove elements from set

SCARD

Return the number of elements

SISM MEMBER

Check if an element is in a set

SINTER key1 key2

Find the intersection of two sets

6.3.2 Core APIs

The following are related APIs for using redisTemplate to operate set

    @Test
    public void opeSet(){
        redisTemplate.opsForSet().add("set1","a","b","c","d","e");
        redisTemplate.opsForSet().add("set2","d","e","f","j");

        Set<Object> set1 = redisTemplate.opsForSet().members("set1");
        set1.forEach(item ->{
            System.out.println("item :" + item);
        });

        //是否set的元素
        Boolean member = redisTemplate.opsForSet().isMember("set1", "a");
        System.out.println(member);

        //求交集
        Set<Object> difference = redisTemplate.opsForSet().difference("set1", "set2");
        difference.forEach(item ->{
            System.out.println(item);
        });

    }

6.4 Set usage scenarios

6.4.1 User attention and recommendation model

For example, in social networking sites, it is a good choice to use Set for operations such as my followers and fans.

user1 : My followers:

sadd user1:fans user2 sadd user1:fans user4 sadd user1:fans user5 ...

user2 : People I follow:

sadd user2:follow user1 sadd user2:follow user3 sadd user2:follow user5 sadd user2:follow user7 ...

Based on the above data, it is possible to find people that user1 and user2 may know respectively, which are fans or follow recommendations

6.4.2 Product/user portrait label

In e-commerce or group-buying websites, you often see a lot of labels under the details of certain products, such as a certain fruit product, which tastes good, is fresh, and is delivered quickly, etc. You can consider using set to save the labels information;

sadd tags:productId "Good taste"

sadd tags:productId "Fresh"

sadd tags:productId "Fast delivery

6.4.3 Lottery

Using the SRANDMEMBER in the set combined with the SPOP operation, the lottery function can be realized, that is, the specified number of elements can be randomly obtained from the set set each time. The implementation idea is as follows:

sadd random user1 user2 user3 user4 user5 user6 user7 user8 user9

srandmember random 2 # Randomly take out the specified number of elements without deleting

spop random 2 # Randomly take out the specified number of elements and delete elements

After one draw, those who have been drawn can continue to participate in the lottery by using srandmember;

After drawing once, the person who has been drawn will be removed from the set and cannot continue to participate in the lottery, use spop;

6.4.4 Number of likes, favorites and likes

In some social apps, Weibo or short video apps, the functions of likes, favorites or favorites that are often seen can be realized based on set. The implementation ideas are as follows:

like

sadd like: Video ID {userId}

cancel like

srem like: Video ID {userId}

Whether the user likes

sismember like: Video ID {userId}

Liked user list

smembers like: Video ID

The number of users who get likes

scard like: Video ID

6.4.5 Statistical website's independent IP

Using the uniqueness of the elements in the set collection, you can quickly and real-time count the independent IPs that visit the website.

Seven, SortedSet

7.1 Overview of SortedSet

SortedSet is a sortable set collection, somewhat similar to TreeSet in Java, but the underlying data structure is very different. Each element in the SortedSet has a score attribute, and the elements can be sorted based on the score attribute. The underlying implementation is a skip list (SkipList) plus a hash table.

Sorted collections can be sorted from small to large using scores. Although the members of an ordered set are unique, the scores can be repeated. For example, in a class, the student's student number is unique, but the grades of each subject can be the same. Redis can use ordered collections to store student grades and quickly perform grade ranking functions.

7.1.1 SortedSet Features

SortedSet has the following characteristics:

  • sortable;

  • elements are not repeated;

  • Fast query speed;

7.2 Common operation commands

The commonly used operation commands of SortedSet are as follows:

  • ZADD key score member: Add one or more elements to the sorted set, and update its score value if it already exists;

  • ZREM key member: delete a specified element in the sorted set;

  • ZSCORE key member: Get the score value of the specified element in the sorted set;

  • ZRANK key member: Get the rank of the specified element in the sorted set;

  • ZCARD key: Get the number of elements in the sorted set;

  • ZCOUNT key min max: Count the number of all elements whose score value is within a given range;

  • ZINCRBY key increment member: Let the specified element in the sorted set auto-increment, and the step size is the specified increment value;

  • ZRANGE key min max: After sorting by score, get the elements within the specified ranking range;

  • ZRANGEBYSCORE key min max: After sorting by score, get the elements within the specified score range;

  • ZDIFF, ZINTER, ZUNION: find difference, intersection, union;

Note: By default, when using SortedSet, the ranking of elements in the set is in ascending order. If you want to descend, add REV after the command;

7.2 .1 Demonstration of operation commands

ZADD

Adds one or more elements to the SortedSet

From the added data, the elements in the SortedSet are ordered, that is, they are sorted in ascending order according to the score

ZSCORE key member

Get the score value of the specified element

ZRANK key member

Get the rank of the specified element

7.2.2 Core operation API

Commonly used API operations are listed below, of course it is far more than these, you can continue to operate on this basis

    @Test
    public void opeZSet(){
        //添加元素
        redisTemplate.opsForZSet().add("urank","user1",99);
        redisTemplate.opsForZSet().add("urank","user2",88);
        redisTemplate.opsForZSet().add("urank","user3",95);
        redisTemplate.opsForZSet().add("urank","user4",79);
        redisTemplate.opsForZSet().add("urank","user5",82);

        //获取某个元素的分值
        Double score = redisTemplate.opsForZSet().score("urank", "user1");
        System.out.println(score);

        //统计排名0~3的元素
        Set<Object> users = redisTemplate.opsForZSet().range("urank", 0, 3);
        users.forEach(item ->{
            System.out.println(item);
        });

        //获取某元素的排名
        Long rank = redisTemplate.opsForZSet().rank("urank", "user5");
        System.out.println(rank);

    }

7.3 SortedSet usage scenarios

7.3.1 Leaderboard (TOP N)

Many websites have a ranking function. For example, news websites can be ranked at the top according to the highest number of reads or likes, and game websites can be ranked according to individual player points. There are many similar scenarios, all of which can be based on SortedSet to achieve the score in .

7.3.2 Weighted message queues

Using SortedSet can implement a weighted message queue. Specifically, different messages are given different weights and stored in SortedSet. When consuming messages, messages with high weights can be preferentially obtained for processing;

7.3.3 Sliding window current limiting

Use the score as a timestamp to count the number of members in the most recent period and realize sliding window current limiting.

7.3.4 Precisely set the expiration time data

You can set the score value in the sorted set as the timestamp of the expiration time, then you can simply sort by the expiration time and clear the expired data regularly, not only to clear the expired data in Redis, but you can completely use the expiration time in Redis as It is an index to the data in the database. Redis is used to find out which data needs to be expired and deleted, and then accurately delete the corresponding records from the database.

Eight, written at the end of the text

Regarding the common data types of redis, it can be said that they can be seen everywhere in daily work. Systematic learning and in-depth mastery of the use of these different data structures can better provide developers with efficient solutions in the face of complex and changeable business scenarios. Solutions, to speed up the efficiency of problem solving, is also an essential skill for an excellent development engineer.

Guess you like

Origin blog.csdn.net/zhangcongyi420/article/details/132132764