_______. _______.___ ___ .______ ____ ____ _______ .______
/ | / | / / | _ / / | ____|| _
| (----` | (----` V / | |_) | / / | |__ | |_) |
> < | / / | __| | /
.----) | .----) | / . | | ----. / | |____ | | ----.
|_______/ |_______/ /__/ __ | _| `._____| __/ |_______|| _| `._____|
SSXRVER는 Linux 플랫폼에서 실행되는 고성능 고성능 네트워크 라이브러리입니다. C ++ 17로 작성되었으며 TCP 및 UDP 프로토콜을 지원합니다.
나와 동일한 개발 환경을 일치 시키십시오. 데이터베이스 모듈이 필요하지 않은 경우 cmakelists.txt를 수정하십시오.
cmake 설치
# debian/ubuntu
sudo apt-get install cmake라이브러리 설치 부스트
wget http://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2
tar -xvf boost_1_72_0.tar.bz2
cd ./boost_1_72_0
./bootstrap.sh --prefix=/usr/local
sudo ./b2 install --with=allrun ./build.sh ssxrver 디렉토리에서 build.sh를 수정할 수 있습니다. 디버그 버전 또는 릴리스 버전 (기본 릴리스 버전)을 생성하도록 선택할 수 있습니다.
./build.sh컴파일 된 것은 성공적으로 빌드/ 디렉토리를 생성하고 실행 파일은 해당 버전 디렉토리에 있습니다. 예를 들어, 릴리스 버전을 선택하면 실행 파일이/build/release/ssxrver입니다.
conf/ssxrver.json.example의 형식을 모방하여 구성 파일을 만듭니다 (구성 파일은 주석이없고 주석이없고 주석이 없음). 아래 각 구성 파일의 옵션을 설명하겠습니다. 실제로 많은 매개 변수의 기본값을 설정합니다. 구성되지 않으면 영향을 미치지 않습니다.
{
" port " : 4507, # 端口号,不填的话默认4507
" address " : " 127.0.0.1 " , # 绑定的地址
" worker_processes " : 4, # IO 线程数量,不填默认为 4 个
" worker_connections " : -1, # 一个 IO 线程最多支持多少连接, -1 表示最多能创建多少就创建多少,不做限制
" task_processes " : 0, # 任务线程,不填的话默认为 0
" cpu_affinity " : " off " , # cpu 亲和度 ,默认关闭
" http " : { # http 模块
" max_body_size " : 67108864, # 单个 http 包最大支持大小
" root_path " : " /home/randylambert/sunshouxun/ssxrver/html/ " # 文件访问根路径
},
" log " : { # log 模块
" level " : " INFO " , # 输出等级,可填三种等级, DEBUG,INFO,WARN 不填默认为 INFO 等级
" ansync_started " : " off " , # 是否打开异步日志线程,不填默认关闭
" flush_second " : 3, # 异步线程每隔多久持久化一次
" roll_size " : 67108864, # 日志文件滚动大小
" path " : " /home/randylambert/sunshouxun/ssxrver/logs/ " , # 日志文件存放路径
" base_name " : " ssxrver " # 日志文件基础名
},
" mysql " : { # 数据库模块
" mysql_started " : " off " , # 是否打开数据库模块,默认关闭
" address " : " 127.0.0.1 " , # 以下是对应数据库连接信息
" user " : " root " ,
" password " : " 123456 " ,
" database_name " : " ttms " ,
" port " : 0,
" unix_socket " : null,
" client_flag " : 0
},
" blocks_ip " : [ " 122.0.0.2 " , " 198.1.2.33 " ] # 可屏蔽部分恶意 IP
}실행 파일을 실행하십시오.
./ssxrver -f /配置文件的路径
# 例如
./build/Release/ssxrver -f ./conf/ssxrver.json| 테스트 환경 | 값 |
|---|---|
| 운영 체제 헤어 스타일 버전 | Deepin V20.1 Community Edition (1030) |
| 커널 버전 | 5.4.70-AMD64-DESKTOP (64 비트) |
| 컴파일러 버전 | GCC 8.3 |
| 도서관 버전을 부스트하십시오 | 1.72 |
| 프로세서 | 인텔 (R) 코어 (TM) i7-8750H CPU @2.20GHz |
| L1 캐시 크기 | 32k |
| L2 캐시 크기 | 256K |
| L3 캐시 크기 | 9216K |
| 하드 디스크 속도 | 1.8 TIB 기계식 하드 드라이브 5400 rpm |
| 하드 디스크 읽기 및 쓰기 속도 | 3.03 초의 370MB = 122.27 MB/SEC |
| 메모리 | 7.6GB |
| 파티션을 바꾸십시오 | 4.7GB |
| 논리적 코어 수 | 12 코어 |
변수를 제어하려면 테스트 전에 컴퓨터를 다시 시작하여 테스트 환경에 CPU 부하가 높은 다른 응용 프로그램이 없도록하십시오.
테스트 도구는 WebBench1.5입니다. 첫 번째 워밍업 데이터를 제거하십시오. 테스트 명령은 다음과 같습니다 (100 명의 클라이언트가 15 초 동안 지속적으로 액세스했습니다).
./webbench -c 100 -t 15 http://127.0.0.1:8081/테스트 객체는 Apache/2.4.38, Nginx/1.14.2, SSXRVer입니다.
참고 : Webbench 또는 AB를 사용하든이 압력 측정 도구로 측정 된 데이터는 간단한 참조로만 사용할 수 있습니다. 압력 측정은 단순히 명령을 실행하는 대신 만능 및 다중 방해가 필요한 테스트입니다. 압력 측정 중에도 데이터는 네트워크를 통해 전혀 전송되지 않고 커널로 돌아갑니다.
| 네트워크 라이브러리 | 속도 (페이지/분) | 성공률을 요청합니다 |
|---|---|---|
| ssxrver는 메모리에서 생성 된 응답을 반환합니다 | 7107414 | 100% |
| ssxrver는 정적 파일을 반환합니다 | 5114376 | 100% |
| 아파치/2.4.28 | 2884072 | 100% |
| nginx/1.14.2 | 4728748 | 100% |
SSXRVer의 테스트 결과는 꽤 좋지만 이상하게도 데이터가 더 높아질 것이라고 생각했습니다. 초기에 개발 될 때 그 당시에는 많은 최적화를하지 않았기 때문입니다. 메모리에서 직접 생성 된 응답을 반환하면 최대 8000000 페이지/분에 가깝게 측정되었습니다 (8000000 페이지/분의 테스트 결과는 스크린 샷에서 촬영되지 않았으며 7550778을 남겼습니다). 당시 Nginx/1.14.2는 최대 5000000 페이지/분을 가졌습니다. 그러나 SSXRVER 또는 NGINX/1.14.2인지 여부에 관계없이 높은 값을 찾을 수 없었습니다. 나는 그 이유가 무엇인지 모르겠습니다. 최종 결과에서 큰 차이가 발생했습니다 (내 컴퓨터가 노화되어 있기 때문에?  ̄ □  ̄||)
현재 시간이 있으면 개인적으로 SSXRVER의 버퍼 모듈과 로그 모듈을 수정합니다.
우선, 버퍼 모듈을 수정하는 가장 쉬운 방법은이를 순환 버퍼로 변경하여 버퍼가 데이터를 전진시키는 횟수를 효과적으로 줄이거 나이 버퍼 구현을 직접 포기하고 고성능 버퍼를 다시 이식하는 것입니다.
둘째, 현재 로그 모듈은 C ++의 스트림 형태로 기록됩니다. ioStream과 함께 C ++를 직접 사용하는 것보다 성능이 확실히 높지만 << Symbolic Form에서 로그를 과부하 시키면 여전히 기능 통화 체인으로 인한 불편한 형식 제어 및 성능 문제가 발생합니다. 이 두 가지 문제는 printf 형태로 로그를 구현하여 해결할 수 있습니다.
시간의 이유로 인해 SSXRVer는 메모리 관리 모듈을 구현하지 않으므로 일반적인 고성능 메모리 관리 모듈을 작성하는 것은 거의 불가능합니다 (Jemalloc 또는 TCMalloc로 직접 이동하는 것이 좋습니다). 그러나 네트워크 라이브러리 시나리오를 분석 함으로써이 시나리오에서 더 높은 성능을 가진 메모리 관리 모듈을 작성할 수있는 기회는 거의 없습니다. 시간이 있다면 Nginx의 구현을 살펴보고 배울 것입니다.
정보를 쿼리 할 때 C ++ 17에서는 std :: string_view를 사용하여 Const String &를 대체 할 수 있다는 결론을 내 렸습니다. 따라서 Const String & 내 프로젝트의 모든 장소를 std :: string_view로 교체하려고 노력했습니다. 그러나 마침내 perf -top 사용하여 변경된 하중을 보았을 때 STD :: String_View를 사용한 후 일부 기능이 실제로 증가한다는 것을 예기치 않게 발견했습니다. 왜이 상황이 발생했는지 매우 당황했습니다. 시간의 이유로 인해 당분간이 문제의 특정 원인을 조사하지 않을 것입니다. 특정 이유를 확인하기 위해 기본 구현을 확인할 기회가 있습니다.
HTTP 구문 분석 모듈을 구현할 때 첫 번째 버전의 문자열과 직접 일치하는 필기 상태 머신을 사용했습니다. 그런 다음 Ragel이 구현 한 상태 기계로 교체했습니다. 그러나 최근 테스트에서 HTTP 구문 분석 기능의 부하가 매우 과장되어 10%에 도달했습니다. Ragel을 사용하면 성능 저하가 발생했을 수 있습니까? (헤더를 구문 분석하면 시스템 부하가 높은 경우 HTTP/2.0은 여전히 성능을 크게 향상시킬 것으로 보입니다.) 불행히도 State Machine을 필기 한 경우 해당 구문 분석 기능의 부하를 테스트하지 않았습니다. 이제 두 사람 간의 데이터 비교를 한 번에 얻을 수 없으며 벤치 마크 테스트를 작성할 기회가 있습니다.
SSXRVER는 간단한 UDP 전송을 지원하지만 개인적으로 정체 제어, 트래픽 제어 및 패킷 손실 재전송 기능이없는 UDP 프레임 워크는 기본적으로 정상적으로 사용할 수 없다고 말할 수 있다고 생각합니다. 앞으로 Quic과 KCP 프로토콜을 배울 시간이 있습니다. UDP 관련 지식을 보완 할 것입니다. 더 효율적이고 유연한 UDP 프로토콜이 미래에 점점 더 널리 사용될 것이라고 생각합니다!
실제로, 현재 최고의 네트워크 프레임 워크는 포트 멀티플렉싱 주소 다중 스레드 (다중 프로세스)가 동일한 주소와 포트를 바인딩하고 커널이 자동으로 수락로드 밸런싱을 수행한다는 것입니다. 동시에 Coroutine Framework + Hook를 통해 블록 시스템 호출을 블록합니다. 이 프레임 워크를 사용한 후에는 기본 스레드를 사용하여 연결을 분배하지 않고 고성능을 보장 할 수 있으며 비동기 콜백 지옥에 빠질 필요가 없습니다.
또한 Linux 커널 5.1 이후에 추가 된 비동기 IO 메커니즘 io_uring을 사용할 수 있다면 서버의 성능이 더 높아질 것이라고 생각합니다. 그러나 현재 io_uring에 대해 많이 알지 못하며 IO_URING을 기반으로 비동기 IO 네트워크 라이브러리를 설계 할 수있는 기능이 없습니다.