[Redis] In-depth exploration of Redis data types - string string


Preface

string The string type is the most basic data type in Redis. You should pay attention to the following points about the string type:

  1. In Redis, all key types are of string type, and several other data types are also built on the basis of string types. For example, the elements of lists and sets are all of string type.
  2. In Redis, strings are stored directly in binary form, so when using Redis, there is no need to consider encoding issues like MySQL (mismatched encoding will cause garbled characters). Therefore, Redis will not handle the character set encoding issue. The character set encoding used in the command passed in by the client will be stored.
  3. The string type value in Redis can be a string, a string in JSON or XML format, a number, an integer, a floating point number, or even binary stream data, such as pictures, audio, videos, etc. However, the maximum value of a string cannot exceed 512MB.

1. String type operation commands

Set and get related commands

1. SET and GET

a)SET:

The function of the SET command is to set the value of string type into Redis. If the key already exists before setting, no matter what the original data type is, the original value will be overwritten, and the TTL set by the key will also be invalid.

SET syntax:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

Option description:

  • EX seconds: Set the expiration time of the key in seconds, equivalent to EXPIRE;
  • PX milliseconds: Set the expiration time of the key in milliseconds, equivalent to PEXPIRE;
  • NX: Set only when the key does not exist. If the key already exists before, the setting will not be executed;
  • XX: Set only when the key exists. If the key does not exist, the setting will not be performed.

Precautions:

  1. []Only one of the options within can be selected, []while the options in between can exist at the same time. That is, EXthe and PXoptions cannot exist at the same time, and NXand XXcannot exist at the same time, because they are mutually exclusive.
  2. The SET command with options can be replaced by commands such as SETEX, PSETEX, and SETNX.

return value:

  • If the setting is successful, OK is returned.
  • If the NX or XX option is specified by SET but the conditions are not met, the execution fails and returns nil.

Usage example:

EX and PX:

NX and XX

SET, SET NX, SET XXExecution process:

b)GET

The function of the GET command is to obtain the value corresponding to the key. If the key does not exist, it will be returned nil. If the data type of the value is not string, an error will be reported.

Usage example:

2. MSET and MGET

The function of MSET is to set multiple key-value pairs at one time; while the function of MGET is to obtain the value of multiple keys at one time. If the corresponding key does not exist or the corresponding data type is not string, it will be returned nil.

Use Cases:

a)MSET:

b)MGET:

Precautions:

As mentioned in the previous article, Redis processes tasks in a single thread, and the Redis client and server communicate through the network. Therefore, when you want to set or obtain multiple keys, it is recommended to operate at the same time. To reduce the number of network requests.

3. SETNX、SETEX、SETPX

a) The function of the SETNX command is to set the key if it does not exist, otherwise it will not be set, for example:


b) The SETEX command is used to specify the expiration time in seconds when setting the key.

grammar:

SETEX key seconds value

For example:

c) The purpose of the PSETEX command is to specify the millisecond expiration time when setting the key.

grammar:

SETEX key milliseconds value

For example:

Counting related commands

1. INCR and INCRBY

  1. INCR

INCRThe function of the command is to add one to the number represented by the string corresponding to the key.

  • If the key does not exist, the value corresponding to the key is considered to be 0, and then one is added;
  • If the value corresponding to the key is not an integer or its range exceeds a 64-bit signed integer, an error will be reported;
  • If INCRthe execution is successful, the value increased by one is returned, otherwise the corresponding error message is returned.

Usage example:

  1. INCRBY

INCRBYThe function of the command is to add a specified integer to the integer represented by the string corresponding to the key.

  • If the key does not exist, the value corresponding to the key is considered to be 0, and then the specified number is added;
  • If the value corresponding to the key is not an integer or its range exceeds a 64-bit signed integer, an error will be reported;
  • If INCRBYthe execution is successful, the added value is returned, otherwise the corresponding error message is returned.

Usage example:

2. DECR and DECRBY

  1. DECR

DECR The function of the command is to decrement the number represented by the string corresponding to the key by one.

  • If the key does not exist, the value corresponding to the key is considered to be 0, and then decremented by one;
  • If the value corresponding to the key is not an integer or its range exceeds a 64-bit signed integer, an error will be reported;
  • If DECR the execution is successful, the value minus one is returned, otherwise the corresponding error message is returned.

Usage example:

  1. DECRBY

DECRBYThe function of the command is to subtract a specified integer from the integer represented by the string corresponding to the key.

  • If the key does not exist, the value corresponding to the key is considered to be 0, and then subtracted by the specified number;
  • If the value corresponding to the key is not an integer or its range exceeds a 64-bit signed integer, an error will be reported;
  • If DECRBYthe execution is successful, the subtracted value is returned, otherwise the corresponding error message is returned;
  • If DECRBYthe specified number to be subtracted is a negative number, it means adding this number.

Usage example:

3. INCRBYFLOAT

INCRBYFLOATThe function of the command is to add the floating point number represented by the string corresponding to the key to the specified number.

grammar:

INCRBYFLOAT key increment 
  • If the key does not exist, it defaults to 0, and then the addition operation is performed;
  • If the string corresponding to key is not a number, an error will be reported
  • If the specified number is negative, it means to subtract this number;
  • If INCRBYFLOATthe execution is successful, the operation result is returned, otherwise an error message is returned;
  • Allows floating point numbers to be represented in scientific notation.

Usage example:

String operation related commands

1. APPEND

APPENDThe function of the command is to append the string after the string corresponding to the key.

grammar:

APPEND key value 
  • If the key does not exist, its effect is equivalent to the SET command;
  • If APPENDthe execution is successful, the length of the final string is returned.

2. STRANGE

GETRANGEThe function of the command is to intercept the substring in the string corresponding to the key.

grammar:

GETRANGE key start end
  • The intercepted content is determined by the specified offsets start and end, and the interval is closed left and right;
  • The specified offset can be a negative number. When it is specified as a negative number, it represents the penultimate character. For example, -1 represents the penultimate character;
  • Out-of-range offsets are adjusted to the correct value based on the length of the string.

Usage example:

3. SETRANGE

SETRANGEThe function of the command is to overwrite part of the string corresponding to the key starting from the specified position.

grammar:

SETRANGE key offset value 
  • The length of the replacement is the length of the replacement string. If the length of the original string is insufficient, all the following parts will be replaced;
  • If key does not exist and the specified replacement position is greater than 0, the previous position is replaced by hexadecimal 0;
  • If the replacement is successful, the length of the final string is returned.

4. STRLEN

STRLENThe function of the command is to obtain the length of the string corresponding to the key.

grammar:

STRLEN key
  • Its return value is the length of the string;
  • If the key does not exist, return 0;
  • If the type of value corresponding to key is not string, an error will be reported;
  • The length of the string is determined by the current encoding rules.

Usage example:

Summary of string related commands

The following is a summary of commands related to the string type in Redis, including commands, functions and time complexity:

Order effect time complexity
SET Set the value of the key to the specified string O(1)
GET Get the string value corresponding to the key O(1)
MSET Set multiple key-value pairs in batches O(N) (N is the number of key-value pairs)
MGET Get the values ​​of multiple keys in batches O(N) (N is the number of keys)
SETNX set value only if key does not exist O(1)
SEVEN Set the key value and expiration time (seconds) O(1)
PSETEX Set the value of the key and the expiration time (in milliseconds) O(1)
INCR Add one to the numeric value corresponding to the key O(1)
INCRBY Add the specified integer to the numeric value corresponding to the key O(1)
Dec Decrease the numeric value corresponding to the key by one O(1)
DECRBY Subtract the specified integer from the numeric value corresponding to the key O(1)
INCRBYFLOAT Add the floating-point value corresponding to the key to the specified floating-point number O(1)
APPEND Append a string after the string value corresponding to the key O(1)
AFFECTED Get the substring of the string corresponding to the key O(N) (N is the length of the substring)
SETRANGE Overwrite part of the content of the string corresponding to the key O(N) (N is the replacement string length)
STRLEN Get the length of the string corresponding to the key O(1)

2. The encoding method of string type

In Redis, string (string) type values ​​can be stored using a variety of different encoding methods. The specific encoding method is dynamically selected based on the content and size of the data to save memory and improve performance to the greatest extent. The following are common encoding methods for string types in Redis:

  1. RAW (Simple Dynamic String) : This is the most common way to encode strings. It is used to store shorter strings, up to the limit of the string encoding structure. This encoding does not compress the string, so it is efficient when storing smaller strings.

  2. INT (integer encoding) : When a string can be interpreted as an integer, Redis will encode it as an integer to save memory. Integer encoding is divided into the following sub-encoding methods:

    • int16_t: 16-bit integer encoding, storing integers within 16 bits.
    • int32_t: 32-bit integer encoding, storing integers within 32 bits.
    • int64_t: 64-bit integer encoding, storing integers within 64 bits.
  3. EMBSTR (nested string encoding) : used to store shorter strings, but unlike RAW, the EMBSTR encoding method also stores the string length in the encoding structure to save memory.

  4. RAW and EMBSTR share encoding : In some cases, Redis will use a special encoding method that can share the advantages of RAW and EMBSTR encoding methods. This means it can store both shorter strings and efficiently store larger strings.

  5. SDS (Simple Dynamic String) : SDS is a data structure used to represent strings that has a dynamic size and can be expanded without the need to reallocate memory. This encoding is used to store larger strings to save memory and improve performance.

It should be noted that Redis will dynamically select the appropriate encoding method based on the content and size of the string, so developers do not need to manually specify the encoding method. This dynamic encoding method enables Redis to make full use of memory under different circumstances and improve efficiency.

You can use Redis OBJECT ENCODINGcommands to see how a specific key is encoded, for example:

OBJECT ENCODING mykey

This will return mykeyhow the key is encoded.

For example:

3. Usage scenarios of string type

1. Cache

Due to its fast speed, Redis is often used for caching functions. A typical cache usage scenario is that Redis serves as the buffer layer, MySQL serves as the storage layer, and most of the requested
data is obtained from Redis. Since Redis has the characteristics of supporting high concurrency, caching can usually play a role in accelerating reading and writing and reducing back-end pressure.

Cache storage architecture consisting of Redis + MySQL:

The following simulates the access process of the business data in the above figure through pseudo code:

1) Assume that the business is to obtain user information based on the user's uid

UserInfo getUserInfo(long uid) {
    
    
	...
}

2) First obtain user information from Redis. We assume that user information is stored in the key corresponding to "user:info:"

// 根据 uid 得到 Redis 的键
String key = "user:info:" + uid;
// 尝试从 Redis 中获取对应的值
String value = Redis 执⾏命令:get key;
// 如果缓存命中(hit)
if (value != null) {
    
    
	// 假设用户信息按照 JSON 格式存储
	UserInfo userInfo = JSON 反序列化(value);
	return userInfo;
}

3) If the user information is not obtained from Redis or the cache misses (miss), the corresponding information is further obtained from MySQL, and then written to the cache and returned

// 如果缓存未命中(miss)
if (value == null) {
    
    
	// 从数据库中,根据 uid 获取⽤⼾信息
	UserInfo userInfo = MySQL 执⾏ SQL:select * from user_info where uid = <uid>
	// 如果表中没有 uid 对应的⽤⼾信息
	if (userInfo == null) {
    
    
		// 响应 404
		return null;
	}

	// 将用户信息序列化成 JSON 格式
	String value = JSON 序列化(userInfo);
	
	// 写⼊缓存,为了防⽌数据腐烂(rot),设置过期时间为 1 ⼩时(3600 秒)
	Redis 执⾏命令:set key value ex 3600

	// 返回用户信息
	return userInfo;
}

By adding the cache function, under ideal circumstances, each user information will only have one MySQL query per hour, which greatly improves the query efficiency and also reduces the number of MySQL accesses.

PS: Design principles and examples of Redis key names

  1. Business name prefix: Start the key name with the business name to isolate keys for different businesses or projects. This helps ensure that keys don't conflict between different applications or teams.
    Example:
    user_info:6379
    order_info:1234
  2. Object Name: Specify the object name in the key name to describe what is stored. This helps to have a clear understanding of the data type or business object that the key stores.
    Example:
    user_profile:6379
    product_catalog:5678
  3. Unique identifier: If desired, a unique identifier can be included in the key name to more specifically identify the stored data. This helps segment the data into different entities.
    Example:
    user:12345:profile
    product:7890:details
  4. Properties: If your data has multiple properties, you can include the property name in the key name to further refine the purpose of the key.
    Example:
    user:12345:profile:name
    product:7890:details:price
  5. Key abbreviation: If a key name becomes too long, you can use abbreviations to reduce the length of the key name, but make sure the abbreviation is clear and understandable within the team.
    Example:
    u:12345:pr:n (abbreviated version)

By using this key namespace convention, Redis keys can be made more organized and easier to maintain and manage. It can also help avoid key name conflicts, especially if multiple applications or teams use the same Redis instance. However, please note that key names that are too long may cause performance degradation, so you need to balance the readability and performance requirements of the key name.

2. Counter

The Counter function is one of the common and useful functions in Redis. It can be used to quickly record and query the count value of an object. This function is very useful in many applications, such as website visit counting, likes, comments, plays, etc.

For example, record the number of video plays:

pseudocode:

// 在 Redis 中统计某视频的播放次数
long incrVideoCounter(long vid) {
    
    
	key = "video:" + vid;
	long count = Redis 执⾏命令:incr key
	return counter;
}

However, there are many challenges and complexities when it comes to actually developing a mature, stable counting system. Here are some challenges and considerations that may need to be addressed:

  1. Anti-cheating : It is crucial to ensure that the counting system is not easily manipulated by malicious actors. Common anti-cheating measures include limiting the counting rate per user or IP address, using verification codes or tokens to verify user behavior, etc.
  2. Counting by different dimensions : Sometimes it is necessary to count according to different dimensions, such as by time, geographical location, user type, etc. To achieve this flexibility, an adaptable counting system architecture needs to be designed.
  3. Avoid single point problems : A single point of failure can lead to unavailability of the counting system. To ensure high availability, you can consider using Redis's master-slave replication or cluster mode, or using other distributed counting systems.
  4. Data persistence : Redis stores data in memory by default, but in order to persist data, you can periodically snapshot the data to disk or use persistence options such as AOF (Append-Only File).
  5. Performance Optimization : Processing large number of count requests can put a strain on performance. It is necessary to optimize the Redis configuration and consider using the cache layer, distributed counting system or load balancing strategy to cope with high load situations.
  6. Concurrency control : Concurrent operations may cause counting inconsistencies. To ensure atomicity of counting, you can use techniques such as Redis transactions or optimistic locking.
  7. Monitoring and logging : Establish a monitoring and logging system to track the performance and operation of the counting system in real time and detect potential problems.
  8. Capacity planning : Consider capacity planning for the counting system, including data storage needs, memory and hard drive space, etc. to support future growth.
  9. Data Cleaning : Periodically clean count data that is no longer needed to prevent data bloat and excessive memory usage.

In summary, developing a realistic counting system is a complex task that requires consideration of numerous factors. Choosing the right technology stack, designing a good architecture, implementing security and anti-cheat measures, ensuring high availability, and establishing a monitoring and maintenance strategy are all important steps in implementing a successful counting system. These challenges require careful planning and implementation to meet the needs of the specific project.

3. Shared session (Session)

In a distributed Web service, user's session information is usually stored on respective servers, including the user's login status and other session-related data. However, due to the need for load balancing, user requests will be distributed to different servers, and session data on different servers are not shared.

This leads to a problem: if the user's requests are balanced to different servers, the user may find themselves needing to log in again when refreshing the page or sending the next request. This experience is unacceptable to the user .

For example, the Session decentralized storage shown in the figure below:

In order to solve this problem, Redis can be used to centrally manage the user's Session information. In this mode, as long as Redis is highly available and scalable, no matter which web server the user is balanced to, Session information can be queried and updated centrally from Redis.

4. Mobile phone verification code

In order to enhance the security of user login, many applications will take the following steps:

  • Each time a user attempts to log in, the user is asked to enter their mobile phone number and a second verification is performed by sending a verification code to their mobile phone. This verification code requires the user to enter it again to ensure that the login request comes from the user himself.
  • In addition, in order to prevent abuse of the SMS interface and improve security, the frequency of users obtaining verification codes per minute is usually limited. For example, the same mobile phone number can only obtain verification codes up to 5 times in one minute.

This process can effectively reduce the risk of malicious logins and spam verification codes, while ensuring user account security.

SMS verification code:

This function can use the following pseudo code to illustrate the basic implementation idea:

String 发送验证码(phoneNumber) {
    
    
    key = "shortMsg:limit:" + phoneNumber;
    // 设置过期时间为 1 分钟(60 秒)
    // 使用 NX,只在不存在 key 时才能设置成功
    bool r = Redis 执行命令:set key 1 ex 60 nx
    if (r == false) {
    
    
        // 说明之前设置过该手机号的验证码了
        long c = Redis 执行命令:incr key
        if (c > 5) {
    
    
            // 说明超过了一分钟 5 次的限制了
            // 限制发送
            return null;
        }
    }
    // 说明要么之前没有设置过手机号的验证码;要么次数没有超过 5 次
    String validationCode = 生成随机的 6 位数的验证码();
    validationKey = "validation:" + phoneNumber;
    // 验证码 5 分钟(300 秒)内有效
    Redis 执行命令:set validationKey validationCode ex 300;
    // 返回验证码,随后通过手机短信发送给用户
    return validationCode;
}

// 验证用户输入的验证码是否正确
bool 验证验证码(phoneNumber, validationCode) {
    
    
    validationKey = "validation:" + phoneNumber;
    String value = Redis 执行命令:get validationKey;
    if (value == null) {
    
    
        // 说明没有这个手机号的验证码记录,验证失败
        return false;
    }
    if (value == validationCode) {
    
    
        return true;
    } else {
    
    
        return false;
    }
}

The above introduces the application of the string data type using Redis in scenarios such as caching, counting, session management, and mobile phone verification codes. However, the applicable scenarios of Redis's string type are far more than these. Developers can give full play to their creativity and imagination and apply it to various business scenarios based on the characteristics of the string type and the commands provided.

Guess you like

Origin blog.csdn.net/qq_61635026/article/details/132744418