지시는 완전해 보인다——모든 VPN 클라이언트를 20 Mbit/s로 제한하라는 것. 그러나 완전하지 않고, 터널 인터페이스 위의 단일 큐 규율로는 그것을 제공할 수 없다. «클라이언트별»은 터널 주소별, 기기별, 계정별일 수 있고, 각 선택은 패킷을 다르게 분류한다. 규칙을 쓰기 전에 요구사항이 실제로 어느 것을 가리키는지 정하라.

아래의 모든 내용은 그 문장과 동작하는 무언가 사이의 거리에 관한 것이다.

«클라이언트별»이 먼저 무엇을 뜻해야 하는가

터널 주소는 분류하기 쉽고 재사용하기도 쉽다. 기기는 더 어려운데, 하나의 계정이 여러 기기를 가질 수 있고 기기 하나가 여러 주소를 가질 수 있기 때문이며, 특히 IPv6에서 그렇다. 공정성 정책에서는 계정이 가장 의미 있는 단위이고, 패킷 헤더에서 가장 찾기 어렵다. 모든 정의는 저마다의 계수 키를 함축하므로, 그 사이를 오가는 정책은 설명이 주장하는 대로 동작하지 않는다.

방향은 두 번째 빠진 단어다. 업로드, 다운로드, 합산은 세 가지 다른 요구사항이며, 한 인터페이스 위의 단일 송신 규칙 하나로 두 경로를 모두 덮는 경우는 드물다.

클라이언트가 아직 보이는 지점을 고르라

모든 방향은 인터페이스를 기준으로 정의된다. 서버 터널에서 원격 클라이언트로 나가는 것은 그 클라이언트의 다운로드로 계산되고, 클라이언트가 보내는 것은 터널로 들어간 뒤 목적지로 나간다. 각 방향마다 스케줄링 지점을 고르고 그곳에 어떤 필드가 있는지 물어라. 출발지 NAT 이전에는 업로드가 여전히 클라이언트의 내부 주소를 지니고, 변환 이후에는 단순한 출발지 일치로는 더 이상 식별하지 못할 수 있다.

암호화된 경로에서는 헤더가 VPN 전송에 속하므로, 내부 주소를 맞추는 필터에는 맞출 대상이 없다. 설계에 따라 더 일찍 분류하고 이후 스케줄러에 마크를 넘길 수 있지만, 그 인계는 의도적이어야 한다——패킷 마크, 연결 마크, 스케줄러 클래스는 서로 다른 상태이며, 하나의 값이 전달되는 것이 아니다.

버킷은 저절로 생기지 않는다

인터페이스에 붙은 토큰 버킷은 그것을 사용하는 트래픽을 형성할 뿐, 출발지 주소마다 새 버킷을 찍어 내지는 않는다. 클래스 기반 설계는 대신 선택된 트래픽을 클래스로 분류하고, 필터가 소속을 결정하며, HTB 설명서는 부모에 여유 대역폭이 있을 때 클래스의 속도와 상한을 분리한다. 의도가 엄격한 상한이라면 상한을 설정하고 차용 동작을 의도적으로 결정해야 하며, 모든 속도 수치를 절대 최댓값으로 다루지 마라.

요구사항이 클라이언트별일 때, 동시에 도는 두 전송은 하나의 할당량을 나눠야 한다. 각 흐름에 전체 속도를 주는 것은 다른 정책이며, 다운로드 하나만 지켜보는 시험은 그것도 통과한다.

기기 둘, 계정 하나, 할당량 하나?

기기 주소 둘을 따로 제한하는 것은 두 기기가 같은 사람으로 로그인하더라도 결코 계정 전체의 할당량 하나로 합쳐지지 않는다. 하나의 피어 뒤에서 변환되는 LAN 전체나, 분류기가 전혀 예상하지 못한 추가 IPv6 주소도 마찬가지다. 주소와 신원의 연결을 최신으로 유지하고, 안정적인 주소가 매핑을 단순하게 만들 뿐 소유자를 인증하지는 않는다는 점을 기억하라.

버스트와 큐 동작도 정의하라. 토큰 버킷은 평균을 넘는 짧은 버스트를 허용하고 버퍼링은 지연을 더하는데, 초과분을 단속하는 것과 나중을 위해 큐에 넣는 것은 증상이 다른 서로 다른 결정이다.

검증하려면 한 클라이언트에서 전송 두 개를 돌리고, 두 번째 클라이언트를 추가한 뒤 각 방향의 클래스 카운터를 읽어라.

관련 글