[![logo](https://www.hongsnet.net/images/logo.gif)](https://www.hongsnet.net)

# Issue

- OO 서비스의 빈번한 일시적 접속 지연 발생에 따른 **Risk Management 상황** 발생
  - 개발 부서 의 분석결과, **Page Cached 영역** 사용 부족에 따른 긴급 증설 요청 의견
    - 접속 지연 이상징후 발생 시 프로세스 재기동 수행 후 해소 (근본원인파악 X)
  - 운용 부서 의 분석결과, 메모리는 30% 정도 여유가 있는 상태이고, SWAP 은 어플리케이션의 특성이라는 의견
    - SWAP 영역의 지속적 상승 유지에 따른 서비스 접속지연 발생의 근본 원인 분석
- <u>개발 / 운용 부서와의 의견충돌이 발생</u> 되고 있으며, 이를 객관화하기 위한 `세부 의미있는 데이터`는 미존재
  - 아래 그래프 최근 3 개월 기준으로는 개발 부서에서 메모리 용량부족 의견에 부합되지 않음

![issue](./images/04p_23-02-16_custom.png)


# Analysis

- OO 서비스는 **Linux Page Cache 영역을 공유 메모리로 사용**
- Linux Kernel은 메모리 가용량에 대해 Page Cache 로 활용하려는 메커니즘
- 실질 시스템 메모리 가용량이 있는 것인지, 부족한 것인지에 대한 일반적인 기술 Based 접근 시 충돌 불가피
  - Linux 는 메모리 가용량에 대해 Page Cache 로 활용“, “OO 서비스 프로세스는 Pag e Cache 일부를 사용
- OO 서비스의 시스템 메모리 `상세 현황`이 없는 상태 (**신속한 모니터링 아이템 발굴 필요**)
  - 분석 결과에 대한 객관성 타당성 부족


# Solution

- **시스템 메모리** 사용 현황의 객관성 및 타당성을 위한 **모니터링 아이템** 발굴 및 긴급 적용 진행 (총 12 대)
- 아이템 발굴 내역
  - Page Cache, Free Memory(Allocable immediately), Avail Memory(free + buffers + cached)
  - Mapped, Dirty, Active(anon, file), Inactive(anon, file), Writeback , OO 서비스 프로세스 공유메모리 사용량
  - Slab, KernelStack , Reclaim
  - Swapping, SwapCache
- 신규 모니터링 아이템 발굴에 따른 `운용 조직 내 수평 전파` 필요 (완료)

# Result

- **개발 운용 부서의 Linux 시스템 기반 서비스 에 대한 메모리 사용의 구조 파악에 일조**
   - **Page Cache** 영역의 사용은 `mmap 시스템콜에 따른 파일 매핑 영역` 메모리 증설이 일부 필요한 이유가 검증됨
   - **Active(anon)** 메모리 영역은 줄어들지 않고, 상승만 되는 구조 (`Memory Leak` 의심되며, 개발부서 인지됨)
   - Swap 영역 의 지속적 상승 이유는 메모리 증설필요와 연관되며, Memory Leak 해결 시 서비스 안정성 강화 기대
- 기술 일반적 관점에서 이를 `객관화 사실화 하는 것이 얼마나 중요한지를 다시 한번 느끼는 계기가 됨`


## Shared Memory

> 서버 내 프로세스가 공유할 때 주로 사용되는 shm, ipc(sysv), cache 사용내역에 대한 모니터링을 위해서 수집이 필요하다. 참고적으로 아래의 `cached_memory` 영역은 이번 이슈의 특성(프로세스 구조)으로 그래프화 되었으며, mapped와 같이 공유 메모리의 영역이 반드시 정해진 것은 아니기 때문에 더욱 더 필요하다.

![mem-shm](./images/03p_shm.png)

 - cached_memory: Skip (아래 Memory Extension의 cached memory 같음)
 - shm_memory: 커널이 공유메모리로 할당받은 용량이다. 여기에는 `SHM, IPC(Sysv), RamDisk`가 해당된다.
 - sap_shm_free: Skip
 - mapped_memory: `어플리케이션이 mmap 함수를 사용`하여 System Call로 사용한 용량이다. 이를 메모리 파일 맵핑이라고 한다.


## Memory Extension

> 수치 기준으로의 사용률(량) 파악이 맞을 수도 있겠지만, 운용자 입장에서는 Pagecache와 free(즉시 할당가능) 량을 주의깊게 관측할 필요가 있다. 또한 avail memory의 경우도 개발 부서에 설명이 필요할 수도 있다.

![mem-ext](./images/03p_mem_ext.png)

 - total memory: 시스템에 설치된 전체용량이다. 참고적으로 증설/감설이력에 활용하면 좋을 것이다.
 - cached memory: 커널이 메모리 가용량에 대해 PageCache로 활용된 용량이다. 다만 `공유메모리도 포함됨을 주의` 해야한다.
 - buffers memory: Block Device(xfs, ext4 등)에 버퍼 캐시량이며, 참고적으로 inode의 인덱싱 정보도 여기에 캐싱된다.
 - used memory(total - free): 수치 기준으로의 사용량
 - free memory(Allocable immediately): 커널이 **아무런 간섭없이(아래 설명 참조)**, 즉시 메모리를 할당할 수 있는 용량
 - avail memory(free+buffers+cached): 이 필드가 실질적으로 가용량이긴 하지만, 여기에 cached 필드가 있으므로, `100% 확신하면 안된다`.

> 간섭 없이란, 일반적으로 리눅스 커널은 가용량에 대해 Pagecache로 활용하는데, 이때 메모리할당요청이 발생되면 cached된 영역에서 요청량만큼 소거하고, 할당한다.


## Active/Inactive Memory

> 리눅스(커널)의 메모리는 Active/Inactive로 구분되는데 이는 기본 Page 교체 알고리즘이 LRU(오래된 페이지를 교체)이기 때문이다. 이는 반대로 Active 영역에 대해서는 프로세스를 강제로 중지하지 않는 이상 반환할 수 없음을 의미하기도 한다.

![mem-active](./images/03p_active_inactive.png)

 - Active(anon) memory usage: **최근에 사용**되어 왔고, 비파일(일반적으로 어플리케이션 메모리) 메모리이기 때문에 `강제로 반환할 수 없다`. 그리고 Swap-out(메모리 -> 디스크)`되지 않는다`.
 - Active(file) memory usage: **더 최근에 사용**되어 왔고, 파일기반의 메모리이지만, `강제로 반환할 수 없다`. 단, Swap-out(메모리 -> 디스크) `가능하다`.
 - Inactive(anon) memory usage: **예전에 사용**되어 왔고, 강제로 반환이 가능하다. Swap-out(메모리 -> 디>스크) `가능하다`.
 - Inactive(file) memory usage: **예전에 사용**되어 왔고, `아무런 영향없이` 강제(drop cache)로 반환이 가능하다.

> 이번 이슈는 Active(anon) 영역이 지속적으로 증가하기 때문에 시간이 지날수록 시스템 메모리가 부족하게 된다. 따라서 결국 Swap도 지속적으로 늘어나면서 시스템/서비스의 부하/지연이 발생되는 이슈다.


## Swapping

> Swap의 경우도 수치 기준으로의 사용률(량) 파악이 맞을 수도 있겠지만, 운용자 입장에서는 swap in/out 량을 주의깊게 관측할 필요가 있다.

![mem-swap](./images/03p_swap.png)

 - swap total: 시스템에 설치된 전체용량이다. 참고적으로 증설/감설이력에 활용하면 좋을 것이다.
 - swap free: 수치 기준으로의 가용량
 - swap in: Page가 `디스크 -> 메모리로 이동`되는 용량이다.
 - swap out: Page가 `메모리 -> 디스크로 이동`되는 용량이다.
 - swap used: 수치 기준으로의 사용량

> SWAP을 사용한다고 100% 문제가 있는 것은 아니다. 다만, swap in/out 구조가 메모리와 디스크라는 특성으로 문제가 되는 것이다. 즉, 메모리와 디스크의 속도차이는 대략 20배 이상인 것으로 알려져 있기 때문에 자주 Swapping되면, 지연(Latency)이 발생될 수 밖에 없다.


# EXTRAS

Zabbix의 가장 큰 약점이라고 생각되는 것이 그래프 인데, 확실히 Grafana를 뛰어넘지 못한다고 보는게 일반적이다. 그래서인지 Zabbix에서는 Grafana와 연동할 수 있는 Plugin을 제공한다.

그럼 Zabbix + Grafana 연동을 통해 그래프의 아쉬움을 개선한다.


## Grafana 설치

다음과 같이 YUM Repository를 설정해야 한다.

```bash
# cat /etc/yum.repos.d/grafana.repo
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
```
설치는 다음과 같이 진행한다.

```bash
# yum install grafana
```

설정은 다음의 세 개만 주석을 해제하여 진행한다.

```bash
# /etc/grafana/grafana.ini
...중략
instance_name = ${HOSTNAME}

[server]
# Protocol (http, https, socket)
protocol = http

# The ip address to bind to, empty will bind to all interfaces
;http_addr =
http_port = 3000
```

grafana-server 데몬을 시작하고, 활성화 한다.

```bash
# systemctl start grafana-server; systemctl enable grafana-server
```

그럼 이제 http://주소:3000을 접속한 후 다음과 같이 Default 로그인정보를 입력하는데, 최초 기본 로그인 정보는 "admin:admin" 이다.



## Zabbix + Grafana 연동

1. 설정 -> Plugins 이동


2. 검색창에 zabbix 입력


3. 검색된 아이콘을 클릭한 후 Install 버튼을 클릭

설치가 완료되면, 다음과 같이 확인된다.

![grafana](./images/grafana_zabbix.png)


4. 서버에 접속하여 다음의 명령을 입력해서, Grafana의 추가 Zabbix 플러그인을 설치

```bash
# grafana-cli plugins install alexanderzobnin-zabbix-app
✔ Downloaded and extracted alexanderzobnin-zabbix-app v4.2.10 zip successfully to /var/lib/grafana/plugins/alexanderzobnin-zabbix-app
 
Please restart Grafana after installing plugins. Refer to Grafana documentation for instructions if necessary.
 
# systemctl restart grafana-server.service
```

5. Plugins 메뉴에서 다시 새로고침을 하면, Enable 버튼이 활성화되는데, 이를 클릭


6. 설정 -> Data sources -> Add data sources 클릭

![grafana_datasource](./images/grafana_zabbix_datasource.png)


7. Save & test 버튼을 클릭하여, 에러없이 출력되면 완료



## Grafana Based Memory Graphs


1. Memory Extension

![grafana_mem_ext](./images/grafana_mem_ext.png)


2. Cache Extension

![grafana_cache_ext](./images/grafana_cache_ext.png)


3. Active / Inactive Memory

![grafana_cache_ext](./images/grafana_mem_active_inactive.png)


4. Pages Extension

![grafana_pages_ext](./images/grafana_pages_ext.png)


5. Swapping Extension

![grafana_swap_ext](./images/grafana_swap_ext.png)


