2016년 9월 23일 금요일

Redis ( CPU Affinity 와 SoftIRQ 를 활용한 Redis 성능 개선 )

  1. 목적 

    1. Redis 를 사용 중인 시스템의 성능 개선 방향을 모색하고, 시스템상에서 안정성을 위해하지 않고, 성능을 개선 할 수 있는 방안이 있기에, 이에 대한 테스트를 진행하여
      증명함을 목적으로 한다.
  2. 테스트 환경 

    1. 아래 환경으로, 1개의 서버에 3개의 Redis Master 서버를 기동하고, 테스트를 수행하였음.
    2. 장비 사양 
      구성
      상세
      CPUIntel(R) Xeon(R) CPU E5645@2.40GHz 6 Core ( HT X)
      Memory16 GB
      Disk1+0 RAID HDD 550G
      NetworkNetXtreme II BCM5709 1Gigzbit Ethernet 1 Port
    3. Redis 구성 
      구성
      상세
      ReplicationActive-StandBy Replication 구성 , RDB 파일 이중화
      AOFActive-StandBy AOF 구성
      Memory각 Redis 당 3GB
    4. 장비 구성 
      IP
      PORT
      Role
      X.X.X.4550001Master
      X.X.X.4550002Master
      X.X.X.4550003Master
      X.X.X.4450001Slave
      X.X.X.4450002Slave
      X.X.X.4450003Slave
      X.X.X.43NULLBenchMark Toll - 3개 Process , 50 Clinet Per a Process
  3. 튜닝 포인트  

    1. Process 의 CPU Affinity 를 지정 할 수 있는 Taskset 으로 Redis Process 를 특정 CPU 에 Binding 
    2. Network Ethernet 이 사용하는 CPU 의 IRQ(인터럽트) 를 특정 CPU 에 Affinity 할 경우와 전체 CPU 에 나누어 분산 시켰을 때의 성능 차이 분석
      1. Ethernet 은 기본적으로 IRQ 를 CPU 한개의 노드에 Affinity 되어서 동작하려고 내부적으로 노력한다. 이는 소켓 버퍼가 성능 향상을  위해 CPU L2 캐쉬단에서 동작하기 때문에, 네트워크를 사용하는 특정 프로세스는 Ethernet IRQ 가 Bind 되어 있는 CPU 를 쓰게 되는 것을 확인 할 수 있을 것이다.
        (예를 들면 보통 Ehternet 은 IRQ Balancer 를 동작하지 않는 이상  0 번 CPU 에서 보통 동작하려고 노력한다. 이때 프로세스를 띄워서 소켓 통신을 해보면 이 프로세스는 보통 CPU 0 을 사용한다 (CPU 인터럽트 비용을 줄이기위해)  그리고, 이때 한개 프로세스를 더 띄워보면, 이 프로세스도 CPU 0 을
        사용하고자 노력하는 것을 확인할 수 있다.  즉 IRQ 를 Balancing 해주지 않으면 0 번 CPU 에 프로세스들이 몰리는 현상이 발생한다.  ( 몰리는 현상이라기 보다는 Ethernet 을 사용하기 위한 인터럽트다 )


  4.  테스트 

    1. 시스템 튜닝 전 (NO-Tunning)
      1. 설명 
        1. Default 로 테스트 한 것으로 해당 서버에는 3개의 Redis Master 가 동작하고, IRQ 는 1 번 CPU 에서 동작하고 있다.  
        2. 이때 Redis 들이 네트워크 Interrupt 를 최소화하고자 1 번 CPU 에 몰리고 있는 현상을 볼 수 있다.  1번 CPU 가 Busy 하고 나머지는 놀고 있기 때문에 CPU 사용을 분산해서 튜닝을 진행해보자
      2. 성능 
        수행 회수
        operation
        50001
        50002
        50003
        Avg
        Max Latency
        1회차Set54351.9650729.4949060.9751380.81 206 milliseconds
         Get49042.6859070.9350986.0753033.23 10 milliseconds
        2회차Set51705.7852170.2952639.3452171.8 
         Get53329.9252203.5152097.4552543.63 
      3. CPU


    2. 1차 튜닝 
      1. 설명 
        1. IRQ 는  0-1 을 사용할 수 있도록 Binding 한다. cat /proc/interrupt 를 보면 확인 할 수 있다.  
        2. 그리고 Taskset 으로 Redis 를 CPU 2개씩 Affinity 를 지정한다.  50001 Redis 는 2-3 CPU , 50002 Redis 는 4-5 CPU , 50003 Redis 3-5 CPU 로 Binding 하였다.  
        3. 성능이 많이 올라갔으나 L2 캐쉬를 사용하지 않기때문에 Redis 의 Latency (응답속도) 가 조금 튀는 것을 확인 할 수 있었다.  다만 특정 한 프로세스가 점유하는 현상이 없어지므로,
          각 프로세스가 비슷한 응답을 줄수 있다.  
      2. 성능 
        수행 회수
        operation
        50001
        50002
        50003
        Avg
        Max Latency
        1회차Set64167.5558679.25 59765.0061423.4 201 milliseconds
         Get71295.1578529.9271536.9073787.3243 milliseconds
        2회차Set62506.2563921.4561601.3962676.36 
         Get72469.0280568.4974142.1775726.56 
      3. CPU

    3. 2차 튜닝 
      1. 설명 
        1. Ethernet 의 각 IRQ 를 모든 CPU 에 분산한다.   그리고 Redis 를 CPU 2개씩 Affinity 를 지정한다.  50001 Redis 는 0-1 CPU , 50002 Redis 는 2-3 CPU , 50003 Redis 4-5 CPU 로 Binding 하였다.  
        2. CPU 가 안정화되는것을 확인할 수 있다.  그리고 Max Latency 로 많이 떨어짐을 확인 할 수 있었다.  
      2. 성능 
        수행 회수
        operation
        50001
        50002
        50003
        Avg
        Max Latency
        1회차Set62820.3864454.5957582.4661619.14139 milliseconds
         Get74573.4571675.3478531.1674926.65 16 milliseconds
        2회차Set62632.3163580.0757126.5461112.97 
         Get70313.673284.7772195.9171931.43 
      3. CPU
  5. 사용 명령어 

    1. 프로세스의 CPU Affinity 확인 
      1. $> taskset -cp $PID 
    2. 프로세스의 CPU Affinity 변경 ( 0-1 번 CPU Binding )
      1. $> taskset -cp 0-1 $PID
    3. IRQ 변경( 0 번 CPU 에 Binding ) 
      1. $> cd /proc/irq/$number/
      2. $> echo 0 > smp_affinity_list
  6. 결론 

    1. Taskset 으로 Redis Process 를 CPU 에 Affinity 하고, IRQ 를 분산 시킨 결과 SET 은 Default 대비 20% 성능 개선 , GET 은 Default 대비 40 % 정도 성능 개선 효과를 볼 수 있었다. 
    2. 1차 튜닝 방법과 2차 튜닝 모두 장단점이 있다.  1차 튜닝은 일정한 Latency 패턴 유지 , 2차 튜닝은 Redis 가 AOF 를 사용할 때 Dist Write Interrupt 를 CPU 한쪽에 몰아서 Waiting 을 줄일 수 있고, 네트웍에 대한 Interrupt 도 줄일 수 있다. 
    3. Taskset 과 IRQ 조절은 Redis 프로세스를 내리지 않고도 가능하므로, QA 시에 조절하면서 적정한 값을 찾는 것이 가장 좋다고 볼 수 있다. ( Operation 패턴(lpush , set,get 조합) 에 따라 달라질 수 있기 때문이다. 
    4. 튜닝은 각 시스템과 환경에 따라 달라지므로, 적절히 튜닝하여 성능 개선을 하도록 하자.  

댓글 없음:

댓글 쓰기