Redis의 성능 최적화를위한 13 가지 군사 규칙

이 기사에서는 Redis의 실행 속도를 개선하기 위해 다음 방법을 사용합니다.

  1. 키-값 쌍의 저장 길이를 줄입니다.

  2. 지연없는 (지연된 삭제) 기능을 사용하십시오.

  3. 키 값의 만료 시간을 설정합니다.

  4. 시간이 오래 걸리는 쿼리 명령을 비활성화합니다.

  5. 시간이 많이 걸리는 명령을 최적화하려면 slowlog를 사용하십시오.

  6. 파이프 라인을 사용하여 데이터를 일괄 적으로 조작합니다.

  7. 많은 양의 데이터가 동시에 실패하지 않도록하십시오.

  8. 클라이언트 사용 최적화;

  9. Redis 메모리 크기를 제한하십시오.

  10. 가상 머신 대신 물리적 머신을 사용하여 Redis 서비스를 설치합니다.

  11. 데이터 지속성 전략을 확인하십시오.

  12. THP 기능을 비활성화합니다.

  13. 분산 아키텍처를 사용하여 읽기 및 쓰기 속도를 높입니다.

1. 키-값 쌍의 저장 길이를 줄입니다.

키-값 쌍의 길이는 성능에 반비례합니다. 예를 들어 데이터 쓰기를위한 일련의 성능 테스트를 수행해 보겠습니다. 실행 결과는 다음과 같습니다.

위의 데이터를 통해 Redis는 동일한 데이터 유형의 저장을 위해 서로 다른 내부 코드를 사용하기 때문에 키가 변경되지 않은 경우 값이 클수록 작업 효율이 느려짐을 알 수 있습니다. 예를 들어 문자열에 대해 3 개의 내부 코드가 있습니다. : int (정수 인코딩), raw (메모리 할당을 최적화하기위한 문자열 인코딩), embstr (동적 문자열 인코딩), 이는 Redis의 작성자가 다른 인코딩을 통해 효율성과 공간의 균형을 이루기를 원하기 때문입니다. 데이터 사용량이 많을수록 내부 코드가 복잡하고 내부 코드가 복잡할수록 저장 성능이 저하됩니다.

이것은 쓰기 속도 일뿐입니다. 키-값 쌍의 내용이 크면 다른 몇 가지 문제가 발생합니다.

  • 콘텐츠가 클수록 지속 시간이 길어지고 일시 중단 시간이 길수록 Redis의 성능이 저하됩니다.

  • 콘텐츠가 클수록 네트워크에서 더 많은 콘텐츠가 전송되고 시간이 오래 걸리며 전체 작동 속도가 느려집니다.

  • 콘텐츠가 클수록 더 많은 메모리를 차지하고 메모리 제거 메커니즘이 더 자주 트리거되어 Redis에 더 많은 운영 부담을 가져옵니다.

따라서 완전한 의미를 보장하면서 가능한 한 키-값 쌍의 저장 길이를 줄여야하며, 필요한 경우 저장하기 전에 데이터를 직렬화 및 압축해야합니다. Java를 예로 들어 직렬화에 protostuff 또는 kryo를 사용할 수 있습니다. 압축은 빠른 사용이 가능합니다.

2. 게으른 무료 기능 사용

lazy free 기능은 Lazy 삭제 또는 지연된 삭제로 이해할 수있는 Redis 4.0의 새롭고 매우 유용한 기능입니다. 삭제시 비동기 지연된 키값 해제 기능을 제공하고, 키값 해제 작업을 BIO (Background I / O)의 별도 서브 스레드에 배치하여 삭제로 인한 Redis 메인 스레드의 차단을 줄이는 것을 의미합니다. 큰 키를 삭제하여 발생하는 성능 및 가용성 문제를 방지합니다.

lazy free는 기본적으로 모두 닫혀있는 4 가지 시나리오에 해당합니다.

 
  1. lazyfree-lazy-eviction no

  2. lazyfree-lazy-expire no

  3. lazyfree-lazy-server-del no

  4. slave-lazy-flush no

  5.  

그들이 나타내는 의미는 다음과 같습니다.

  • lazyfree-lazy-eviction : Redis 실행 메모리가 maxmeory를 초과 할 때 삭제하는 lazy free 메커니즘을 활성화할지 여부를 나타냅니다.

  • lazyfree-lazy-expire : 만료 시간의 키 값이 설정되어 있고 만료 후 삭제를 위해 lazy free 메커니즘을 열지 여부를 나타냅니다.

  • lazyfree-lazy-server-del : 일부 명령은 rename 명령과 같은 기존 키를 처리 할 때 암시 적 del 키 작업을 수행합니다. 대상 키가 이미 있으면 Redis는 먼저 대상 키를 삭제합니다. 삭제를 차단하는 큰 키이 구성은이 시나리오에서 삭제를 위해 지연없는 메커니즘을 열지 여부를 나타냅니다.

  • Slave-lazy-flush : 슬레이브 (슬레이브 노드)에 대한 전체 데이터 동기화를 수행합니다. 마스터의 RDB 파일을로드하기 전에 슬레이브는 데이터를 정리하기 위해 fluxhall을 실행합니다.이 때 lazy free 메커니즘이 삭제를 위해 활성화되었는지 여부를 나타냅니다. .

lazyfree-lazy-eviction, lazyfree-lazy-expire, lazyfree-lazy-server-del 및 기타 구성을 활성화하여 메인 스레드의 실행 효율성을 효과적으로 개선하는 것이 좋습니다.

3. 키 값의 만료 시간 설정

실제 비즈니스 상황에 따라 키 값에 대해 합리적인 만료 시간을 설정해야 Redis가 만료 된 키-값 쌍을 자동으로 삭제하여 메모리 사용량을 절약하고 키 값의 과도한 누적 및 빈번한 메모리 트리거를 방지하도록 도와줍니다. 전략.

4. 시간이 오래 걸리는 쿼리 명령 비활성화

대부분의 Redis 읽기 및 쓰기 명령의 시간 복잡도는 O (1)과 O (N) 사이입니다. 공식 문서에는 각 명령에 대한 시간 복잡도 설명이 있습니다. 주소 : https://redis.io/commands, 아래와 같이 :

그 중에서 O (1)은 안전하게 사용할 수 있음을 의미하고 O (N)은주의해야하며 N은 불확실 함을 의미하며 데이터가 클수록 질의 속도가 느려질 수 있습니다. Redis는 데이터 쿼리에 하나의 스레드 만 사용하기 때문에 이러한 명령이 오래 걸리면 Redis를 차단하고 많은 지연이 발생합니다.

Redis에 대한 O (N) 명령의 영향을 피하기 위해 다음 측면에서 변환을 시작할 수 있습니다.

  • keys 명령의 사용을 금지하기로 결정했습니다.

  • 모든 구성원을 한 번에 쿼리하지 않으려면 scan 명령을 사용하여 배치 및 커서를 탐색하십시오.

  • 메커니즘을 통해 Hash, Set, Sorted Set 및 기타 구조의 데이터 크기를 엄격하게 제어합니다.

  • 클라이언트에 정렬, 통합, 교차 및 기타 작업을 배치하여 Redis 서버의 작동 압력을 줄입니다.

  • 대용량 데이터를 삭제 (삭제) 할 경우 시간이 오래 걸릴 수 있으므로 비동기 삭제 방법을 사용하여 링크를 해제하는 것이 좋습니다. 그러면 기본 Redis 스레드를 차단하지 않고 대상 데이터를 삭제하는 새 스레드가 시작됩니다.

5. slowlog를 사용하여 시간 소모적 인 명령 최적화

slowlog 함수를 사용하여 가장 시간이 많이 걸리는 Redis 명령을 찾고 관련 최적화를 수행하여 Redis의 실행 속도를 개선 할 수 있습니다. 느린 쿼리에 대한 두 가지 중요한 구성 항목이 있습니다.

  • slowlog-log-slower-than : 느린 쿼리의 평가 시간, 즉이 구성 항목을 초과하는 명령은 느린 작업으로 처리되어 느린 쿼리 로그에 기록됩니다. 실행 단위는 마이크로 초 (1 초는 1000000 마이크로 초와 동일)입니다. ;

  • slowlog-max-len : 느린 쿼리 로그의 최대 레코드 수를 구성하는 데 사용됩니다.

실제 업무 상황에 따라 해당 구성을 만들 수 있습니다. 느린 로그는 삽입 된 순서의 역순으로 느린 쿼리 로그에 저장됩니다.이를 사용  slowlog get n 하여 해당 느린 쿼리 로그를 가져온 다음 해당하는 비즈니스를 찾을 수 있습니다. 관련 최적화를위한 이러한 느린 쿼리에.

6. 파이프 라인을 사용하여 대량 데이터 조작

파이프 라인 (파이프 라인 기술)은 한 번에 여러 Redis 명령을 처리하여 전체 상호 작용의 성능을 향상시키기 위해 클라이언트가 제공하는 일괄 처리 기술입니다.

Java 코드를 사용하여 Pipeline과 일반 작업의 성능 비교를 테스트합니다. Pipeline의 테스트 코드는 다음과 같습니다.

 
  1. publicclass PipelineExample {

  2. public static void main(String[] args) {

  3. Jedis jedis = new Jedis("127.0.0.1", 6379);

  4. // 记录执行开始时间

  5. long beginTime = System.currentTimeMillis();

  6. // 获取 Pipeline 对象

  7. Pipeline pipe = jedis.pipelined();

  8. // 设置多个 Redis 命令

  9. for (int i = 0; i < 100; i++) {

  10. pipe.set("key" + i, "val" + i);

  11. pipe.del("key"+i);

  12. }

  13. // 执行命令

  14. pipe.sync();

  15. // 记录执行结束时间

  16. long endTime = System.currentTimeMillis();

  17. System.out.println("执行耗时:" + (endTime - beginTime) + "毫秒");

  18. }

  19. }

  20.  

위 프로그램의 실행 결과는 다음과 같습니다.

실행 시간 : 297 밀리 초

일반적인 작업 코드는 다음과 같습니다.

 
  1. publicclass PipelineExample {

  2. public static void main(String[] args) {

  3. Jedis jedis = new Jedis("127.0.0.1", 6379);

  4. // 记录执行开始时间

  5. long beginTime = System.currentTimeMillis();

  6. for (int i = 0; i < 100; i++) {

  7. jedis.set("key" + i, "val" + i);

  8. jedis.del("key"+i);

  9. }

  10. // 记录执行结束时间

  11. long endTime = System.currentTimeMillis();

  12. System.out.println("执行耗时:" + (endTime - beginTime) + "毫秒");

  13. }

  14. }

  15.  

위 프로그램의 실행 결과는 다음과 같습니다.

실행 시간 : 17276 밀리 초

위의 결과에서 파이프 라인의 실행 시간은 297 밀리 초, 일반 명령의 실행 시간은 17276 밀리 초로 파이프 라인 기술은 일반 실행보다 약 58 배 빠르다는 것을 알 수 있습니다.

7. 대량 데이터의 동시 장애 방지

Redis 만료 된 키 값 삭제는 탐욕스러운 전략을 사용합니다. 초당 10 개의 만료 된 스캔을 수행합니다.이 구성은 redis.conf에서 구성 할 수 있습니다. 기본값은  hz 10Redis가 임의로 20 개의 값을 선택하고이 20 개의 값에서 만료 된 키를 삭제하는 것입니다. 만료 된 키의 비율이 25 %를 초과하면 다음 그림과 같이이 프로세스를 반복합니다.

대규모 시스템에서 동시에 많은 수의 캐시가 만료되는 경우 Redis는 만료 된 사전의 만료 된 키 값이 드물게 삭제되고 전체 실행이 끝날 때까지 루프에서 만료 된 사전을 여러 번 스캔하고 삭제합니다. 프로세스로 인해 Redis가 실패합니다. 읽기 및 쓰기에 명백한 지연이 있습니다. 지연의 또 다른 이유는 메모리 관리자가 메모리 페이지를 자주 회수해야하기 때문에 일정량의 CPU를 소모하기 때문입니다.

이러한 지연을 피하기 위해서는 많은 수의 캐시가 동시에 만료되는 것을 방지해야합니다. 간단한 해결책은 만료 시간을 기준으로 지정된 범위의 난수를 추가하는 것입니다.

8. 클라이언트 사용 최적화

클라이언트를 사용할 때 파이프 라인 기술을 가능한 많이 사용하는 것 외에도 Redis 연결을 자주 생성하고 파괴하는 대신 가능한 한 Redis 연결 풀을 사용하는 데주의를 기울여야합니다. 네트워크 전송 횟수를 줄이고 불필요한 통화 지침을 줄입니다.

9. Redis 메모리 크기 제한

64 비트 운영 체제에서 Redis의 메모리 크기는 무제한입니다. 즉, 구성 항목  maxmemory <bytes> 이 주석 처리되어 실제 메모리가 부족할 때 스왑 공간을 사용하여 공간을 교환하고 Redis를 사용하는 시스템 메모리 페이징이 스왑 공간으로 이동되면 Redis 프로세스가 차단되어 Redis가 지연되어 Redis의 전체 성능에 영향을 미칩니다. 따라서 Redis의 메모리 크기를 고정 값으로 제한해야합니다. Redis가이 값에 도달하면 메모리 제거 전략이 트리거됩니다. Redis 4.0 이후에는 8 개의 메모리 제거 전략이 있습니다 .

  1. noeviction : 데이터를 제거하지 않음 메모리가 부족하면 새 작업에서 오류를보고합니다. Redis 기본 메모리 제거 전략;

  2. allkeys-lru : 전체 키 값에서 가장 긴 사용하지 않은 키 값을 제거합니다.

  3. allkeys-random : 임의의 키 값을 제거합니다.

  4. Volatile-lru : 만료 시간이있는 모든 키 값 중에서 가장 긴 미사용 키 값을 제거합니다.

  5. Volatile-random : 만료 시간이있는 모든 키 값을 무작위로 제거합니다.

  6. volatile-ttl : 더 일찍 만료되는 키 제거의 우선 순위를 지정합니다.

Redis 4.0 버전에는 두 가지 새로운 제거 전략이 추가되었습니다.

  1. volatile-lfu : 만료 시간이있는 모든 키 중에서 가장 적게 사용 된 키 값을 제거합니다.

  2. allkeys-lfu : 전체 키 값에서 가장 적게 사용 된 키 값을 제거합니다.

그중 allkeys-xxx는 모든 키 값에서 데이터를 제거하는 것을 의미하고 volatile-xxx는 만료 된 키가있는 키 값에서 데이터를 제거하는 것을 의미합니다.

실제 업무 상황에 따라 설정할 수 있으며, 기본 제거 전략은 데이터를 제거하지 않으며 추가시 오류가보고됩니다.

10. 가상 머신 대신 물리적 머신 사용

Redis 서버는 물리적 네트워크 포트를 물리적 시스템과 공유하고 물리적 시스템에 여러 개의 가상 시스템이 실행될 수 있으므로 가상 시스템에서 실행하면 메모리 사용량 및 네트워크 대기 시간 측면에서 성능이 매우 나빠질 수 있습니다. ./redis-cli --intrinsic-latency 100 명령어를 통해 지연 시간 을  확인하고, Redis의 성능에 대한 요구 사항이 높은 경우, 가능한 한 물리적 머신에 직접 Redis 서버를 배포해야합니다.

11. 데이터 지속성 전략 확인

Redis의 지속성 전략은 재해 복구 또는 데이터 마이그레이션을 수행 할 수 있도록 메모리 데이터를 하드 디스크에 복사하는 것이지만이 지속성 기능을 유지하려면 많은 성능 오버 헤드가 필요합니다.

Redis 4.0 이후 Redis에는 세 가지 지속성 방법이 있습니다.

  • RDB (Redis DataBase, 스냅 샷 모드)는 특정 순간의 메모리 데이터를 바이너리 방식으로 디스크에 기록합니다.

  • AOF (Append Only File, 파일 추가 모드)는 모든 작업 명령을 기록하고 텍스트 형식으로 파일에 추가합니다.

  • Redis 4.0 이후에 추가 된 새로운 방식 인 Hybrid Persistence 방식입니다. Hybrid Persistence는 RDB와 AOF의 장점을 결합한 것입니다. 쓰기시 먼저 현재 데이터를 RDB 형태로 파일 시작 부분에 쓴 다음 후속 작업 명령을 추가합니다. AOF 형식으로 파일에 저장되므로 Redis 다시 시작 속도를 보장 할뿐만 아니라 데이터 손실 위험도 줄일 수 있습니다.

RDB와 AOF 지속성에는 장단점이 있습니다. RDB는 일정 기간 동안 데이터 손실을 일으킬 수있는 반면 AOF는 대용량 파일로 인해 Redis의 시작 속도에 영향을줍니다. RDB와 AOF의 장점을 모두 갖기 위해서는, Redis 4.0에는 하이브리드 지속성 방법이 추가되었으므로 지속성 작업을 수행해야 할 때 하이브리드 지속성 방법을 선택해야합니다.

config get aof-use-rdb-preamble 명령을 사용하여 하이브리드 지속성이 활성화되었는지 여부 쿼리 할 수  있으며 실행 결과는 다음 그림에 표시됩니다.

그중 yes는 하이브리드 지속성이 켜져 있음을 의미하고 no는 꺼져 있음을 의미하며 Redis 5.0의 기본값은 yes입니다. Redis의 다른 버전 인 경우 먼저 하이브리드 지속성이 켜져 있는지 확인해야합니다. 꺼져 있으면 다음 두 가지 방법으로 켤 수 있습니다.

  • 명령 줄을 통해 열기

  • Redis 구성 파일을 수정하여 열기

① 명령 줄을 통해 열기

명령  config set aof-use-rdb-preamble yes 실행 결과는 아래 그림과 같습니다.

명령 줄 설정 구성의 단점은 Redis 서비스를 다시 시작하면 설정 구성이 무효화된다는 것입니다.

② Redis 구성 파일을 수정하여 열기

Redis의 루트 경로에서 redis.conf 파일을 찾고 구성 파일 aof-use-rdb-preamble no 을  aof-use-rdb-preamble yes 다음 그림으로 변경합니다  .

구성이 완료된 후 구성을 적용하려면 Redis 서버를 다시 시작해야하지만 구성 파일은 Redis 서비스가 다시 시작될 때마다 수정되며 구성 정보는 손실되지 않습니다.

지속될 필요가없는 비즈니스에서는 지속성을 끌 수 있으므로 간헐적 인 고착없이 Redis의 실행 속도를 효과적으로 향상시킬 수 있습니다.

12. THP 기능 비활성화

Linux 커널은 2.6.38 커널에 THP (Transparent Huge Pages) 기능을 추가합니다. 2.6.38 커널은 기본적으로 활성화되어있는 2MB의 대용량 메모리 페이지 할당을 지원합니다.

THP를 켜면 포크 속도가 느려지고, 포크 후 각 메모리 페이지가 4KB에서 2MB로 변경되어 다시 쓰기 과정에서 상위 프로세스의 메모리 사용량이 크게 증가합니다. 동시에 각 쓰기 명령에 의해 발생하는 복사 메모리 페이지 단위가 512 배 확대되어 쓰기 작업의 실행 시간이 느려지고 많은 쓰기 작업의 쿼리 속도가 느려집니다. 예를 들어 간단한 incr 명령도 느린 쿼리에 표시되므로 Redis는이 기능을 비활성화 할 것을 권장합니다. 비활성화 방법은 다음과 같습니다.

echo never> / sys / kernel / mm / transparent_hugepage / enabled

시스템을 다시 시작한 후에도 THP 구성이 계속 적용되도록하려면 /etc/rc.local에 추가 할 수 있습니다  echo never > /sys/kernel/mm/transparent_hugepage/enabled.

13. 분산 아키텍처를 사용하여 읽기 및 쓰기 속도 향상

Redis 분산 아키텍처에는 세 가지 중요한 수단이 있습니다.

  • 마스터-슬레이브 동기화

  • 센티넬 모드

  • Redis 클러스터

마스터-슬레이브 동기화 기능을 사용하여 메인 라이브러리에 쓰기를 실행하고 읽기 기능을 슬레이브 서비스로 전송할 수 있으므로 단위 시간당 더 많은 요청을 처리 할 수 ​​있으므로 Redis의 전체 실행 속도가 향상됩니다.

센티넬 모드는 마스터-슬레이브 기능의 업그레이드이지만 마스터 노드가 충돌하면 수동 개입없이 Redis의 정상적인 사용이 자동으로 복원 될 수 있습니다.

Redis Cluster는 Redis 3.0에 의해 공식적으로 출시되었습니다. Redis 클러스터는 데이터베이스를 여러 노드에 분산하여 각 노드의 부하 압력을 분산합니다.

Redis Cluster는 가상 해시 슬롯 파티션을 사용합니다. 모든 키는 해시 함수에 따라 0에서 16383까지의 정수 슬롯에 매핑됩니다. 계산 공식은 다음과 같습니다. slot = CRC16 (key) & 16383. 각 노드는 슬롯의 일부를 유지 관리합니다. 슬롯에 의해 매핑 된 키 값 데이터입니다. 이러한 방식으로 Redis는 한 서버에서 여러 서버로 읽기 및 쓰기 부담을 분산 할 수 있으므로 성능이 크게 향상됩니다.

이 세 가지 기능 중 하나만 사용하면됩니다. Redis Cluster가 선호되는 구현 솔루션이어야한다는 것은 의심의 여지가 없습니다. 더 많은 서버에 대한 읽기 및 쓰기 부담을 자동으로 공유 할 수 있으며 자동 재해 복구 기능이 있습니다.

추천

출처blog.csdn.net/A___B___C/article/details/107375451