#####  네트워크 다중화


# 1. 링크의 다중화와 리눅스 Bonding Driver


<Bonding Driver>


a.  중요파라미터 

- MII(Media Independent Interface) 감시 : NIC Link Pown 발생시 고장으로 간주, 저비용과 단시간으로 구현가능

- ARP(Address Resolution Protocol) 감시 : 고장을 간과할 가능성은 낮으나 ARP 요청을 송신하지 않으면 잘못된 진단으로 판단


b. Bonding Driver 동작모드



#2. 스위치 다중화

: Bonding 드라이버를 사용하여도 동일한 스위치에 접속하여 있다면 스위치 장애에는 대응하기가 어려움



# 3. 스위치 증설 + more

- Boding, Trunking, Link Aggregation, 802.3ad, ARP 사용

- Looping으로 인한 Broadcast Storm 발생

=> STP 사용





##### RSTP 

: Rapid Spanning Tree Protocol


- 스위치 상호간에 BPDU(Bridge Protocol Data Unit)패킷을 교환하여 우선순위 정보 등의 교환과 장애 검출 수행

- RSTP가 동작하는 브릿지에서는 BPDU를 교환하여 상위 브릿질즐 판별(Root Bridge)

=> 우선순위 검사


1. Root 브릿지라고 인식되어있는 브릿지의 브릿지 ID

2. 루트브릿지로의 경로비용

3. 브릿지의 브릿지 ID

4. 상대 브릿지가 BPDU를 송신한 포트의 포트 ID

5. 상대 브릿지로부터 BPDU를 수신한 포트의 포트 ID


* 브릿지 ID (8bytes) : 사용자가 설정한 우선순위 값(상위 2bytes) + MAC(6bytes)


- RSTP에서 port의 역할

: 모든 브릿지의 초기화 과정에서 브릿지 각 포트에 대하여 RSTP상의 역할을 결정


1. 루트포트 : 브릿지 각 포트 중 가장 상위 브릿지와 연결되어 있는 포트

2. Designated port : 하위 브릿지 연결 포트

3. Alternate Port : root port외에 상위 브릿지에 연결되어있는 port

4. Backup port : 다른 designated port로부터 자기자신이 보낸 BPDU를 수신한 port

5. Disable port



<RSTP의 동작>

1. VLAN 도입 : 논리적 네트워크 분할(브로드캐스트 도메인 분할)


- Static VLAN

- Dynamic VLAN


- MAC기반 VLAN : 빈번한 변경이 없는 서버팜에선 상관 없음

- Port기반 VLAN, Tag기반 VLAN  : but, 일반적으로 서버팜에선 빈번한 변화도 고려해야 함


a. Port VLAN : 스위치의 port마다 VLAN ID 할당



- 간단한 구성

- 트래픽과 관계없이 여러포트가 소비됨

=> 대량의 데이터를 다룰 때 서버는 동일한 스위치에서 연결하여 제어되어야 함


b. 태그 VLAN : VLAN ID를 포함한 식별정보(tag)

여러개의 스위치를 걸쳐서 VLAN 그룹을 나눌 수 있음

=> VLAN 테깅 기능을 가지는 장비를 사용해야함 (VLAN 태그를 인식하지 못하면 패킷을 버리기 떄문)



2. 서버팜에서 활용


<모두 다중화>



- WAN 스위치는 각 4개 포트만 이용하고 낭비가 심함

- 대체장비가 WAN쪽 스위치로는 연결되지 않음

물리적 구조의 이유로 활용이 적음

- LVS만 구성이 특수함(NIC가 4개 필요)



* 모두 다중화에서 동일한 스위치에 모두 구성으로 변화    


<동일한 스위치에 모두 구성>



- but, 브로드캐스트/멀티캐스트 frame이 모든 포트로 포워딩 됨!!



* VLAN 등장 


< Port VLAN >



- VLAN을 WAN구간과 LAN구간으로 나누어 분류했지만, Load Balancer는 NIC가 4개여야하며, 

장애에 대비해 대체장비에도 4개의 NIC를 구성해야함



* VLAN을 태깅 기반으로 구성


< Tag VLAN>





3. 물리적 구성의 단순화

: 논리적으로 구성할 VLAN 환경에서도 VLAN 구성에 따른 병목현상이 있을 수 있으므로 애초부터 물리적 구성을 잘해야함



4. 성능튜닝


I/O <-> OS


"top", "ps", "sar" 명령어



<병목 규명을 위한 작업>

- Load Average 확인 : top, uptime 명령어

- CPU, I/O 중 병목원인 조사

CPU : ps, strace, oprofile

I/O : sar, vmstat



5. 프로세스 상태변화




a. Process discripter 상태

 TASK_RUNNING

 실행가능 상태 

 TASK_INTERRUPTIBLE

 interrupt 가능한 대기 상태. 

 복귀시간이 예측 불가능하거나 장기간의 대기 상태로 사용자의 입력대기 상태나 sleep 상태

 TASK_UNINTERRUPTIBLE 

 중단 가능 상태로 주로 단기간에 복귀할 경우

 TASK_STOPPED

 suspend 시그널을 받아서 실행이 중단된 상태 (~resume전까지)

 TASK_ZOMBIE

 좀비상태로 자식 프로세스가 exit해서 부모 프로세스로 반활 될 때까지의 상태



b. Load Average로 환산되는 대기상태


* 프로세스 수행 상태 변화

TASK_RUNNING이면서 실행 중

TASK_RUNNING

TASK_INTERRUPTIBLE

TASK_UNINTERRUPTIBLE


(TASK_RUNNING, TASK_UNINTERRUPTIBLE. 이 두 상태만 Load Average 계산에 포함)

즉, CPU를 사용하고자 해도 다른 프로세스가 CPU를 사용하고 있어서 기다리고 있는 프로세스

계속해서 ㄱ처리하고자 해도 디스크 입출력이 끝날때까지 기다려야하는 프로세스



c. Load Average를 계산하는 커널코드 확인


- kernel/timer.c, calc_load()

: avenrun 전역변수에 "count_active_tasks()" 값을 저장

- kernel/sched.c, nr_active()

: for_each_online_cpu() // cpu 별로 계산할 때 사용하는 매크로

- cpu_rq()    // cpu에 엮여있는 runqueue얻는 매크로

=> CPU의 runqueue를 차례로 확인

- cpu_rq(i) -> nr_running

cpu_rq(i) - nr_uninterruptible


즉, averun값은 Load Average 값


> cat /proc/loadavg

=> averun 배열의 값을 정형화해서 출력 (TASK_RUNNING, TASK_UNINTERRUPTIBLE 합산)



6. CPU 사용률과 I/O 대기율


a. 원인 찾는 방법

- sar(System Activity Reporter)로 CPU사용률, I/O 대기률 확인 : "%user", "%systemz)

sysstat 패키지에 포함


- 시스템(커널) 모드, 유저모드

- I/O 바운드인 경우의 sar : "%iowait"



7. multi CPU와 CPU 사용률


sar -P ALL | head -l3

(-P : 프로세서별로 조회, 이 설정이 없으면 합계로 나옴)



8. CPU 사용률이 계산되는 원리


a. Timer interrupt로 커널 내부에서 수행

b. CPU 용으로 준비된 전용공간인 cpu_usage_stat구조체에 계산 결과 저장

CPU마다 별도의 공간에 데이터를 저장하므로 sar등에서 CPU별 정보를 얻을 수 있다.


* Process Accounting

: 프로세스 전환을 위해 각 프로세스가 생성된 후부터 CPU 시간을 이용한 정보


c. Process Accounting을 CPU별로 합산해서 단위시간으로 나누어 CPU사용률을 계산



9. Process Accounting 커널코드


a. include/kernel-stat.h

- cpu_usage_stat : 계산된 CPU별 정보를 저장하는 구조체

- kernel_stat : DECLARE_PER_CPU() 매크로


b. kernel/timer.c, update_process_times()

: 실제 process accounting 처리


(1) current 매크로로 현재 프로세스의 프로세스 디스크립터 얻기

(2) user_tick 값을 보고 처리를 분기

(3) 최근 시간이 kernel mode였는지 user mode였는지에 따라 각각 account_system_time(), account_user_time()을 호출 (kernel/sched.C)

(4) CPU 용으로 cpustat 구조체를 얻음

(5) cpu_add 매크로로 현 프로세스의 uptime(cpu소비시간)을 계산

(6) cpu_stat의 nicert user값에 cputime64_add 매크로로 동일한 경과시간을 갱신

(7) id/e, 시스템모드로 계산하고 있는 시간, I/O를 기다리는 시간

=> cpu_usage_stat 항목 갱신



10. Thread, Process


*Apache의 경우 MPM으로

- prefork하면 멀티쓰레드

- worker하면 멀티쓰레드+ 멀티프로세스


멀티프로세스 : 각각 독립적인 메모리 공간,

멀티스레드 : 프로세스 별로 메모리 공간을 공유. 메모리 공간 전환이 낮아지므로 전환 비용도 줄어듬


a. 커널 내부에서의 프로세스와 스레드

: 커널 내부에서는 스레드 하나에 프로세스 디스크립터 하나가 할당되며, 스레드와 프로세스가 동일한 로직으로 스케쥴링 됨

스레드를 LWP(Light Weight Process)라고 함


- "ps" 명령으로 멀티스레드를 확인할 때 -L 옵션이 필요

ps -elf | grep (CMD|mysql)


- PID는 프로세스별로 같고 스레드 ID인 LWP는 다름

- 단일 프로ㅔ스에 복수 스레드 동작

- "NLWP" Number of LWP의 약자인 명령어로 스레드 갯수 출력


b. LinuxThreadset


- NPTL, Native POSIX Thread Library

- LinuxThread

=> 리눅스의 여러가지 멀티스레드 구현형태


c. ps, sar, vmstat


(1) ps : Report Process Status

<항목>

- %CPU : PS 명령 수행하는 프로세스의 CPU 사용률

- %MEM : 메모리 백분률 환산 값

- VSZ, RSS : 각 해당 프로세스가 확보하고 있는 가상 메모리 영역과 물리 메모리 영역의 크기

- STAT : 프로세스 상태

- TIME : CPU 사용기간


- VSZ : Virtual Set Size

- RSS : Resident Set size


- Virtual Memory

- Paging


* 실제 매핑(실제 물리메모리와의 매핑)은 실제 쓰기 작업시에 이루어짐


< 가상메모리 구조 도입의 장점 >

- 메모리 over-wrapping 가능

- 흝어져있는 물리메모리 공간들을 가상의 연속된 공간으로 사용가능

- 물리메모리 부족 시, 우선순위에서 밀린 순으로 메모리 매핑을 해제하여 2차 기억장치로 swapping을 수행

-서로 다른 프로세스가 창조하는 가상메모리 영역을 동일한 물리메모리에 대응

=> 두개의 프로세스가 메모리 공유 (ef. IPC 공유메모리..)


(2) TIME은 CPU 사용시간

: 프로세스 디스크립터에 기록된 CPU 사용시간



(3) Blocking / Busy Loop 차이를 "ps"명령어로 확인


"ps"를 실행


- STATE 필드가 R(running)이면서, CPU사용 시간인 TIME필드가 계속 증가하면, Busy Loop상태

- STATE 필드가 S(TASK_INTERUPTIBLE)이면서 CPU사용시간이 증가하지 않으면, Blocking된 상태


(4) sar (System Activity Reporter)

: OS가 보고하는 각종 지표/정보


- sysstat 패키지에 포함

- 사용방법 : 

과거의 동계데이터조회(default)

현재 데이터 주기적 확인


- sar에는 sadc라는 백그라운드 프로그램이 포함

- sysstat패키지 설치시 자동으로 sadc가 커널로부터 레포트를 수집하여 저장함

(sar명령어를 옵션없이 사용하면 sadc가 수집한 cpu사용률의 과저 통계를 참고할 수 있음, default는 0:00부터의 데이터)


- 어제 이전의 데이터 조회 : -f옵션 사용. "/var/log/sa" directory에 log파일 저장

- 주기적으로 현재 데이터 조회 : "sar 1 1000", 1초 간격으로 1000회

- cpu 사용률 확인 : "sar -u"

* user/system/iowait/idle 값이 중요

- 로드에버리지 확인 : "sar -q", 실행큐에 쌓여있는 프로세스 수 등등

- 메모리 사용량 확인 : "sar -r", 물리메모리 이용현황


<항목>

kbmemfree 

kbmemused

memused  : 물리메모리 사용률

kbbuffers  : 커널 내 버퍼로 사용되고 있는 물리 메모리량

kbcached  : 커널내에서 캐시메모리로 사용중인 물리 메모리량

kbswpfree

kbswpused


- "sar -w과 조합하여 스왑이 발생한 경우, 해당 시간대의 메모리 사용량 확인



(5) I/O 부하경감과 페이지 캐시

- 4KB의 페이지 단위

- 캐시메모리, 페이지캐시


!! 리눅스의 페이지 캐싱 동작은 

가능한 남아있는 페이지를 페이지 캐시로 활용하고 함 !!


=> 시간이 지남에 따라 kbmemfree가 줄어느는데, 이는 위와같은 이유로 kbcache가 증가하기 떄문이다.



(6) 페이지 캐시에 의한 I/O부하의 경감 효과

: 디스크 액세스를 줄이기 위해 캐시를 효율적으로 잘 사용해야 함


- 메모리 증설

- 메모리 증설이 어렵다면,

데이터를 분할해서 각각의 서버에 위치시키도록 하는법을 검토



(7) 페이지 캐시는 한 번의 read에서 시작


"sar -w" 스왑 발생 상황 확인


pswpin/s : 스왑인 상황

pswout/s : 스왑아웃 상황



(8) vmstat : 가상메모리 관련 정보, report Virtual Memory Statics


ex. vmstat 1 1000


- bi : 블록디바이스에서 수신한(in) 블럭

- bo : 블록디바이스에서 송신한 블럭(out)


cf. 

- character device : 바이트 단위 I/O

- Block device : 블록단위 I/O


(9) OS 튜닝 

: 부하의 원인을 알고 이를 제거하는 작업 


a. 최근의 OS나 미들웨어

b. 메모리 증설과 캐시영역 확보

- 데이터량이 너무 많은지 체크

- 애플리케이션들에서의 처리 알고리즘 변경


(10) 아파치 튜닝


a. 병렬처리의 구현모델

- 프로세스를 여러개 생성하여 처리하는 멀티프로세스 모델

- 멀티쓰레드 모델

- 입출력을 감시해서 이벤트가 발생하는 타이머에 처리를 전환하는 시그널스레드로 이벤트 모델


b. MPM, multi-processing Module

: 아파치에서 병렬처리를 수행하는 코어 부분


<구현모듈>

- prefork : 멀티프로세스 모델, 안전지향, 후방호환성이 높은 MPM

- worker : 멀티프로세스 + 멀티스레드, 확장성이 높은 MPM


c. worker 모델이 메모리 효율이 좋음

- copy on write

- context switching의 차이

: 메모리전환이 없으면 TLB를 그래도 유지

TLB : 메모리의 가상 주소를 물리주소로 변환하는 처리를 가속화 하기위한 캐시로 CPU내부의 구조.

context switcing 발생 시 TLB 초기화 됨 (비용이 큼)


d. 아파치에서 하나의 클라이언트 요청에 대해 하나의 프로세스or스레드가 응답

=> 스레드건 프로세스건 갯수가 중요



(11) httpd.conf


a. MaxClient : 동시에 접속 가능한 client 수

b. Server Limit Thread  or Process 수 (고려사항)

- 서버가 탑재되어있는 물리 메모리 용량 : "free"로 하드웨어 스팩확인

- 프로세스 하나당 평균 메모리 소비량 : "ps", "top" 명령어, "proc" 파일( /proc/<PID>/stams)


ex. 

<가정>

- 메모리 4GB

- httpd 프로세스 하나당 100MB의 메모리를 사용

- OS가 512MB 사용


-> 4GB - 512MB = 3.5GB를 httpd에 할당

-> 3,500 / 100 = 35개

-> MAX client의 갯수는 35개


c. copy-on-write

: 부모자식 프로세스 간 메모리 공유


- fork 는 비용이 많이 듬

- 가상공간을 각각 만들지만 물리 공간을 하나로 공유

=> 시간이 지날수록 단편화에 의해서 공유률이 저하됨


d. MaxRequestsPerChild



(12) MySQL 튜닝


a. 서버측

- mysqld 파라미터 튜닝

: 메모리, 디스크 I/O 관련 파라미터

(디스크 I/O와 관련한 커널파라미터, 적절한 f/s선택과 mount 옵션들)

- 파티셔닝

: 데이터를 primary key등을 기반을 분할하여 DB서버와 나누기

(데이터를 작게 유지할 수 있고, 캐시에 올리기 쉬워지고, 액세스 분산의 효과가 있음

but, SQL레벨에서의 쿼리가 복잡하며 애플리케이션 측의 부담이 증가)


b. 서버측 이외

- 데이블설계(인덱스, 의도적 비정규화)

- SQL 최적화 (인덱스사용, 테이블결합 순서 및 방법 조정)


c. 주변 시스템 튜닝

- 클라이언트와 DB 서버사이에 memcached같은 캐시서버 놓기



(13) 메모리 관련 파라미터 튜닝 (MySQL)

튜닝의 포인트

참고로 특정 DB 서버(실메모리 4기가)의 실제 설정값


a. 버퍼의 종류 

- global buffer : mysql에서 내부적으로 하나만 확보되는 버퍼

- thread buffer : 커넥션(스레드)별로 확보되는 버퍼


b. 지나친 할당 주의

: 버퍼에 많은 메모리를 할당하면 좋지만 over되면 swapping되므로 성능저하


tip! 

MyISAM 테이블은 MySQL레벨의 파라미터 튜닝보다는, MyISAM의 데이터파일이 OS의 디스크캐시에 오르도록 조정하는 게 좋음


c. 메모리 관련 파라미터


- innodb_buffer_pool_size

: InnoDB 데이터나 인덱스를 캐시하기 위한 메모리 영역(G-buffer)


- innodb_addtitinal_mem_pool_size

: InnoDB의 내부데이터 등을 저장하기 위한 메모리 영역

(크게는 안해도 됨, 어차피 부족하면 에러나서 그때 수정하면 됨)


- innodb_log_buffer_size

: InnoDB의 갱신로그를 기록하는 메모리 영역

(버퍼는 트랜젝션이 commit되거나, 매초 disk로 flush 되므로 다른 파라미터를 더 크게 하는게 좋음)


- innodb_log_file_size

: 갱신로그를 기록하는 디스크상의 파일 (튜닝에 있어서 중요!!)


1MB < innodb_log_file_size < MAX_innodb_log_file < 4GB(32비트 기준) 


MAX_innodb_log_size = innodb_buffer_pool_size / innodb_log_files_in_group


innodb_log_file_size가 클수록 crash recovery 시간이 오래걸림


- sort_buffer_size : ORDER BY나 GROUP BY에 사용되는 메모리 영역(T-buffer)


- read_rnd_buffer_size : 정렬부에 레코드를 읽을 때 사용되는 메모리 영역

=> 디스크 I/O가 줄어들기 때문에 ORDER BY의 성능을 증가시킴(T-buffer)


- join_buffer_size : 인덱스를 사용하지 않는 테이블 결합시 사용되는 메모리영역

=> 매 초에 인덱스를 사용하지 않는 결합은 피해야함

(즉, 크기를 크게하지 말자)


- read_buffer_size : MyISAM의 키(index)를 메모 상에 캐시하는 영역

=> global buffer로 클수록 좋음. MyISAM을 많이 사용하면 크게!


- myisam_sort_buffer_size : MyISAM REPAIR TABLE, CREATE INDEX, ALTER INDEX의 경우 인덱스 정렬에 사용하는 메모리 영역

=> 통상 DML쿼리에서 사용되는 것이 아니므로 크게는 안해도됨


(14) Nagios

: 이상, 에러감시


- ping

- TCP 접속에 의한 각종 서비스 감시

- SNMP에 의한 호스트 상태 감시


<응용>

- 가동률 측정

- 독자적인 플러그인(MySQL리플리카 감시)

MySQL 프로세스 수 감시, memcached  감시 등


<구현방법>

- NRPE(Nagios Remote Plugin Executor)를 이용한 방법

- SNMP 이용방법

- 독자플러그인 이용방법



(15) Ganglia  서버 리소스 모니터링


- CPU 사용률

- 메모리 사용률

- Load Average

- 네트워크 트래픽



(16) Puppet 서버 관리 툴


- 신규서버 투입

- 기존 서버 설정 변경




(17) daemontools

: 데몬 가동 관리


background로 실행안됨. foregound로 전한하기 위한 daemontools에 포함된 fghack을 사용



(18) PXE, initramfs

: 네트워크 부트 동작


*initpramfs

: 커널이 루트 파일시스템을 마운트하고 init을 실행하기 전에 커널의 외부에서 밖에 수행할 수 없는 초기화를 하기 위한 도구

- 커널이 루트 파일 시스템을 마운트 할 때 필요한 드라이버 모듈을 커널에 로드해줌

- 필요한 파일을 모아서 cpio로 정의 후 gzip으로 압축한 파일

- 부트로더가 커널을 메모리에 읽을 때 커널과 함께 메모리에 로드됨

- Diskless system

- NFS나 메모리 파일시스템에 루트 파일시스템을 두고 diskless system 구현이 가능 (서버고장발생 감소)


* PXE(Pre-eXecution Enjoinment)

- BIOS 초기화, 확장 BIOS 스캔 후 PXE BIOS 등록

- PXE라 부팅 바이오스로 선택, 제어권이 넘어옴

- PXE BIOS가 DHCP를 사용하여 IP통신 준비, 파일버서구조와 부트로더 파일명을 얻어옴

- 파일서버로 부트로더를 얻어서 실행한 후 제어권을 넘김

- 부트로더 실행, 파일서버로부터 부트로더 자신의 설정 파일 얻기

(파일 서버의 주소는 PXE BIOS로부터 부트로더로 통지)

- 부트로더는 실행할 커널과 설정파일에 지정되어있다면 initramfs의 파일을 파일서버로부터 얻어서 메모리상에 올린 후 커널에 제어권을 넘김


note. PXE BIOS가 서버로부터 파일을 얻기위해 TFTP사용

=> Trivial File Transper Protocol, UDP 기반


<필요항목>

- PXE를 지원하는 NIC, DHCP서버, TFTP서버

- PXE에 맞는 부트로더, 커널, initramfs라는 루트파일시스템을 초기화하는 시스템, 루트파일시스템 



(19) 원격관리


관리회선

시리얼콘솔

IPMI, Intelligent Platform Management Interface

=> 하드웨어 구현(free 버전도 있음)

Magic SysRq

WatchDog 타이머

Kdump

...



(20) 웹서버 로그관리


- Syslog : 유닉스 계열 OS에서 로그 수집

- Syslog-ng






[서버/인프라를 지탱하는 기술]





'Network/Infra' 카테고리의 다른 글

스토리지 서버의 다중화  (0) 2015.12.28
DNS 다중화  (0) 2015.12.28
스토리지 서버의 필요성  (0) 2015.12.28
MySQL Replication  (0) 2015.12.28
UTM, VoIP  (0) 2015.12.27

+ Recent posts