SpringBoot 는 Redis 의 zset 를 사용 하여 온라인 사용자 정 보 를 통계 합 니 다.

7430 단어 SpringBootRediszset
온라인 사용자 의 수 를 통계 하 는 것 은 응용 에서 흔히 볼 수 있 는 수요 이다.사용자 가 온라인,오프라인 상태 라 는 정확 한 통계 가 필요 하 다 면 클 라 이언 트 와 서버 만 TCP 긴 연결 을 유지 함으로써 이 루어 질 것 이 라 고 생각 합 니 다.응용 자체 가 IM 응용 이 아니라면 이런 방식 은 원가 가 매우 높다.
현재 의 응용 프로그램 은 모두 심장 박동 패 키 지 를 사용 하여 사용자 가 온라인 인지 아 닌 지 를 표시 하 는 경향 이 있다.사용자 가 로그 인 한 후 일정 시간 마다 서버 에 메 시 지 를 보 내 현재 사용자 가 온라인 임 을 표시 합 니 다.서버 는 클 라 이언 트 의 심장 박동 메 시 지 를 5 분 안에 받 아 온라인 사용자 로 볼 수 있 는 시간 차 를 정의 할 수 있 습 니 다.
온라인 사용자 통계 의 실현
데이터베이스 기반 구현
가장 쉬 운 방법 은 사용자 표 에 마지막 심장 박동 가방 을 추가 하 는 날짜 시간 필드 lastactive。서버 가 심장 박동 을 받 은 후,매번 이 필드 를 현재 의 최신 시간 으로 업데이트 합 니 다.
최근 5 분 동안 활성 화 된 사용자 수 를 조회 하려 면 SQL 한 마디 로 간단하게 완성 할 수 있다.

SELECT COUNT(1) AS `online_user_count` FROM `user` WHERE `last_active` BETWEEN  '2020-12-22 13:00:00' AND '020-12-22 13:05:00';
단점 도 분명 하 다.검색 효율 을 높이 기 위해 lastactive 필드 에 색인 을 추가 합 니 다.심장 박동 의 업데이트 로 인해 색인 트 리 를 자주 유지 하고 효율 이 매우 낮 습 니 다.
Redis 기반 실현
이것 은 비교적 이상 적 인 실현 방식 이다.Redis 는 메모 리 를 바탕 으로 읽 기와 쓰 기 를 하 는데 관계 형 데이터베이스 보다 성능 이 훨씬 좋 고 Zset 가 제공 하 는 온라인 사용자 의 통계 서 비 스 를 편리 하 게 구축 할 수 있다.
Redis 의 Zset
여 기 는 redis 와 관련 된 것 이 많 지 않 습 니 다.아래 zset 를 간단하게 설명 하 겠 습 니 다.그것 은 질서 있 는 set 집합 으로 집합 중의 모든 요 소 는 2 개의 물건 으로 구성 된다.
4.567917.member 가 집합 인 이상 집합 중의 요소 이 고 중복 할 수 없다.
  • score  질서 가 있 는 이상 정렬 에 사용 되 는 가중치 필드 입 니 다.
  • Zset 부분 조작
    요소 추가
    
    ZADD key score member [score member ...]
    집합 에 하나 이상 의 요 소 를 한꺼번에 추가 합 니 다.member 가 존재 하면 현재 score 를 사용 하여 덮어 씁 니 다.
    모든 원소 의 수량 을 통계 하 다
    
    ZCARD key
    score 값 이 min 과 max 사이 의 요소 수량 을 통계 합 니 다.
    
    ZCOUNT key min max
    score 값 이 min 과 max 사이 에 있 는 요 소 를 삭제 합 니 다.
    
    ZREMRANGEBYSCORE key min max
    하나의 예시
    내 마음속 프로 그래 밍 언어의 평 점 순 위 를 zset 로 저장 하려 고 합 니 다.이 키 는 lang 이 라 고 합 니 다.
    정 보 를 추가 하고 새로 추 가 된 요소 개 수 를 되 돌려 줍 니 다.
    
    > zadd lang 999 php 10 java 9 go 8 python 7 javascript
    "5"
    추 가 된 수량 보기
    
    > zcard lang
    "5"
    평 점 8-10 사이 의 요소 개 수 를 보면 3 개가 있 습 니 다.
    
    > zcount lang 8 10
    "3"
    평 점 이 8-1000 인 요 소 를 삭제 하고 삭 제 된 개 수 를 되 돌려 줍 니 다.
    
    > ZREMRANGEBYSCORE lang 8 1000
    "4"
    온라인 사용자 서비스의 실현
    zset 를 알 게 되면 온라인 사용자 의 통계 서 비 스 를 실현 할 수 있 습 니 다.
    사고의 방향 을 실현 하 다.
    클 라 이언 트 는 5 분 마다 서버 에 심장 박동 을 보 냅 니 다.서버 는 세 션 에 따라 사용자 의 ID 를 가 져 옵 니 다.zset 의 member 입 니 다.
    zset 에 저장 하면 score 는 현재 심장 박동 을 받 은 시간 스탬프 입 니 다.같은 사용자 가 두 번 째 로 심장 박동 을 보 낼 때 해당 하 는 score 값 을 업데이트 합 니 다.업데이트 가 메모리 에 있 기 때문에 이 속 도 는 상당히 빠 릅 니 다.
    
    zadd users 1608616915109 10000
    온라인 사용자 의 수 를 집계 해 야 한다.본질 적 으로 통계 해 야 한다.최근 5 분 동안 심장 박동 을 보 내 는 사용자 가 있 으 며,zcount 를 통 해 쉽게 집계 할 수 있다.프로그램 을 통 해 현재 시간 스탬프 를 가 져 옵 니 다.max Score 로 시간 스탬프 를 5 분 빼 면 minScore 로 합 니 다.
    
    zcount users 1608616615109 1608616915109 
    일부 사용자 들 은 오랫동안 로그 인 을 하지 않 았 을 수도 있 기 때문에 ZREMRANGEBYSCORE 를 통 해 청 소 를 할 수 있 습 니 다.프로그램 을 통 해 현재 시간 스탬프 를 가 져 옵 니 다.5 분 을 뺀 후 maxScore 로 0 을 사용 합 니 다.minScore 로 서 5 분 이 넘 도록 심장 박동 패 키 지 를 보 내지 않 은 모든 사용 자 를 청소 하 는 것 을 의미 합 니 다.
    
    ZREMRANGEBYSCORE users 0 1608616615109 
    구현 코드
    
    import java.time.Duration;
    import java.time.Instant;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    
    import javax.annotation.Resource;
    
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    
    /**
     * 
     * 
     *       
     * 
     * @author Administrator
     *
     */
    @Component
    public class OnlineUserStatsService {
        
        private static final String ONLINE_USERS = "onlie_users";
    
        @Resource
        private StringRedisTemplate stringRedisTemplate;
    
        /**
         *         
         * @param userId
         * @return 
         */
        public Boolean online(Integer userId) {
            return this.stringRedisTemplate.opsForZSet().add(ONLINE_USERS, userId.toString(), Instant.now().toEpochMilli());
        }
        
        /**
         *        ,       
         * @param duration
         * @return
         */
        public Long count(Duration duration) {
            LocalDateTime now = LocalDateTime.now();
            return this.stringRedisTemplate.opsForZSet().count(ONLINE_USERS, 
                                        now.minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), 
                                        now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        }
        
        /**
         *             ,    
         * @return
         */
        public Long count() {
            return this.stringRedisTemplate.opsForZSet().zCard(ONLINE_USERS);
        }
        
        /**
         *                 
         * @param duration
         * @return
         */
        public Long clear(Duration duration) {
            return this.stringRedisTemplate.opsForZSet().removeRangeByScore(ONLINE_USERS, 0, 
                    LocalDateTime.now().minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        }
    }
    사용 예시
    
    @Resource
    private OnlineUserStatsService onlineUserStatsService;
    
    @Test
    public void test() {
        
        // ID 1         
        boolean result = this.onlineUserStatsService.online(1);
        System.out.println("online=" + result);
        
        //   5   ,           ,          
        Long count = this.onlineUserStatsService.count(Duration.ofMinutes(5));
        System.out.println("oneline count=" + count);
        
        //                
        count = this.onlineUserStatsService.count();
        System.out.println("all count=" + count);
        
        //     1            
        Long clear = this.onlineUserStatsService.clear(Duration.ofDays(1));
        System.out.println("clear=" + clear);
    }
    메모리 소모 분석
    예산 레 디 스 메모리 소모
    저 는 Redis 의 메모리 배분 에 익숙 하지 않 습 니 다.제 생각 대로 데 이 터 를 작 성 했 을 뿐 입 니 다.그래서 제 가 여기 서 이해 하 는 것 은 잘못된 것 일 수도 있 습 니 다.하지만 증명 에 지장 이 없 을 것 같 습 니 다.-이런 장면 에서 Zset 를 사용 하면 메모리 소모 가 매우 적다 는 사실.
    구상 onlieusers 는 1 억 명의 사용자 의 상태 정 보 를 저장 해 야 합 니 다.각 요소 score 와 member 는 10 개의 바이트 로 저장 해 야 합 니 다.그러면 모두 20G 메모리 가 필요 합 니 다.20G 의 메모 리 는 현재 서버 로 서 는 큰 문제 가 아니다.

    마지막.
  • 심장 박동 프로 토 콜 은 반드시 HTTP 가 필요 하지 않 습 니 다.클 라 이언 트 가 지원 하면 UDP 가 적합 하고 시스템 비용 을 절약 할 수 있 습 니 다
  • zset 의 key 는 굳이 String 을 사용 하지 않 아 도 됩 니 다.직렬 화 방식 을 수정 하여 고정된 바이트 형식 으로 사용자 ID 를 저장 할 수 있 습 니 다.사용자 ID 가 너무 클 때 저장 공간 을 절약 할 수 있 습 니 다
  • 
    String userId = "10010";
    System.out.println(userId.getBytes().length); //          =>   5   
    
    byte[] bin = ByteBuffer.allocate(4).putInt(Integer.valueOf(userId)).array();
    System.out.println(bin.length);                    //            =>   4   
    
    System.out.println(ByteBuffer.wrap(bin).getInt());    //      ID => 10010
    이상 은 SpringBoot 가 Redis 의 zset 를 사용 하여 온라인 사용자 정 보 를 통계 하 는 상세 한 내용 입 니 다.SpringBoot 가 온라인 사용자 정 보 를 통계 하 는 데 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 시기 바 랍 니 다!

    좋은 웹페이지 즐겨찾기