분산 세션이 일관성이 없으면 어떻게 해야 하나요? 다음 기사에서는 Redis의 분산 세션 불일치에 대한 솔루션을 소개하겠습니다. 도움이 되길 바랍니다.
1. 세션의 역할은 무엇인가요?
Session은 클라이언트와 서버 사이의 통신 세션 추적 기술로, 서버와 클라이언트는 전체 통신의 기본 세션 정보를 유지합니다. [관련 권장 사항: Redis 비디오 튜토리얼]
클라이언트가 처음으로 서버에 액세스하면 서버는 sessionId로 응답하고 이를 로컬 쿠키에 저장합니다. 이후 방문에서는 sessionId가 쿠키에 저장됩니다. sessionId는 서버에 접속하기 위해 요청 헤더에 넣어집니다.
이 sessionId를 통해 해당 데이터를 찾을 수 없으면 서버는 새로운 sessionId를 생성하고 클라이언트에 응답합니다.
2. 분산 세션의 문제점은 무엇입니까?
단일 서버 웹 애플리케이션에서는 세션 정보만 서버에 저장하면 됩니다. 이는 지난 몇 년 동안 우리가 접한 가장 일반적인 방법입니다.
그러나 분산 시스템의 인기로 인해 최근 몇 년 동안 단일 시스템은 더 이상 증가하는 요구를 충족할 수 없습니다. 수백만 명의 사용자 수요가 증가함에 따라 많은 회사에서 클러스터 배포 서버를 사용하고 있습니다
고동시성 요청이 서버에 도착하면 서버에 분산됩니다. 동일한 사용자의 여러 요청이 클러스터의 다른 서버로 분산되면 세션 데이터를 가져오지 못하므로 세션 공유에 문제가 발생할 수 있습니다.
3. 서비스 클러스터링은 일반적으로 어떻게 이루어지나요?
4. nginx 로드 밸런싱과 리본 로드 밸런싱의 차이점
5. 세션 일관성 솔루션
1. 세션 복제(동기화)
아이디어: 여러 서버가 세션을 서로 동기화하여 각 서버에 모든 세션이 포함됩니다. 세션
장점: 서버에서 지원되는 기능, 애플리케이션에서 코드를 수정할 필요가 없습니다
단점:
2. 클라이언트 저장 방법
아이디어: 서버는 모든 사용자 세션을 저장하며, 메모리 사용량이 크기 때문에 세션이 브라우저 쿠키에 저장 가능, 각 끝은 한 명의 사용자 데이터만 저장하면 됩니다
장점: 서버는 저장할 필요가 없습니다
단점:
아이디어: 고가용성을 보장하기 위해 서버에 여러 개의 중복 서버가 있습니다. 역방향 프록시 계층이 동일한 사용자의 요청이 포함되도록 뭔가를 할 수 있습니까? 섬기는 사람? 옵션 1: 4계층 프록시 해시
옵션 2: 7계층 에이전트 해시
역방향 프록시는 http 프로토콜의 특정 비즈니스 속성을 사용하여 sid, city_id, user_id 등과 같은 해싱을 수행합니다. 이는 동일한 브라우저 사용자의 요청이 동일한 서버에 있는지 확인하기 위해 해시 전략을 보다 유연하게 구현할 수 있습니다
장점:
단점:
세션에는 일반적으로 유효 기간이 있으며, 이 두 가지 단점은 부분 세션 실패와 동일하다고 간주할 수 있습니다. 일반적으로 큰 문제는 아닙니다.
4계층 해싱 또는 7계층 해싱과 관련하여 저는 개인적으로 전자를 권장합니다. 전문 소프트웨어가 전문적인 작업을 수행하도록 하고 역방향 프록시는 전달을 담당합니다. 꼭 필요한 경우가 아니면 애플리케이션 계층 비즈니스 속성을 도입하지 마세요. , 때로는 컴퓨터실의 다중 활동이 비즈니스 속성에 따라 다른 컴퓨터실의 서버로 라우팅되어야 하는 경우도 있습니다.
4. 백엔드 통합 중앙 집중식 스토리지
장점:
단점: 네트워크 호출이 추가되고, 애플리케이션 코드를 수정해야 함
DB의 경우 스토리지나 캐시 중 개인적으로 후자를 권장합니다. 세션 읽기 빈도가 매우 높을 것이며 데이터베이스 압력도 상대적으로 높을 것입니다. 세션 고가용성이 필요한 경우 캐시를 고가용성으로 만들 수 있지만 대부분의 경우 세션이 손실될 수 있으므로 일반적으로 고가용성을 고려할 필요가 없습니다.
요약
세션 일관성을 보장하기 위한 일반적인 아키텍처 설계 방법:
6. 사례 사례: SpringSession+redis는 분산 세션 불일치 문제를 해결합니다.
1단계: SpringSession과 redis의 종속성 패키지 추가
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.4.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
2단계: 구성 파일
# 为某个包目录下 设置日志 logging.level.com.ljw=debug # 设置session的存储方式,采用redis存储 spring.session.store-type=redis # session有效时长为10分钟 server.servlet.session.timeout=PT10M ## Redis 配置 ## Redis数据库索引(默认为0) spring.redis.database=0 ## Redis服务器地址 spring.redis.host=127.0.0.1 ## Redis服务器连接端口 spring.redis.port=6379 ## Redis服务器连接密码(默认为空) spring.redis.password=
3단계: 인터셉터 구성
@Configuration public class SessionConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SecurityInterceptor()) //排除拦截的2个路径 .excludePathPatterns("/user/login") .excludePathPatterns("/user/logout") //拦截所有URL路径 .addPathPatterns("/**"); } }
@Configuration public class SecurityInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { HttpSession session = request.getSession(); //验证当前session是否存在,存在返回true true代表能正常处理业务逻辑 if (session.getAttribute(session.getId()) != null){ log.info("session拦截器,session={},验证通过",session.getId()); return true; } //session不存在,返回false,并提示请重新登录。 response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.getWriter().write("请登录!!!!!"); log.info("session拦截器,session={},验证失败",session.getId()); return false; } }
4단계: 컨트롤러
@RestController @RequestMapping(value = "/user") public class UserController { Map<String, User> userMap = new HashMap<>(); public UserController() { //初始化2个用户,用于模拟登录 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) { //模拟数据库的查找 User user = this.userMap.get(username); if (user != null) { if (!password.equals(user.getPassword())) { return "用户名或密码错误!!!"; } else { session.setAttribute(session.getId(), user); log.info("登录成功{}",user); } } else { return "用户名或密码错误!!!"; } return "登录成功!!!"; } /** * 通过用户名查找用户 */ @GetMapping(value = "/find/{username}") public User find(@PathVariable String username) { User user=this.userMap.get(username); log.info("通过用户名={},查找出用户{}",username,user); return user; } /** *拿当前用户的session */ @GetMapping(value = "/session") public String session(HttpSession session) { log.info("当前用户的session={}",session.getId()); return session.getId(); } /** * 退出登录 */ @GetMapping(value = "/logout") public String logout(HttpSession session) { log.info("退出登录session={}",session.getId()); session.removeAttribute(session.getId()); return "成功退出!!"; } }
5단계: 엔터티 클래스
@Data public 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; } }
6단계: 액세스 테스트
로그 먼저 :http://127.0.0.1:8080/user/login?username=user1&password=user1
다시 쿼리http://127.0.0.1:8080/user/find/user1
7 분석 SpringSession의 redis 원리
1단계: SpringSession의 redis 데이터 구조 분석
127.0.0.1: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"
공통점: 세 개의 키는 모두 spring:session:으로 시작하는데, 이는 SpringSession의 redis 데이터를 나타냅니다. .
쿼리 유형
127.0.0.1:6379> type spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b hash
127.0.0.1:6379> 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\x02\x00\x00xp\x00\x00\x01|\xc5\xdb\xecu" // sesson的属性,存储了user对象 3) "sessionAttr:d3434f61-4d0a-4687-9070-610bd7790f3b" 4) "\xac\xed\x00\x05sr\x00\x1ecom.ljw.redis.controller.User\x16\"_m\x1b\xa0W\x7f\x02\x00\x03I\x00\x02idL\x00\bpasswordt\x00\x12Ljava/lang/String;L\x00\busernameq\x00~\x00\x01xp\x00\x00\x00\x01t\x00\x05user1q\x00~\x00\x03" //最后的访问时间 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\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01|\xc5\xe1\xc7\xed" //失效时间 100分钟 7) "maxInactiveInterval" 8) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x17p"
2단계: SpringSession의 redis 만료 전략 분석
만료된 데이터의 경우 일반적으로 세 가지 삭제 전략이 있습니다.
예약 삭제, 즉 만료 시간을 설정하는 동안 만료 시간이 되면 즉시 키를 삭제하는 타이머를 생성합니다.
지연 삭제, 즉 키에 액세스할 때 키가 만료되었는지 확인하고, 만료되면 삭제하고, 그렇지 않으면 키 값을 반환합니다.
定期删除,即每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
redis删除过期数据采用的是懒性删除+定期删除组合策略,也就是数据过期了并不会及时被删除。
但由于redis是单线程,并且redis对删除过期的key优先级很低;如果有大量的过期key,就会出现key已经过期但是未删除。
为了实现 session 过期的及时性,spring session 采用了定时删除+惰性删除的策略。
定时删除
127.0.0.1:6379> type spring:session:expirations:1635413520000 set 127.0.0.1:6379> smembers spring:session:expirations:1635413520000 1) "\xac\xed\x00\x05t\x00,expires: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"
惰性删除
127.0.0.1:6379> type spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b string 127.0.0.1:6379> get spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b "" 127.0.0.1:6379> ttl spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b (integer) 3143 127.0.0.1:6379>
2) "spring:session:sessions:expires:d3434f61-4d0a-4687-9070-610bd7790f3b" 3) "spring:session:expirations:1635413520000" 6) "spring:session:sessions:d3434f61-4d0a-4687-9070-610bd7790f3b"
更多编程相关知识,请访问:编程视频!!
위 내용은 Redis에서 분산 세션 불일치에 대해 수행할 작업의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!