Для изучения нового языка программирования я использую следующий подход. Сначала я читаю учебник по этому языку программирования, в котором объясняются синтаксис, идиомы, философия и принципы работы языка. После этого я пишу небольшой пет-проект на этом языке программирования. На пет-проекте я немного практикуюсь с новым языком, с его стандартными библиотеками и популярными фреймворками.
Чтобы погрузиться сильнее в язык, вместо пет-проекта я начинаю писать свои библиотеки для работы с базами данных (ORM), JSON, акторами, MVC веб-фреймворком, логированием и т.д. Библиотеки, которые вряд ли будут кому-то нужны, но они помогут мне лучше понять язык программирования. На удивление, с языком Rust я добрался до написания своего веб-сервера. Раньше такого не было. Думаю, это из-за того, что Rust — это язык системного программирования и грех на нём не попробовать заняться оптимизацией перформанса.
В итоге я столкнулся с тем, что Rust не имеет аналогов Nginx, Lighttpd, Caddy, HAProxy, Apache, Tomcat, Jetty и т.д. Все эти веб-сервера написаны на C, Go, Java и т.д. Имеются только веб-фреймворки: Actix, Axum, Rocket, Hyper и т.д.
В целом я прикинул, что обычно я использую Nginx для следующих целей:
1. TLS для доменов
2. Проксирование запросов на бэкэнд
3. Раздача статических файлов
В итоге решил написать свою реализацию веб-сервера на Rust.
Сервер поддерживает конфигурационный файл в формате KDL Document Language. Вот примеры "Cbltfile" конфигурационного файла для веб-сервера Cblt:
Файл сервер
"*:80" {
root "*" "/path/to/folder"
file_server
}
Файл сервер & Проксирование
"127.0.0.1:8080" {
reverse_proxy "/test-api/*" "http://10.8.0.3:80"
root "*" "/path/to/folder"
file_server
}
TLS поддержка
"example.com" {
root "*" "/path/to/folder"
file_server
tls "/path/to/your/domain.crt" "/path/to/your/domain.key"
}
Сейчас Cblt веб-сервер можно запустить двумя способами: через Cargo или Docker.
Cargo
cargo run --release
Docker
docker build -t cblt:0.0.3 .
docker run -d -p 80:80 --restart unless-stopped --name cblt cblt:0.0.3
На текущий момент я добился приемлемой скорости работы для проксирования статических файлов.
UPDATE: Начиная с версии 0.1.5, работает в 10 раз быстрее, чем Nginx на запросах менее 100 Кб. Принимаю поздравления :)
Провёл тест с Apache Benchmark (ab) для 300 запросов с 100 одновременными соединениями. Загрузка изображения размером 5 МБ с example.com/logo_huge.png.
ab -c 100 -n 300 http://example.com/logo_huge.png
Percent |
Cblt |
Nginx |
Caddy |
50% |
1956 |
1941 |
1768 |
75% |
2101 |
2065 |
1849 |
100% |
2711 |
2360 |
2270 |
Cblt
igumn@lenovo MINGW64 ~/cblt (main)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0589d8f26d91 cblt:0.0.1 "./cblt" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp cblt
igumn@lenovo MINGW64 ~/cblt (main)
$ ab -c 100 -n 300 http://example.com/logo_huge.png
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking example.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Finished 300 requests
Server Software:
Server Hostname: example.com
Server Port: 80
Document Path: /logo_huge.png
Document Length: 5122441 bytes
Concurrency Level: 100
Time taken for tests: 6.020 seconds
Complete requests: 300
Failed requests: 0
Total transferred: 1536745500 bytes
HTML transferred: 1536732300 bytes
Requests per second: 49.83 [#/sec] (mean)
Time per request: 2006.721 [ms] (mean)
Time per request: 20.067 [ms] (mean, across all concurrent requests)
Transfer rate: 249283.62 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 2
Processing: 1293 1926 262.3 1956 2711
Waiting: 1 118 139.1 63 645
Total: 1293 1926 262.3 1956 2711
Percentage of the requests served within a certain time (ms)
50% 1956
66% 2027
75% 2101
80% 2127
90% 2213
95% 2394
98% 2544
99% 2597
100% 2711 (longest request)
Nginx
igumn@lenovo MINGW64 ~/cblt/benchmark/nginx (main)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37fbf1dac42b nginx_srv "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp nginx_srv
igumn@lenovo MINGW64 ~/cblt/benchmark/nginx (main)
$ ab -c 100 -n 300 http://example.com/logo_huge.png
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking example.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Finished 300 requests
Server Software: nginx/1.27.2
Server Hostname: example.com
Server Port: 80
Document Path: /logo_huge.png
Document Length: 5122441 bytes
Concurrency Level: 100
Time taken for tests: 6.043 seconds
Complete requests: 300
Failed requests: 0
Total transferred: 1536804300 bytes
HTML transferred: 1536732300 bytes
Requests per second: 49.65 [#/sec] (mean)
Time per request: 2014.267 [ms] (mean)
Time per request: 20.143 [ms] (mean, across all concurrent requests)
Transfer rate: 248359.28 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 2
Processing: 1387 1940 168.4 1941 2360
Waiting: 1 115 84.5 98 301
Total: 1387 1940 168.4 1941 2360
Percentage of the requests served within a certain time (ms)
50% 1941
66% 2024
75% 2065
80% 2088
90% 2152
95% 2201
98% 2263
99% 2317
100% 2360 (longest request)
Caddy
igumn@lenovo MINGW64 ~/cblt (main)
$ ab -c 100 -n 300 http://example.com/logo_huge.png
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking example.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Finished 300 requests
Server Software: Caddy
Server Hostname: example.com
Server Port: 80
Document Path: /logo_huge.png
Document Length: 5122441 bytes
Concurrency Level: 100
Time taken for tests: 5.440 seconds
Complete requests: 300
Failed requests: 0
Total transferred: 1536804000 bytes
HTML transferred: 1536732300 bytes
Requests per second: 55.14 [#/sec] (mean)
Time per request: 1813.469 [ms] (mean)
Time per request: 18.135 [ms] (mean, across all concurrent requests)
Transfer rate: 275858.99 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 2
Processing: 1264 1749 191.1 1767 2270
Waiting: 1 96 104.7 67 467
Total: 1265 1749 191.1 1768 2270
Percentage of the requests served within a certain time (ms)
50% 1768
66% 1821
75% 1849
80% 1877
90% 1955
95% 2152
98% 2226
99% 2241
100% 2270 (longest request)
В планах также провести тесты для проксирования бэкенда, в общем reverse_proxy на производительность не тестировал еще.
Может в этот раз мой мини-проект кого-то заинтересует? И это увлечение вырастет в что-то большее?
Если интересно глянуть код или поконтрибутить, вот ссылка на репозиторий: https://github.com/evgenyigumnov/cblt
Комментарии (27)
Medeyko
09.11.2024 15:08Спасибо, но было бы здорово, если бы в статье было написано, с какими проблемами столкнулись, как обошли...
В частности, понятно ли, почему работает несколько медленнее Nginx и Caddy? Что можно сделать, чтобы убыстрить?
Tyiler
09.11.2024 15:08Может в этот раз мой мини-проект кого-то заинтересует? И это увлечение вырастет в что-то большее?
Присоединяйтесь лучше ко мне - надерем задницу ZeroMQ!
PS: на самом деле всех приглашаю кто шарит: проекту нужны веб-страничка с доками (своя или от гитхаба), тесты, фиксы, идеи... ну и как результат: ответы на so, восторженные отзывы и статьи на ресурсах (редит, хабр, медиум и тд).
vdudouyt
09.11.2024 15:08Поставил плюс на гитхабе за подход к написанию кода - просто и по делу, а не как бывает у иных пассионарных фанатов Rust или, тем более, Haskell.
Dgolubetd
09.11.2024 15:08В итоге я столкнулся с тем, что Rust не имеет аналогов Nginx, Lighttpd, Caddy, HAProxy, Apache, Tomcat, Jetty и т.д. Все эти веб-сервера написаны на C, Go, Java и т.д.
Есть River (замена Nginx, на ранней стадии разработки):
https://www.memorysafety.org/initiative/reverse-proxy/
Есть G3:
https://github.com/bytedance/g3
Имеются только веб-фреймворки: Actix, Axum, Rocket, Hyper и т.д.
Мне кажется не корректно Actix, Axum и тем более Hyper фреймворками называть. Это библиотеки. Последняя к тому же достаточно низкоуровневая, чтобы на ней строились другие (тот же Axum и Rocket используют Hyper).
olku
09.11.2024 15:08О, теперь и на Раст. Быстрый, надёжный, простой прокси интересует. От конфигов Traefik тошнит, Nginx нужно перезапускать, Caddy хорош но не поддерживает лейблы из коробки.
Safort
09.11.2024 15:08Автор, вы смотрели на https://github.com/cloudflare/pingora ? Выглядит так, что в ней уже реализуются вещи, которых вам не хватало.
qweururu
Для того, чтобы проект заинтересовал кого-нибудь должна быть какая-то идея, какие-то киллер-фичи. Поправьте меня, если я пропустил что-то, но из причин увидел только "нет вебсервера на rust". Этого как-то мало.
Поэтому если хотите заинтересовать кого-то, думаю вам нужна какая-то определённая цель, что-то новое, чего не хватает в существующих решениях.
Grey83
Но это же как минимум фатальный недостаток!
qweururu
Ну я без шуток говорил. Непонятен ход мыслей автора по поводу привлечения людей.
Фатальный недостаток - насколько мне известно, это больше про управление/собственное производство/прочий контроль, а не про выбор инструментов разработки.
Grey83
http://lurklurk.com/Фатальный_недостаток
https://neolurk.org/wiki/Фатальный_недостаток
https://ru.wikipedia.org/wiki/Синдром_неприятия_чужой_разработки
igumnov Автор
Ржачно - почитал ссылки )
qweururu
Ну ссылки подтверждают мой тезис. Там везде своё vs чужое, а не технология X vs технология Y.
pkirill
Фича это открытый код который работает.
qweururu
nginx это также открытый код, который работает. Причём я этот момент явно описывал: "что-то новое, чего не хватает в существующих решениях". Хотя даже без подобной оговорки, неясно как можно выдавать за киллер-фичу что-то присущее обоим вариантам и не являющееся уникальным.
pkirill
Еще он от С отличается безопасностью и коробки Rust
igumnov Автор
Добился цели. Работает в 10 раз быстрее, чем Nginx на запросах меньше 100 Кб. Принимаю поздравления.
qweururu
Неполохо бы было определиться, потому как ниже есть комментарий "Цель переплюнуть nginx не ставилась"(и вы это не отрицаете). Цели ставятся/декларируются изначально, а не после.
По поводу самой цели - это подлог. Многое вам уже написали в комментариях к другой статье. Основной смысл вебсервера - запуск php/иных скриптов, и в целом расширяемость/кастомизируемость без правки кода самого вебсервера. Если есть возможность разменять универсальность на скорость - берётся библиотека, а не сервер.
В целом, опять же не вижу мотивации, с которой люди должны вливаться в проект. Но дело ваше.
igumnov Автор
Добавить поддержку PHP бека ? ) На нем еще пишут? Наверное только старые легаси проекты поддерживают.
qweururu
Ну это одна из главных фич вебсерверов. Протоколами/коннектами/роутингом/в целом управлением занимается вебсервер, а далее сзади пускается php/что-то иное, куда пользователь может легко вписать какую-то свою логику. И типа в сложный код вэбсервера лезть ему не придётся.
igumnov Автор
Ну все верно CBLT это сервер который настраивается через конфиг - в код лезть не надо
Ставиться комадной:
cargo install cblt
после этого:
cblt --help
и будет счастье
qweururu
Может быть кому-то и этого будет достаточно, но я в этом смысла не вижу. Это по поводу фразы "вырастет в что-то большее" из статьи. Не слишком понятно, во что и каким образом проект может вырасти при таких вводных.
А так - код ваш, решать вам. Если видите применимость подобного, могу только пожелать удачи. Возможно что-то и получится.
igumnov Автор
Add PHP backand support · Issue #7 · evgenyigumnov/cblt