_______. _______.___ ___ .______ ____ ____ _______ .______
/ | / | / / | _ / / | ____|| _
| (----` | (----` 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 |
| Boost Library เวอร์ชัน | 1.72 |
| เครื่องประมวลผล | Intel (R) Core (TM) I7-8750H CPU @2.20GHz |
| ขนาดแคช L1 | 32K |
| ขนาดแคช L2 | 256k |
| ขนาดแคช L3 | 9216K |
| ความเร็วฮาร์ดดิสก์ | 1.8 ฮาร์ดไดรฟ์กลไก TIB 5400 รอบต่อนาที |
| ฮาร์ดดิสก์อ่านและเขียนความเร็ว | 370 MB ใน 3.03 วินาที = 122.27 MB/วินาที |
| หน่วยความจำ | 7.6GB |
| พาร์ทิชันแลกเปลี่ยน | 4.7GB |
| จำนวนแกนหลักตรรกะ | 12 คอร์ |
ในการควบคุมตัวแปรให้รีสตาร์ทคอมพิวเตอร์ก่อนการทดสอบเพื่อให้แน่ใจว่าสภาพแวดล้อมการทดสอบไม่มีแอปพลิเคชันอื่นที่มีโหลด CPU สูงและโหลด IO สูง
เครื่องมือทดสอบคือ 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% |
| Apache/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 ++ แม้ว่าจะมีประสิทธิภาพสูงกว่าการใช้ C ++ โดยตรงกับ iOstream แต่การโอเวอร์โหลดล็อกในรูปแบบ << สัญลักษณ์จะยังคงทำให้เกิดการควบคุมรูปแบบที่ไม่สะดวกและปัญหาประสิทธิภาพที่เกิดจากห่วงโซ่การเรียกใช้ฟังก์ชัน ปัญหาทั้งสองนี้สามารถแก้ไขได้โดยการใช้บันทึกในรูปแบบของ PRINTF
เนื่องจากเหตุผลเวลา SSXRVER ไม่ได้ใช้โมดูลการจัดการหน่วยความจำดังนั้นแทบจะเป็นไปไม่ได้เลยที่จะเขียนโมดูลการจัดการหน่วยความจำประสิทธิภาพสูงทั่วไป (เป็นการดีกว่าที่จะไปยัง Jemalloc หรือ TCMalloc) โดยตรง อย่างไรก็ตามด้วยการวิเคราะห์สถานการณ์ของไลบรารีเครือข่ายมันยังคงเป็นโอกาสเล็กน้อยที่จะเขียนโมดูลการจัดการหน่วยความจำที่มีประสิทธิภาพสูงกว่าในสถานการณ์นี้ ถ้าฉันมีเวลาฉันจะดูการใช้งานใน Nginx และเรียนรู้
เมื่อฉันสอบถามข้อมูลฉันได้ข้อสรุปว่าใน C ++ 17 คุณสามารถใช้ std :: string_view เพื่อแทนที่สตริง const & ซึ่งจะปรับปรุงประสิทธิภาพบางอย่าง ดังนั้นฉันจึงพยายามแทนที่สถานที่ทั้งหมดที่สตริง const & ในโครงการของฉันด้วย std :: string_view อย่างไรก็ตามในที่สุดเมื่อฉันใช้ perf -top เพื่อดูโหลดที่เปลี่ยนแปลงฉันก็ค้นพบโดยไม่คาดคิดว่าฟังก์ชั่นบางอย่างเพิ่มขึ้นจริงหลังจากที่ฉันใช้ std :: string_view เพื่อแทนที่ ฉันงงมากว่าทำไมสถานการณ์นี้จึงเกิดขึ้น เนื่องจากเหตุผลเวลาฉันจะไม่ตรวจสอบสาเหตุเฉพาะของปัญหานี้ในขณะนี้ ฉันมีโอกาสตรวจสอบการใช้งานพื้นฐานเพื่อตรวจสอบเหตุผลเฉพาะ
เมื่อใช้โมดูลการแยกวิเคราะห์ HTTP ฉันใช้เครื่องรัฐที่เขียนด้วยลายมือที่ตรงกับสตริงโดยตรงในเวอร์ชันแรก จากนั้นฉันก็แทนที่ด้วยเครื่องรัฐที่ใช้โดย Ragel อย่างไรก็ตามในระหว่างการทดสอบเมื่อเร็ว ๆ นี้ฉันพบว่าภาระของฟังก์ชั่นการแยกวิเคราะห์ HTTP นั้นเกินจริงมากถึง 10% เป็นไปได้ไหมที่การใช้ Ragel ทำให้ประสิทธิภาพลดลง? (หากการแยกวิเคราะห์ส่วนหัวจะทำให้เกิดการโหลดระบบที่สูงเช่นนั้นดูเหมือนว่า HTTP/2.0 จะยังคงปรับปรุงประสิทธิภาพอย่างมีนัยสำคัญ) น่าเสียดายที่เมื่อฉันเขียนด้วยลายมือของเครื่องก่อนฉันไม่ได้ทดสอบภาระของฟังก์ชั่นการแยกวิเคราะห์ที่สอดคล้องกัน ตอนนี้ฉันไม่สามารถรับการเปรียบเทียบข้อมูลระหว่างทั้งสองได้ในครั้งเดียวและฉันมีโอกาสเขียนการทดสอบมาตรฐาน
SSXRVER รองรับการส่ง UDP อย่างง่าย แต่โดยส่วนตัวแล้วฉันคิดว่าเฟรมเวิร์ก UDP ที่ไม่มีการควบคุมความแออัดการควบคุมการจราจรและฟังก์ชั่นการส่งคืนการสูญเสียแพ็คเก็ตสามารถกล่าวได้ว่าไม่สามารถใช้งานได้ตามปกติ ในอนาคตฉันมีเวลาเรียนรู้โปรโตคอล QUIC และ KCP ฉันจะเสริมความรู้ที่เกี่ยวข้องกับ UDP ฉันเชื่อว่าโปรโตคอล UDP ที่มีประสิทธิภาพและยืดหยุ่นมากขึ้นจะใช้กันอย่างแพร่หลายมากขึ้นในอนาคต!
ในความเป็นจริงฉันคิดว่าเฟรมเวิร์กเครือข่ายที่ดีที่สุดในปัจจุบันควรเป็นที่พอร์ตมัลติเพล็กซ์มัลติเพล็กซิ่งบวกหลายเธรด (หลายกระบวนการ) เชื่อมต่อที่อยู่และพอร์ตเดียวกันและเคอร์เนลจะดำเนินการโดยอัตโนมัติ ในเวลาเดียวกันบล็อกการโทรผ่าน Coroutine Framework + Hook หลังจากใช้เฟรมเวิร์กนี้แล้วมันสามารถมั่นใจได้ว่าประสิทธิภาพสูงโดยไม่ต้องใช้เธรดหลักเพื่อแจกจ่ายการเชื่อมต่อและไม่จำเป็นต้องตกอยู่ในการโทรกลับแบบอะซิงโครนัส
นอกจากนี้หากคุณสามารถใช้กลไก IO แบบอะซิงโครนัส io_ การเพิ่มหลังจาก Linux Kernel 5.1 ฉันเชื่อว่าประสิทธิภาพของเซิร์ฟเวอร์จะสูงขึ้น อย่างไรก็ตามฉันไม่รู้เกี่ยวกับ io_ ในปัจจุบันและฉันไม่มีความสามารถในการออกแบบห้องสมุดเครือข่าย IO แบบอะซิงโครนัสตาม iO_uring