지정된 시간(이후)에 작업 수행

일반적인 방법은 다음과 같습니다.

  • 예약 된 일들

  • 로켓MQ 지연 대기열

  • Rabbitmq 데드 레터 큐

  • 시간바퀴 알고리즘

  • Redis 만료 모니터링

1. 예정된 작업 종료 순서(최저)

일반적인 상황에서 가장 권장되지 않는 방법은 주문을 마감하거나 작업을 예약하는 것입니다. 이유를 설명하기 위해 다음 그림을 볼 수 있습니다.

주문 마감 시간은 주문 후 10분, 예정된 작업 간격도 10분이라고 가정했는데, 위 그림을 보면 1분 안에 주문이 들어오면 스캔이 되지 않는 것을 알 수 있습니다. 20분까지 주문 마감 작업을 실행하려면 이 오류가 10분에 이르며 이는 많은 시나리오에서 허용되지 않습니다. 또한 주요 주문 번호를 자주 스캔해야 하기 때문에 네트워크 IO 및 디스크 IO 소비가 발생하며 이는 특정 영향을 미칩니다. 실시간 거래이므로 PASS

2. RocketMq 지연 대기열 모드

지연된 메시지: 생산자가 메시지 서버에 메시지를 보낸 후 즉시 소비될 것으로 예상하지 않고 소비자가 소비할 수 있을 때까지 지정된 시간 동안 기다립니다. 이러한 유형의 메시지를 일반적으로 지연된 메시지라고 합니다. RocketMQ 오픈소스 버전에서는 지연된 메시지는 지원되지만, 임의의 시간 정밀도를 갖는 지연된 메시지는 지원되지 않으며, 특정 수준의 지연된 메시지만 지원됩니다. 메시지 지연 수준은 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h 총 18단계입니다.

이 방법은 예정된 작업보다 훨씬 낫지만 지연 수준이 18개에 불과하다는 치명적인 단점이 있습니다.(상용 버전은 맞춤 시간을 지원합니다.) 주문 마감 시간을 15분으로 설정하려면 어떻게 해야 할까요? 유연성이 충분하지 않은 것 같습니다.

3. RabbitMQ 배달 못한 편지 대기열 방법

Rabbitmq 자체에는 지연 대기열이 없으며 Rabbitmq 자체 대기열의 특성을 통해서만 구현할 수 있습니다. Rabbitmq에서 지연 대기열을 구현하려면 Rabbitmq의 데드 레터 교환(Exchange) 및 메시지 생존 시간을 사용해야 합니다. TTL(Time To Live).

데드 레터 교환(Dead Letter Exchange) 메시지는 다음 조건을 만족하는 경우 데드 레터 교환(Dead Letter Exchange)에 들어갑니다. 이것은 대기열이 아니라 스위치라는 점을 기억하십시오. 하나의 스위치는 여러 대기열에 대응할 수 있습니다.

소비자가 메시지를 거부했으며 거부 메소드의 requeue 매개변수가 false였습니다. 즉, 다시 대기열에 들어가 다른 소비자가 사용하지 않습니다. 위 메시지의 TTL이 도착했으며 메시지가 만료되었습니다.

대기열 길이 제한이 가득 찼습니다. 대기열 맨 위에 있는 메시지는 삭제되거나 배달 못한 편지 경로에 배치됩니다. 데드 레터 스위치는 일반적인 스위치입니다 . 만료된 메시지를 스위치에 넣는다고 해서 데드 레터 스위치라고 합니다. 데드 레터 스위치가 특정 종류의 스위치라는 의미는 아닙니다.

메시지 TTL(메시지 TTL) 메시지의 TTL은 메시지의 TTL입니다. RabbitMQ는 큐와 메시지에 대해 각각 TTL을 설정할 수 있습니다. 큐를 설정한다는 것은 소비자가 연결되지 않은 상태에서 큐가 유지되는 시간을 의미하며, 개별 메시지별로 별도의 설정도 가능합니다. 이 시간이 지나면 우리는 메시지를 데드 레터(Dead Letter)라고 간주합니다. 큐가 설정되고 메시지가 설정되면 더 작은 값이 사용됩니다. 따라서 메시지가 다른 대기열로 라우팅되는 경우 메시지의 종료 시간이 다를 수 있습니다(다른 대기열 설정). 여기서는 단일 메시지의 TTL에 대해서만 설명합니다. 왜냐하면 이것이 지연된 작업을 달성하는 데 핵심이기 때문입니다.

byte[] messageBodyBytes = "Hello, world!".getBytes();  
AMQP.BasicProperties properties = new AMQP.BasicProperties();  
properties.setExpiration("60000");  
channel.basicPublish("my-exchange", "queue-key", properties, messageBodyBytes);  

复制代码

메시지의 만료 필드 또는 x-message-ttl 속성을 설정하여 시간을 설정할 수 있으며 둘 다 동일한 효과를 갖습니다. 단지 만료 필드가 문자열 매개변수이므로 int 유형의 문자열을 작성해야 합니다. 위의 메시지가 대기열에 던져졌을 때 60초 후에 메시지가 소비되지 않으면 해당 메시지는 종료됩니다. 소비자가 소비하지 않습니다. 이 메시지 뒤에는 소비자가 표시하고 소비하는 "죽은" 메시지가 없습니다. 배달 못한 편지는 대기열에서 삭제되거나 해제되지 않으며 대기열의 메시지 수에 포함됩니다.

이 방법은 데드레터 큐에 진입하는 시간을 커스터마이징할 수 있는데, 완벽할까요? 그런데 메시지 미들웨어가 로켓mq인데 회사에서 상용 버전을 사용하지 못하는 경우가 있는데 어떻게 해야 하나요? 그런 다음 다음 섹션으로 이동하세요.

4. 타임휠 알고리즘

(1) 순환 대기열 생성 예를 들어 3600개의 슬롯(기본적으로 배열)을 포함하는 순환 대기열을 생성할 수 있습니다.

(2) 작업 세트, 링의 각 슬롯은 세트이며 동시에 타이머가 시작됩니다. 이 타이머는 1초마다 위에서 언급한 링 큐에서 한 칸씩 이동합니다. 슬롯을 식별하는 현재 인덱스 포인터가 있습니다. 감지되고 있습니다.

작업 구조에는 두 가지 매우 중요한 속성이 있습니다. (1) Cycle-Num: 현재 인덱스가 해당 사이클에서 이 슬롯을 스캔할 때 작업이 실행됩니다. (2) 주문 번호, 닫힐 주문 번호(일 수도 있음) 기타 정보(예: 특정 주문 번호를 기반으로 한 작업입니다)

현재 현재 지수가 0번째 슬롯을 가리킨다고 가정합니다. 예를 들어 3610초 후에 청산해야 할 주문이 있습니다. (1) 이 주문을 어느 슬롯에 넣어야 하는지 계산합니다. 계산하면 다음과 같습니다. 이제 1을 가리킵니다. 3610초 후에는 10번째 그리드가 되어야 하므로 이 Task는 10번째 슬롯의 Set에 배치되어야 합니다. (2) 이 Task의 Cycle-Num을 계산합니다. 순환 큐는 3600그리드이므로( 1초에 한 그리드씩 이동, 정확히 1시간) 이 작업은 3610초 후에 실행되므로 3610/3600=1원 후에 실행해야 하므로 Cycle-Num=1

현재 인덱스는 계속 이동하며 매초마다 새로운 슬롯으로 이동합니다. 이 슬롯의 해당 세트에 대해 각 태스크는 Cycle-Num이 0인지 확인합니다. (1) 0이 아닌 경우 이동해야 함을 의미합니다. 원을 몇 개 더 추가하세요. Change the Cycle -Num minus 1 (2) 0이면 마감 주문 작업이 곧 실행된다는 의미입니다. 주문 번호를 꺼내서 마감 주문을 실행하세요(별도의 스레드를 사용할 수 있습니다). 작업을 실행하기 위해), 세트에서 주문 정보를 삭제합니다. (1) 모든 주문을 폴링할 필요가 없음, 고효율 (2) 하나의 주문, 작업은 한 번만 실행됨 (3) 적시성이 좋고 초 단위까지 정확함 (타이머 이동 빈도를 제어하면 정확도를 제어할 수 있음)

5. Redis 만료 모니터링

시험 결과

        키 개수가 10,000개 미만일 경우 기본적으로 10초 이내에 만료 알림이 완료될 수 있습니다.

        키 수가 30,000개에 도달하면 일부 키가 120초 지연됩니다.

        키 개수가 50,000개에 도달했을 때 대부분은 이미 2분 정도 뒤쳐져 있었습니다.
        

Guess you like

Origin blog.csdn.net/piaomiao_/article/details/125084589