콘텐츠로 이동

커널 최적화

커널 최적화는 Windows가 아닌 Linux 운영체제를 대상으로 한다. 아래 명령어는 root 권한으로 실행해야 한다.

tuned 튜닝 서비스는 튜닝 프로필을 적용해 특정 워크로드에서 더 좋은 성능을 내도록 운영체제를 조정한다.

다음 명령어로 tuned를 설치한다.

Terminal window
sudo apt install tuned

그다음 시작한다.

Terminal window
systemctl enable tuned --now

그리고 다음 명령어로 커널을 조정한다.

Terminal window
tuned-adm profile throughput-performance

/etc/sysctl.conf 파일을 열고 맨 끝에 다음 내용을 추가한다.

vm.nr_hugepages = <필요한 페이지 수>

필요한 페이지 수는 다음 공식으로 구할 수 있다.

(할당한 메모리 (단위: MB)) / 2 + 300

예를 들어 메모리를 12GB(12288 MB) 할당했다면 값은 12288 / 2 + 300 = 6444이고, 최종 설정은 다음과 같다.

vm.nr_hugepages = 6444

그다음 머신을 재부팅한다.

먼저 운영체제가 huge page를 지원하는지 확인한다.

Terminal window
cat /sys/kernel/mm/transparent_hugepage/shmem_enabled

결과에 다음 내용이 포함되어 있다면 운영체제가 transparent huge page를 지원하는 것이다.

Terminal window
always within_size advise never deny force

그다음 다음 명령어로 transparent huge page를 활성화한다.

Terminal window
echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo advise | sudo tee /sys/kernel/mm/transparent_hugepage/shmem_enabled
echo defer | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
echo 1 | sudo tee /sys/kernel/mm/transparent_hugepage/khugepaged/defrag

마지막으로 부팅 시 자동으로 적용되도록 설정한다.

Terminal window
sudo apt install sysfsutils
sudo tee /etc/sysfs.d/enableTHP.conf <<EOF
kernel/mm/transparent_hugepage/enabled=madvise
kernel/mm/transparent_hugepage/shmem_enabled=advise
kernel/mm/transparent_hugepage/defrag=defer
kernel/mm/transparent_hugepage/khugepaged/defrag=1
EOF
sudo systemctl restart sysfsutils

이제 머신을 재부팅하면 끝이다.

모든 CPU 코어가 최고 클럭으로 동작하도록 강제한다(오버클럭과 달리 CPU 수명에는 영향이 없다).

Terminal window
sudo cpupower frequency-set -g performance

XanMod Linux 커널에는 Cloudflare, Google 등에서 나왔지만 메인라인에 병합되지 않은 최적화를 비롯해 많은 최적화 패치가 들어 있다.

  1. 호환성 확인

    Terminal window
    awk -f <(wget -qO- https://dl.xanmod.org/check_x86-64_psabi.sh)

    출력 결과

    CPU supports x86-64-v4

    이 CPU는 v4를 지원한다는 것을 알 수 있다. 설치할 때 이 결과에 맞춰 고르면 된다.

  2. 업스트림 공개 키 추가

    Terminal window
    wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -vo /usr/share/keyrings/xanmod-archive-keyring.gpg
  3. 저장소 추가

    Terminal window
    echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list
    apt update
  4. 설치

    Terminal window
    apt install -y linux-xanmod-rt-x64v3

    v3는 1단계의 CPU supports 결과에 맞게 바꾸고, 마지막으로 재부팅하면 된다.

  5. 설치 확인

    재부팅 후 설치를 확인한다.

    Terminal window
    uname -r
cat <<'TEXT' > /etc/sysctl.conf
# ------ 네트워크 튜닝: 기본 ------
# TTL 설정, Linux 기본값 64
# net.ipv4.ip_default_ttl=64
# RFC 1323 참고. 켜 두어야 한다.
net.ipv4.tcp_timestamps=1
# ------ END 네트워크 튜닝: 기본 ------
# ------ 네트워크 튜닝: 커널 Backlog 큐와 버퍼 ------
# Ref: https://www.starduster.me/2020/03/02/linux-network-tuning-kernel-parameter/
# Ref: https://blog.cloudflare.com/optimizing-tcp-for-high-throughput-and-low-latency/
# Ref: https://zhuanlan.zhihu.com/p/149372947
# 아래 네 항목은 사실상 net.ipv4.tcp_rmem, net.ipv4.tcp_wmem과 중복되므로 한쪽만 설정하면 된다
# https://github.com/torvalds/linux/blob/87d6aab2389e5ce0197d8257d5f8ee965a67c4cd/net/ipv4/tcp_output.c#L241-L248
# net.core.wmem_default=1310720
# net.core.rmem_default=1310720
# net.core.rmem_max=536870912
# net.core.wmem_max=536870912
# 왼쪽부터 최솟값 기본값 최댓값
# 가능하면 실측 결과에 따라 tcp_rmem, tcp_wmem 값을 조정하자
# 직접 측정해 보니 차이는 크지 않았다. 원래 네트워크가 좋아서일 수도 있다
# 버퍼 관련 설정은 모두 메모리와 연관된다
net.ipv4.tcp_rmem=8192 262144 536870912
net.ipv4.tcp_wmem=4096 16384 536870912
net.ipv4.tcp_adv_win_scale=-2
net.ipv4.tcp_collapse_max_bytes=6291456
net.ipv4.tcp_notsent_lowat=131072
net.core.netdev_max_backlog=10240
net.ipv4.tcp_max_syn_backlog=10240
net.core.somaxconn=3276800
net.ipv4.tcp_abort_on_overflow=1
# 모든 NIC가 소프트 인터럽트 한 번에 처리하는 최대 프레임 수
net.core.netdev_budget = 600
# 흐름 제어와 혼잡 제어 튜닝
# Egress traffic control 관련. fq, cake 중 선택
# 실측상 둘의 차이는 크지 않으니 기본값 fq를 유지하면 된다
net.core.default_qdisc=fq
# Xanmod 커널 6.X는 현재 기본으로 bbr3를 쓰므로 설정할 필요 없다
# 실측상 bbr, bbr2보다 모두 나았다
# 다만 네트워크 환경에 따라 다르니, 필요하면 직접 측정하자.
# net.ipv4.tcp_congestion_control=bbr3
# 명시적 혼잡 알림(ECN)
# 혼잡이 심한 네트워크에서는 오히려 해로운 것으로 알려져 있다.
# net.ipv4.tcp_ecn=1
# TCP 윈도 스케일링
# 64KB를 넘는 TCP 윈도를 지원하려면 반드시 켜야 한다
net.ipv4.tcp_window_scaling=1
# 켜면 TCP 혼잡 윈도가 RTO 시간만큼
# 유휴 상태가 된 뒤 초기 혼잡 윈도(CWND) 크기로 초기화된다.
# 대부분의 경우, 특히 트래픽이 많은 장기 연결이라면 0으로 설정한다.
# 네트워크 상황이 수시로 크게 변하는 환경이라면 1로 설정한다.
net.ipv4.tcp_slow_start_after_idle=1
# nf_conntrack 튜닝
# Add Ref: https://gist.github.com/lixingcong/0e13b4123d29a465e364e230b2e45f60
net.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=30
net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
net.netfilter.nf_conntrack_tcp_timeout_close_wait=15
net.netfilter.nf_conntrack_tcp_timeout_established=300
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=7200
# TIME-WAIT 상태 튜닝
# Ref: http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html
# Ref: https://www.cnblogs.com/lulu/p/4149312.html
# 4.12 커널에서 완전히 폐기된 파라미터이니 켤지 말지 고민할 필요 없다
# net.ipv4.tcp_tw_recycle=0
## 클라이언트에만 적용된다. 서버가 업스트림에 연결할 때도 클라이언트로 간주된다
net.ipv4.tcp_tw_reuse=1
# 시스템이 동시에 유지하는 TIME_WAIT 소켓의 최대 수
# 이 수를 넘으면 TIME_WAIT 소켓이 즉시 정리된다
net.ipv4.tcp_max_tw_buckets=55000
# ------ END 네트워크 튜닝: 커널 Backlog 큐와 버퍼 ------
# ------ 네트워크 튜닝: 기타 ------
# Ref: https://zhuanlan.zhihu.com/p/149372947
# Ref: https://www.starduster.me/2020/03/02/linux-network-tuning-kernel-parameter/\#netipv4tcp_max_syn_backlog_netipv4tcp_syncookies
# 선택적 확인 응답(SACK) 사용
# WAN 통신이라면 켜 두어야 한다
net.ipv4.tcp_sack=1
# 전달 확인 응답(FACK) 사용
# WAN 통신이라면 켜 두어야 한다
net.ipv4.tcp_fack=1
# TCP SYN 연결 타임아웃 재전송 횟수
net.ipv4.tcp_syn_retries=3
net.ipv4.tcp_synack_retries=3
# TCP SYN 연결 타임아웃. 5로 설정하면 약 30s
net.ipv4.tcp_retries2=5
# SYN 플러드 공격 보호 사용 여부
# 주의: tcp_syncookies를 켜면 사실상 논리적인 큐 길이가 없어지고,
# Backlog 설정이 무시된다. syncookie는 현실과 타협한 결과로,
# TCP 프로토콜 설계를 크게 어기고 TCP option을 쓸 수 없게 만든다. 또 구현상
# hash 계산으로 반개방 연결 유지를 피하는 것도 만능이 아니라 일종의 tradeoff다.
# 이른바 "보안 최적화 가이드"만 믿고 생각 없이 켜지 말자
net.ipv4.tcp_syncookies=0
# Ref: https://linuxgeeks.github.io/2017/03/20/212135-Linux%E5%86%85%E6%A0%B8%E5%8F%82%E6%95%B0rp_filter/
# 역경로 필터링 사용
# Aliyun 로드 밸런서 인스턴스 뒤에 있는 ECS는 0으로 설정해야 한다
net.ipv4.conf.default.rp_filter=2
net.ipv4.conf.all.rp_filter=2
# FIN-WAIT-2 상태에 머무는 시간을 줄여 시스템이 더 많은 연결을 처리할 수 있게 한다
# Ref: https://www.cnblogs.com/kaishirenshi/p/11544874.html
net.ipv4.tcp_fin_timeout=10
# Ref: https://xwl-note.readthedocs.io/en/latest/linux/tuning.html
# 기본적으로 TCP 연결이 닫히면 그 연결의 파라미터를 dst_entry에 저장해 두고,
# dst_entry가 유효한 동안은 같은 연결을 새로 맺을 때 저장된 파라미터로 초기화한다.
# 보통은 꺼져 있고, 동시 접속이 많다면 1로 설정한다.
net.ipv4.tcp_no_metrics_save=1
# unix socket 최대 큐
net.unix.max_dgram_qlen=1024
# 라우팅 캐시 갱신 주기
net.ipv4.route.gc_timeout=100
# Ref: https://gist.github.com/lixingcong/0e13b4123d29a465e364e230b2e45f60
# MTU 탐색 사용. 경로에 ICMP 블랙홀이 있을 때 유용하다(대부분 그렇다)
net.ipv4.tcp_mtu_probing = 1
# No Ref
# 스푸핑, 소스 라우팅, 리다이렉트 패킷 기록
net.ipv4.conf.all.log_martians=1
net.ipv4.conf.default.log_martians=1
# 소스 라우팅 패킷 처리
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
# TCP KeepAlive 튜닝
# 최대 유휴 시간
net.ipv4.tcp_keepalive_time=600
# 최대 실패 횟수. 이 값을 넘으면 애플리케이션 계층에 연결 실패를 알린다
net.ipv4.tcp_keepalive_probes=3
# 탐색 패킷 전송 간격
net.ipv4.tcp_keepalive_intvl=15
# TCP 연결 요청에 대한 응답을 포기하기 전 재시도 횟수
net.ipv4.tcp_retries1 = 5
# 활성(통신이 수립된) TCP 연결을 버리기 전 재시도 횟수
net.ipv4.tcp_retries2 = 5
# 고아 소켓
net.ipv4.tcp_orphan_retries = 3
# 어떤 프로세스에도 속하지 않은 TCP 소켓을 시스템이 처리할 수 있는 최대 수
net.ipv4.tcp_max_orphans=3276800
# arp_table 캐시 제한 최적화
net.ipv4.neigh.default.gc_thresh1=128
net.ipv4.neigh.default.gc_thresh2=512
net.ipv4.neigh.default.gc_thresh3=4096
net.ipv4.neigh.default.gc_stale_time=120
net.ipv4.conf.default.arp_announce=2
net.ipv4.conf.lo.arp_announce=2
net.ipv4.conf.all.arp_announce=2
# ------ END 네트워크 튜닝: 기타 ------
# ------ 커널 튜닝 ------
# Ref: Aliyun, etc
# 커널 Panic 발생 1초 후 자동 재부팅
kernel.panic=1
# 더 많은 PID를 허용해 PID 순환 문제를 줄인다
kernel.pid_max=32768
# 커널이 허용하는 최대 공유 메모리 세그먼트 크기(bytes)
kernel.shmmax=4294967296
# 어느 시점에든 시스템에서 쓸 수 있는 공유 메모리 총량(pages)
kernel.shmall=1073741824
# 프로그램 코어 덤프 시 생성되는 파일 이름 형식
kernel.core_pattern=core_%e
# oom 발생 시 panic으로 전환
vm.panic_on_oom=1
# Linux VM이 최소한으로 남겨 둘 여유 메모리(Kbytes)
# vm.min_free_kbytes=1048576
# 100보다 크면 커널이 directory와 inode cache를 우선 회수한다
vm.vfs_cache_pressure=250
# 시스템의 스왑 경향. 값(0-100)이 높을수록 디스크 스왑이 일어나기 쉽다
vm.swappiness=10
# 10%만 시스템 cache로 사용
vm.dirty_ratio=10
vm.overcommit_memory=1
# 시스템 파일 디스크립터 제한 늘리기
# Fix error: too many open files
fs.file-max=6553560
fs.inotify.max_user_instances=8192
fs.inotify.max_user_instances=8192
# 커널이 매직 SysRq 키에 반응
kernel.sysrq=1
# 폐기됨
# net.ipv4.tcp_low_latency=1
# Ref: https://gist.github.com/lixingcong/0e13b4123d29a465e364e230b2e45f60
# 한 노드의 가용 메모리가 부족하면 다른 노드에서 메모리를 할당한다. Mongo/Redis 같은 cache 서버에 유리하다
vm.zone_reclaim_mode=0
# Ref: Unknwon
# F-RTO(TCP 재전송 타임아웃에 대한 개선된 복구 알고리즘) 사용.
# 무선 환경에서 특히 유용하다. 무선 환경의 패킷 손실은 보통 중간 라우터 혼잡이 아니라 무작위 전파 간섭 때문이다
net.ipv4.tcp_frto = 2
# TCP FastOpen
net.ipv4.tcp_fastopen = 3
# TCP 스트림에서 순서가 바뀐 데이터그램의 최대 수
net.ipv4.tcp_reordering = 300
# 켜면 재전송 시 최대 크기 패킷을 보내려 한다. 버그가 있는 일부 프린터를 위한 우회책이다
net.ipv4.tcp_retrans_collapse = 0
# 자동 corking
net.ipv4.tcp_autocorking = 1
# TCP 메모리 자동 조정
net.ipv4.tcp_moderate_rcvbuf = 1
# TSO 세그먼트 하나가 쓸 수 있는 혼잡 윈도 비율. 기본값 3
net.ipv4.tcp_tso_win_divisor = 3
# RFC1337에 설명된 TIME-WAIT Assassination Hazards in TCP 문제 수정
net.ipv4.tcp_rfc1337 = 1
# 패킷 포워딩. 보안상 Linux는 기본적으로 패킷 포워딩을 막는다
net.ipv4.ip_forward = 0
# 브로드캐스트 ICMP 패킷에 응답하지 않음
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 악의적인 ICMP 오류 메시지 보호 사용
net.ipv4.icmp_ignore_bogus_error_responses = 1
TEXT
cat <<'TEXT' > /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
* soft noproc 65535
* hard noproc 65535
root soft nofile 65535
root hard nofile 65535
root soft noproc 65535
root hard noproc 65535
TEXT
cat <<'TEXT' > /etc/security/limits.d/90-nproc.conf
* soft nproc 65535
root soft nproc 65535
TEXT

참고한 NodeSeek 가이드: