Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the inconsistency of distributed session in redis

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly explains "how to solve the distributed session inconsistency in redis". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to solve the distributed session inconsistency in redis".

Distributed session inconsistency solution

What is the function of Session?

Session is the communication session tracking technology between the client and the server. The server and the client keep the basic information of the whole communication session. [related recommendation: Redis video tutorial]

When the client accesses the server for the first time, the server responds to a sessionId and stores it in the local cookie, and later access puts the sessionId in the cookie into the request header to access the server

If the corresponding data is not found through this sessionId, the server creates a new sessionId and responds to the client.

What's wrong with distributed Session?

In single-server web applications, session information only needs to be stored in the server, which is the most common way we have come into contact with in the past few years.

However, in recent years, with the popularity of distributed systems, a single system can no longer meet the growing needs of millions of users, and cluster deployment servers have been used in many companies.

When the request with high concurrency reaches the server, it is distributed to a server in the cluster by load balancing, which may cause multiple requests from the same user to be distributed to different servers in the cluster, and the session data will not be available, so the sharing of session becomes a problem.

Third, how is the service cluster generally done?

SpringBoot project, then just change the lower port number to start a few, and then use nginx unified as a reverse proxy.

SpringCloud micro-service project, so at this time, you can use ribbon local load balancing.

4. The difference between nginx load balancing and ribbon load balancing.

Nginx load balancer is a server-side load balancer, which accesses an address uniformly and decides which server to access according to the load balancing algorithm.

Ribbon load balancer, which is a local load balancer (client load balancer), caches and records all client addresses that provide services, and implements load balancing according to the local algorithm.

5. Session consistency solution

1. Session replication (synchronization)

Idea: multiple servers synchronize session with each other, so that each server contains all the session

Advantages: functions supported by the server, the application does not need to modify the code

Disadvantages:

The synchronization of session requires data transmission, which accounts for the bandwidth of the private network and sometimes delays.

All servers contain all session data. The amount of data is limited by memory and cannot be scaled horizontally.

two。 Client storage method

Idea: the server stores the session of all users, which takes up a large amount of memory. The session can be stored in the browser cookie, and each side only needs to store one user's data.

Advantages: the server does not need storage

Disadvantages:

Every http request carries session, which accounts for the public network bandwidth.

Data is stored on the end and transmitted on the network, so there are security risks such as leakage, tampering, theft and so on.

The size of data stored in session and the number of domain names cookie are limited.

Note: although this scheme is not commonly used, it is indeed a way of thinking.

3. Reverse proxy hash consistency

Idea: the server has multiple redundancy in order to ensure high availability, can the reverse proxy layer do something to ensure that the request of the same user falls on the same server?

Solution 1: four-tier agent hash

The reverse proxy layer uses the user's ip to do hash to ensure that the request for the same ip falls on the same server.

Solution 2: seven-tier agent hash

Reverse proxy uses some business attributes of http protocol to do hash, such as sid,city_id,user_id, which can implement hash policy more flexibly to ensure that the request of the same browser user falls on the same server.

Advantages:

You only need to change the nginx configuration, not the application code.

Load balancing. As long as the hash attribute is uniform, the load of multiple servers is balanced.

Can support server-side horizontal scaling (session synchronization is not good, limited by memory)

Disadvantages:

If the server restarts, part of the session will be lost, resulting in business impact, such as some users logging back in.

If the server expands horizontally and the session is redistributed after rehash, some users will not be routed to the correct session

Session generally has a validity period, and two of all deficiencies can be considered as equivalent to partial session invalidation, which is generally not a big problem.

For layer-4 hash or layer-7 hash, I recommend the former: let professional software do professional things, and reverse proxy is responsible for forwarding, and try not to introduce application layer business attributes unless you have to do so (for example, sometimes multiple servers in multiple data centers need to be routed to servers in different data centers according to business attributes).

The difference between layer 4 and layer 7 load balancing

4. Back-end unified centralized storage

Advantages:

There are no security risks.

It can be expanded horizontally, and the database / cache can be split horizontally.

No session will be lost when the server is restarted or expanded.

Deficiency: an additional network call has been added and the application code needs to be modified

For db storage or cache, the latter is recommended: the frequency of session reading will be very high, and the pressure on the database will be high. If there is a need for high availability of session, cache can be highly available, but in most cases session can be lost, and there is generally no need to consider high availability.

Summary

Common approaches to architecture design to ensure session consistency:

Session synchronization method: multiple servers synchronize data with each other

Client-side storage method A user stores only his own data

Reverse proxy hash consistency both layer 4 hash and layer 7 hash can be done to ensure that a user's request falls on a server.

The server of the backend unified storage is restarted and expanded, and the session will not be lost (backend cache unified storage is recommended)

6. Case study: SpringSession+redis solves the problem of distributed session inconsistency

Step 1: add dependent packages for SpringSession and redis

Org.springframework.boot spring-boot-starter-redis 1.4.7.RELEASE org.springframework.session spring-session-data-redis

Step 2: profile

# set log logging.level.com.ljw=debug# under a package directory and set the storage mode of session Use redis to store spring.session.store-type=redis# session valid duration for 10-minute server.servlet.session.timeout=PT10M## Redis configuration # # Redis database index (default is 0) spring.redis.database=0## Redis server address spring.redis.host=127.0.0.1## Redis server connection port spring.redis.port=6379## Redis server connection password (default is empty) spring.redis.password=

Step 3: configure the interceptor

@ Configurationpublic class SessionConfig implements WebMvcConfigurer {@ Override public void addInterceptors (InterceptorRegistry registry) {registry.addInterceptor (new SecurityInterceptor ()) / exclude intercepted 2 paths. IntercepdePathPatterns ("/ user/login") .recipdePathPatterns ("/ user/logout") / / intercept all URL paths .addPathPatterns ("/ *") @ Configurationpublic class SecurityInterceptor implements HandlerInterceptor {@ Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {HttpSession session = request.getSession () / / verify whether the current session exists. If true true is returned, the business logic if can be processed normally (session.getAttribute (session.getId ())! = null) {log.info ("session interceptor, session= {}, verification passed", session.getId ()); return true;} / / session does not exist, return false, and prompt to log in again. Response.setCharacterEncoding ("UTF-8"); response.setContentType ("application/json; charset=utf-8"); response.getWriter () .write ("Please login!") ; log.info ("session interceptor, session= {}, validation failed", session.getId ()); return false;}}

HandlerInterceptor

PreHandle: called before the business processor processes the request. Preprocessing, which can be processed by coding, security control, permission verification and so on.

PostHandle: executed after the business processor processes the request execution and before the view is generated. Post-processing (Service was called and ModelAndView was returned, but the page was not rendered), and there was a chance to modify ModelAndView

AfterCompletion: called after the DispatcherServlet has fully processed the request, which can be used to clean up resources, etc. Return processing (the page has been rendered)

Step 4: controller

@ RestController@RequestMapping (value = "/ user") public class UserController {Map userMap = new HashMap (); public UserController () {/ / initialize 2 users to simulate login to User u1=new User (1, "user1", "user1"); userMap.put ("user1", U1); User u2=new User (2, "user2", "user2"); userMap.put ("user2", U2) } @ GetMapping (value = "/ login") public String login (String username, String password, HttpSession session) {/ / Lookup of the simulation database User user = this.userMap.get (username); if (user! = null) {if (! password.equals (user.getPassword () {return "wrong username or password!!" ;} else {session.setAttribute (session.getId (), user); log.info ("login succeeded {}", user);}} else {return "wrong username or password!!" ;} return "login succeeded!!" ;} / * find user by user name * / @ GetMapping (value = "/ find/ {username}") public User find (@ PathVariable String username) {User user=this.userMap.get (username); log.info ("find user {} by user name = {}", username,user); return user } / * take the current user's session * / @ GetMapping (value = "/ session") public String session (HttpSession session) {log.info ("current user's session= {}", session.getId ()); return session.getId () } / * exit login * / @ GetMapping (value = "/ logout") public String logout (HttpSession session) {log.info ("exit login session= {}", session.getId ()); session.removeAttribute (session.getId ()); return "exit successfully!!" ;}}

Step 5: entity class

@ Datapublic class User implements Serializable {private int id; private String username; private String password; public User (int id, String username, String password) {this.id = id; this.username = username; this.password = password;}}

Step 6: access the test

Log in first: http://127.0.0.1:8080/user/login?username=user1&password=user1

Query http://127.0.0.1:8080/user/find/user1 again.

7. Analyze the redis principle of SpringSession.

Step 1: analyze the redis data structure of SpringSession

127.0.1 41e5-b9ab-a77649a7bb6a 6379 > keys * 1) "spring:session:sessions:9889ccfd-f4c9-41e5-b9ab-a77649a7bb6a" 2) "spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b" 3) "spring:session:expirations:1635413520000" 4) "spring:session:sessions:expires:9889ccfd-f4c9-41e5-b9ab-a77649a7bb6a" 5) "spring:session:expirations:1635412980000" 6) "spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b"

What they have in common: all three key start with spring:session: and represent the redis data of SpringSession.

Query type

127.0.1 610bd7790f3bhash127.0.0.1:6379 6379 > type spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3bhash127.0.0.1:6379 > creation time of hgetall spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b// session 1) "creationTime" 2) "xac\ xed\ X00\ x05sr\ X00\ x0ejava.lang.Long \ x8b\ xe4\ x90\ xcc\ x8f#\ xdf\ X02\ x00\ x01J\ X00\ x05valuexr\ X00\ x10java.lang.Number\ x86\ xac\ x95\ x1d\ x0b\ x94\ xe0\ x8b\ X00\ x00xp\ X00\ X01 |\ xc5\ xdb\ xecu "/ sesson attributes Stored user object 3) "sessionAttr:d3434f61-4d0a-4687-9070-610bd7790f3b" 4) "\ xac\ xed\ X00\ x05sr\ X00\ x1ecom.ljw.redis.controller.User\ x16\" _ m\ X1b\ xa0W\ X7f\ X02\ x03I\ X00\ x02idL\ X00\ bpasswordt\ X00\ x12Ljava/lang/String L\ X00\ busernameq\ X00~\ X00\ x01xp\ X00\ X00\ x01t\ x00\ x05user1q\ x00~\ x00\ x03 "/ Last access time 5)" lastAccessedTime "6)"\ xac\ xed\ X00\ x05sr\ X00\ x0ejava.lang.Long \ x8b\ xe4\ x90\ xcc\ x8f#\ xdf\ X02\ x00\ x01J\ X00\ x05valuexr\ X00\ x10java.lang.Number\ x86\ xac\ x95\ x1d\ x94\ xe0\ x8b\ x02\ x00xp\ X00\ X00 |\ xc5\ xe1\ xc7\ xed "/ / expiration time 100 minutes 7)" maxInactiveInterval "8)" xac\ xed\ X00\ x05sr\ X00\ x11java.lang.Integer\ X12\ xe2\ xa0\ xa4\ xf7\ x878\ x02\ X00\ x01I\ x00\ x05valuexr\ X00\ x10java.lang.Number\ x86\ xac\ x95\ x1d\ x0b\ x94\ xe0\ x8b\ x02\ x00\ x00xp\ X00\ x00\ x17p "

Step 2: analyze SpringSession's redis expiration policy

There are generally three deletion strategies for out-of-date data:

Timing deletion, that is, while setting the expiration time of the key, create a timer, when the expiration time of the key comes, delete immediately.

Lazy deletion, that is, when the key is accessed, it is determined whether the key has expired, and if it expires, it is deleted, otherwise the key value is returned.

Delete periodically, that is, at regular intervals, the program checks the database and deletes the expired keys. It is up to the algorithm to decide how many expired keys to delete and how many databases to check.

Redis uses a combination of lazy deletion and periodic deletion to delete expired data, that is, data will not be deleted in time when it expires.

However, because redis is single-threaded, and redis has a low priority for deleting expired key, if there are a large number of expired key, there will be key that has expired but has not been deleted.

In order to achieve the timeliness of session expiration, spring session adopts the strategy of regular deletion + lazy deletion.

Scheduled deletion

127.0.0.1 xed 6379 > type spring:session:expirations:1635413520000set127.0.0.1:6379 > smembers spring:session:expirations:16354135200001) "\ xac\ 4d0a-4687\ x00\ x05t\ x00" reslance d3434f61-4d0a-4687-9070-610bd7790f3b "2)" spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b "3)" spring:session:expirations:1635413520000 "6)" spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b

1635412980000 is a timestamp, equal to 2021-10-28 17:23:00, that is, it should expire at this time

Springsession scheduled (1 minute) polling, delete spring:session:expirations: [?] Expired member elements of, for example: spring:session:expirations:1635413520000

Springsesion regularly detects the value of the timeout key, and deletes the seesion according to the value, such as key:spring:session:expirations:1635413520000. The value is (sessionId): d3434f61-4d0a-4687-9070-610bd7790f3b seesion.

Lazy deletion

127.0.0.1 type spring:session:sessions:expires:d3434f61 6379 > get spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3bstring127.0.0.1:6379 > get spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b "" 127.0.0.1 get spring:session:sessions:expires:d3434f61 6379 > ttl spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b (integer) 3143127.0.0.1 get spring:session:sessions:expires:d3434f61 6379 >

When visiting spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b, determine whether the key expires, delete it if it expires, otherwise return an improved value.

For example, when accessing spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b, determine whether the ttl expires, and delete it when it expires.

2) "spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b" 3) "spring:session:expirations:1635413520000" 6) "spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b" thank you for reading. The above is the content of "how to solve distributed session inconsistency in redis". After the study of this article, I believe you have a deeper understanding of how to solve the problem of distributed session inconsistency in redis. The specific use situation still needs to be verified by practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report