VPS에서 CentOS 7을 실행하고 있으며 특정 포트의 대역폭을 제한하고 싶습니다. 나는 광범위하게 조사했고 내가 찾을 수 있는 해결책은 인터페이스에 대한 제한 사항이거나 CentOS 6에서만 시도된 것처럼 보이는 iptable 설정이 모호하게 설명되어 있다는 것입니다.
제 경우에는 Shadowsocks(프록시 애플리케이션) 서버 측이 포트 1080
및 1081
. 무제한 대역폭을 허용하고 싶지만 대역폭을 약 1MBps로 제한하고 싶습니다. 프록시 애플리케이션이므로 인바운드 및 아웃바운드 트래픽이 대략 동일합니다. 이는 3개의 포트에서 수신 대기하는 Shadowsocks의 단일 인스턴스입니다.1082
eth0
1080
1081
1082
아니요3개의 인스턴스는 각각 1개의 포트를 수신하므로 프로세스별 대역폭 제한이 적용되지 않습니다.
하지만 그 외에는 즉시 사용 가능한 CentOS 지원이든 일종의 중간 모니터링 계층이든 관계없이 모든 솔루션을 고려할 수 있습니다. 일이 완료되는 한 나는 기꺼이 그 일을 할 것입니다.
미리 감사드립니다.
답변1
다음 방법을 통해서만 트래픽을 제한할 수 있습니다.리눅스 흐름 제어.
다시 한번 확인하기 위해,섀도우 양말한쪽이 SOCKS5 프록시 역할을 하는 터널을 생성합니다(sslocal
, 나는 이것이 주어진 포트가 주어진 OP의 서버에서 실행되고 있다고 가정하고 있으며 원격 끝점과 통신합니다(ssserver
) 자체적으로 실제 대상 서버와 통신합니다. Shadowsocks는 SOCKS5 UDP ASSOCIATE를 처리한 다음 (SOCKS5) TCP 포트와 동일한 포트에서 (SOCKS5) UDP를 사용합니다.
이 솔루션은 TCP와 UDP 모두에 대해 있는 그대로 작동하지만 (참고 1 참조) UDP는 추가 문제를 나타낼 수 있습니다. 소스가 "MTU보다 큰" 크기의 UDP 패킷을 생성하는 경우(아마도 선량하게 동작하는 클라이언트에서는 사용해서는 안 됨) 또는 서버) 조각화됩니다.TC,효율적인보다 일찍웹 필터존재하다입구그리고 그보다 나중에웹 필터존재하다출구, 조각이 표시됩니다. UDP 포트는 조각으로 사용할 수 없으므로 필터가 이를 포착할 수 없으며 제한이 거의 발생하지 않습니다. 자연스럽게 MTU를 사용하여 패킷 크기를 제한하고 어쨌든 경로 MTU 검색을 수행하는 TCP는 대부분의 설정에서 이 문제가 발생하지 않습니다.
다음은 패킷 스트림의 ASCII 그림입니다(전체 그림은 일반적으로 두 개의 스트림(에이전트 왼쪽과 오른쪽에 하나씩)을 발생시키는 클라이언트 활동을 나타냅니다).
traffic controlled TCP self-adjusting / no UDP control
-------------> <-------------
/ \ / \
clients | | proxy | | remote ====== real servers
\ / (sslocal) \ / (ssserver)
<------------- ------------->
traffic controlled already rate limited
원격 서버 트래픽에 대해 필요하거나 걱정할 필요가 없습니다.
- 물론 프록시에서 원격 서버로 나가는 것은 클라이언트의 수신에 의해 제한됩니다.
- 원격/서버에서 프록시 전달
- TCP는 일반적으로 클라이언트 트래픽처럼 조정하고 작동합니다.
- UDP에는 애플리케이션 프로토콜이 이를 수행할 수 없는 한 이러한 가능성이 없습니다. 예: 단순 UDP를 통한 두 개의 비디오 소스가 서버 측에서 도착하고 클라이언트 제한을 초과하는 경우 두 클라이언트 스트림이 모두 손상될 수 있습니다. 대역폭을 줄이기 위한 애플리케이션 피드백이 있어야 하며 이는 이 범위를 벗어납니다.
그럼에도 불구하고 원격/서버 측 트래픽을 클라이언트에 연결하기 위해 Shadowsock 내에서 변경이 필요할 수 있으며 더 복잡해질 것입니다.TC용법.
데이터만 전송하는 SOCKS5 클라이언트의 경우 한도는입구데이터만 수신하는 SOCKS5 클라이언트의 경우 대역폭을 제한해야 합니다.출구대역폭을 제한해야 합니다. 사용되는 애플리케이션이 잘 알려져 있지 않는 한 두 방법 모두 트래픽 제어를 받아야 합니다.
교통 통제는 제가 거의 다루기 힘든 복잡한 주제입니다. 두 가지 답변을 드리겠습니다. 단순한 정책(과잉 데이터 삭제)과 셰이핑(삭제되기 전 지연 포함)을 수행하고 IFB 인터페이스를 사용하여 다음 제한 사항을 해결하는 더 복잡한 답변입니다.입구.
개념과 Linux 구현을 이해하려면 다음 문서를 읽어야 합니다.
http://www.tldp.org/HOWTO/Traffic-Control-HOWTO/
또한 쉘 스크립트에서 구현된 이 명령은(그리고 이 답변에 있는 것과 유사한 메커니즘을 사용하여) 다음과 같은 놀라운 결과를 제공합니다.
https://github.com/magnific0/wondershaper
단순한
ㅏ경찰작업은 포트와 일치하는 초과 패킷을 삭제하는 데 사용됩니다(대략적인 접근 방식임). 그것은 일반적으로 사용됩니다입구하지만 다음에 적용됩니다출구또한. 트래픽은 속도가 제한되어 있지만 속도가 제한된 다양한 클라이언트 간에 변동 및 불공평한 공유가 있을 수 있습니다(특히 UDP와 TCP가 관련된 경우).
출구(나가는 패킷)
가장 단순한큐 디스크추가 필터 허용 예프리오 큐 디스크, 특정 기능은 실제로 사용되지 않습니다.
tc qdisc add dev eth0 root handle 1: prio
TCP 및 UDP에 대한 필터링은 각 포트("소스 포트"를 의미)에 대해 다음 필터(8mbits/s <=> 1MBytes/s)를 추가하여 간단히
u16 at 0 layer transport
수행됩니다 (참고 2 참조) .tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081)' action police rate 8mibit burst 256k tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
제가 잘못 이해한 경우를 대비해 1081과 1082는 하나의 공통 제한만 가져야 합니다. 위의 두 제한 대신 이를 사용하여 동일한 작업으로 그룹화합니다(사용하기 쉽습니다).기초적인/전자 매칭필터), 단일 토큰 버킷에서 처리됩니다.
tc filter add dev eth0 parent 1: protocol ip basic match 'cmp(u16 at 0 layer transport eq 1081) or cmp(u16 at 0 layer transport eq 1082)' action police rate 8mibit burst 256k
수신(수신 패킷)
입구비교하다출구(할 수 없다형성), 그러나 어떤 경우에도 간단한 경우에는 수행되지 않습니다. 이를 사용하려면
ingress
qdisc를 추가하기만 하면 됩니다 (참고 3 참조) .tc qdisc add dev eth0 ingress
해당 필터(
u16 at 2 layer transport
"대상 포트"를 의미):tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action police rate 8mibit burst 256k tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
또는 위의 두 가지 대신 단일 제한의 경우:
tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081) or cmp(u16 at 2 layer transport eq 1082)' action police rate 8mibit burst 256k
클린텍
출구,입구또는 두 설정을 모두 아래의 개선된 버전으로 대체할 수 있습니다. 이전 설정을 먼저 지워야 합니다.
이전에 적용된 TC 설정을 제거하려면 간단히 삭제하세요.뿌리그리고입구 큐 디스크. 그 아래의 모든 항목(필터 포함)도 제거됩니다. 기본 인터페이스 루트 디렉터리큐 디스크예약된 핸들 0: 다시 배치됩니다.
tc qdisc del dev eth0 root
tc qdisc del dev eth0 ingress
보다 복잡한 설정을 위해 qdisc와 유사한 IFB 인터페이스를 사용하십시오.
어떤 것의 목적을 가리킨다.형성이는 패킷이 삭제되기 전에 지연되어 전반적인 결과가 향상됩니다.계층적 토큰 버킷(HTB), 대역폭을 처리할 클래스 qdisc가 있고 그 아래에는 무작위 공정 큐(SFQ)는 클라이언트가 제한된 대역폭 내에서 경쟁할 때 공정성을 향상시킵니다.
출구
다음 설정을 설명하는 ASCII 이미지는 다음과 같습니다.
root 1: HTB classful qdisc | / | \ / | \ / | \ / | \ / 1:20 1:30 HTB classes / 8mibit 8mibit / | \ / | \ / 20: 30: / SFQ SFQ still 1: default port port incl. port 1080 1081 1082
제한된 대역폭은 추가로 사용 가능한 트래픽을 차용하지 않습니다(OP에서 요청하지 않음). 이것이 바로 "사용 가능한 전체 대역폭" 기본 범주의 하위 클래스가 아닌 이유입니다. 포트 1080을 포함한 나머지 기본 트래픽은 특별한 처리 없이 1:에 그대로 유지됩니다. 클래스가 사용 가능한 대역폭을 빌릴 수 있는 다양한 설정에서 이러한 클래스는 빌릴 대상을 알 수 있도록 속도가 사용 가능한 최대 대역폭의 정확한 값으로 설정된 상위 클래스 아래에 배치되어야 합니다. 따라서 각 상황에 맞게 구성을 미세 조정해야 합니다. 나는 그것을 간단하게 유지합니다.
htb에는 qdisc 클래스가 있습니다.
tc qdisc add dev eth0 root handle 1: htb
htb 클래스, 첨부된 sfq 및 이를 가리키는 필터:
tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit tc class add dev eth0 parent 1: classid 1:30 htb rate 8mibit tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10 tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10 tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20 tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:30
또는 위의 6개 명령 대신 단일 제한의 경우:
tc class add dev eth0 parent 1: classid 1:20 htb rate 8mibit tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10 tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1081)' flowid 1:20 tc filter add dev eth0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 0 layer transport eq 1082)' flowid 1:20
입구
입구qdisc는 다음과 함께 사용할 수 없습니다.형성(예: 지연 패킷) 간단한 경우처럼 필터를 사용하여 삭제합니다. 더 나은 제어를 위한 요령은 다음과 같습니다.중간 기능 블록, 인공적인 것 같아요출구인터페이스는 어디에 있나요?입구교통은 괜찮습니다리디렉션필터를 사용하지만 나머지 네트워크 스택과의 상호 작용은 거의 없습니다. 일단 자리를 잡으면,출구들어오는 트래픽의 실제 제어가 수신 시스템에 있지 않다는 점을 고려하면 일부 기능이 항상 도움이 되지 않더라도 특정 기능을 여기에 적용할 수 있습니다. 그래서 여기에서
ifb0
인터페이스를 설정 하고 위의 내용을 복사했습니다(출구) 일종의 수신 형성이 단순한 치안보다 더 나은 성능을 발휘하도록 설정합니다.만들다만약 b0 (참고 4 참조) 이전과 동일한 설정을 적용합니다.출구:
ip link add name ifb0 type ifb 2>/dev/null || : ip link set dev ifb0 up tc qdisc add dev ifb0 root handle 1: htb
클래스와 필터를 가리킵니다.
tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit tc class add dev ifb0 parent 1: classid 1:30 htb rate 8mibit tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10 tc qdisc add dev ifb0 parent 1:30 handle 30: sfq perturb 10 tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20 tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:30
또는 단일 제한의 경우 위의 6개 명령을 사용하는 경우:
tc class add dev ifb0 parent 1: classid 1:20 htb rate 8mibit tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10 tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1081)' flowid 1:20 tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match 'cmp(u16 at 2 layer transport eq 1082)' flowid 1:20
다음에서 리디렉션됨이더넷 0~의입구도착하다만약 b0 출구다음이 수행됩니다. 최적화를 위해 모든 트래픽 대신 예상되는 포트만 리디렉션하십시오. 실제 필터링 및 형성은 위에서 수행됩니다.만약 b0그래도.
tc qdisc add dev eth0 ingress tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0 tc filter add dev eth0 ingress protocol ip basic match 'cmp(u16 at 2 layer transport eq 1081)' action mirred egress redirect dev ifb0
노트:
1. 일부 네트워크 네임스페이스를 사용하여 Debian 10/kernel 5.3에서 테스트되었습니다. 명령 구문은 CentOS 7.6 컨테이너/커널 5.3(3.10 아님)에서도 테스트되었습니다 .
2. u32 match ip sport 1081 0xffff
소스 포트 1081을 일치시키는 데 사용되었을 수 있습니다. 그러나 IP 옵션의 존재를 처리할 수는 없습니다. u32 match tcp src 1081 0xffff
처리할 수 있지만 실제로는 복잡한 사용이 필요함삼 u32필터에 대한 설명은 아래에 있습니다매뉴얼 페이지. 그래서 basic match
결국 선택했어요.
3. 지정 여부에 관계없이 ingress
예약된 핸들 ffff:
(지정된 핸들 값은 무시됨)이 있으므로 지정하지 않는 것이 좋습니다. 참조 수신 은 내가 선택한 parent ffff:
그냥 으로 대체될 수 있습니다 .ingress
4. IFB 인터페이스가 처음 생성되면 ifb 모듈이 로드되고 기본적으로 자동으로 생성됩니다.만약 b0그리고만약 b1초기 네임스페이스의 인터페이스는 실제로 명령의 결과로 생성되었지만 인터페이스 이름 ifb0을 묻는 경우 오류가 발생합니다. 동시에 모듈만 로드하면 인터페이스가 네트워크 네임스페이스(예: 컨테이너)에 표시되지 않으므로 인터페이스가 여전히 필요합니다. 따라서 추가하면 2>/dev/null || :
두 경우 모두를 해결할 수 있습니다. 물론 실제로 IFB 지원이 가능하다고 가정한다.