Производительность GridFS
В этой заметке я хочу разместить свой перевод замечательной статьи про GridFS. Задача хранения и раздачи файлов в кластерной среде сегодня с развитием облачных вычислений приобретает всё большую актуальность.
Задача
Хранить и раздавать статические файлы (картинки, стили и скрипты) на кластере из нескольких серверов.
Возможные решения
NFS, Lustre, SMB (Samba), Hadoop, DRBD (сетевой RAID). Из всего множества решений раньше мне больше всего импонировал Hadoop, однако попробовать его руки так и не дошли. А тут на глаза недавно попался бенчмарк про GridFS, о котором я рассказывал в предыдущем посте.
Что такое GridFS?
GridFS – это GridFS это маленькая но очень полезная возможность в MongoDB, которая позволяет хранить файлы любых видов и размеров в самой БД, используя при этом преимущества шардинга и репликации. Однако, раз файлы в БД, а не в ФС, как же получить доступ к ним, как раздавать файлы клиентам? Есть несколько вариантов и ниже мы их рассмотрим.
На данный момент есть 3 возможности:
- Использовать “низкоуровневый” скрипт-обработчик, как Rack скрипт или Rails Metal handler для раздачи файлов из БД.
- Подмонтировать файлы из БД к ФС с помощью, например, gridfs-fuse, и читать файлы из ФС напрямую.
- Использовать модуль для веб-сервера, например nginx-gridfs, который при получении запроса будет обращаться напрямую к MongoDB.
Второй вариант я рассмотрел в предыдущей статье, теперь займёмся третьим 🙂
ФС через Apache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
[chris@polaris conf]# ab -n 50000 -c 10 http://advice/images/embed/alliance-60.png Server Software: Apache/2.2.13 Server Hostname: advice Server Port: 80 Document Path: /images/embed/normal_alliance-60.png Document Length: 31596 bytes Concurrency Level: 10 Time taken for tests: 1.904 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 159463760 bytes HTML transferred: 158043192 bytes Requests per second: 2625.37 [#/sec] (mean) Time per request: 3.809 [ms] (mean) Time per request: 0.381 [ms] (mean, across all concurrent requests) Transfer rate: 81767.87 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 0.4 1 4 Processing: 1 3 0.5 3 6 Waiting: 0 1 0.4 1 4 Total: 2 4 0.4 4 8 Percentage of the requests served within a certain time (ms) 50% 4 66% 4 75% 4 80% 4 90% 4 95% 4 98% 5 99% 5 100% 8 (longest request) |
Довольно быстро, как мы и ожидали. Теперь попробуем с nginx.
ФС через nginx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
[chris@polaris conf]# ab -n 50000 -c 10 http://advice:81/images/embed/normal_alliance-60.png Server Software: nginx/0.8.33 Server Hostname: advice Server Port: 81 Document Path: /images/embed/normal_alliance-60.png Document Length: 31596 bytes Concurrency Level: 10 Time taken for tests: 7.623 seconds Complete requests: 50000 Failed requests: 0 Write errors: 0 Total transferred: 1590513618 bytes HTML transferred: 1579863192 bytes Requests per second: 6559.31 [#/sec] (mean) Time per request: 1.525 [ms] (mean) Time per request: 0.152 [ms] (mean, across all concurrent requests) Transfer rate: 203763.10 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 9 Processing: 1 1 0.4 1 11 Waiting: 0 0 0.1 0 9 Total: 1 1 0.5 1 12 Percentage of the requests served within a certain time (ms) 50% 1 66% 1 75% 1 80% 2 90% 2 95% 2 98% 3 99% 3 100% 12 (longest request) |
Nginx рулит, 6500 запросов в секунду.
GridFS через nginx-gridfs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
[chris@polaris conf]# ab -n 5000 -c 10 http://advice:81/images/gfs/uploads/user/avatar/4b7b2c0e98db7475fc000003/normal_alliance-60.png Server Software: nginx/0.8.33 Server Hostname: advice Server Port: 81 Document Path: /images/gfs/uploads/user/avatar/4b7b2c0e98db7475fc000003/normal_alliance-60.png Document Length: 31596 bytes Concurrency Level: 10 Time taken for tests: 4.613 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 158580000 bytes HTML transferred: 157980000 bytes Requests per second: 1083.88 [#/sec] (mean) Time per request: 9.226 [ms] (mean) Time per request: 0.923 [ms] (mean, across all concurrent requests) Transfer rate: 33570.65 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 1 Processing: 1 9 4.7 9 103 Waiting: 1 9 4.7 9 102 Total: 2 9 4.7 9 103 Percentage of the requests served within a certain time (ms) 50% 9 66% 9 75% 9 80% 9 90% 9 95% 9 98% 9 99% 11 100% 103 (longest request) |
Определённо ниже, однако всё ещё внушающие. 1051 запросов в секунду это более чем достаточно для большинства целей, особенно, с фасадом в виде CDN 🙂
Rails Metal handler
Основное преимущество Rails metal handler в том, что о простой. Не надо ничего перекомпилировать, просто добавьте его в свой проект. Вот его результаты:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
[chris@polaris nginx-gridfs]$ ab -n 250 -c 4 http://advice/images/gfs/uploads/user/avatar/4b7b2c0e98db7475fc000003/normal_alliance-60.png Server Software: Apache/2.2.13 Server Hostname: advice Server Port: 80 Document Path: /images/gfs/uploads/user/avatar/4b7b2c0e98db7475fc000003/normal_alliance-60.png Document Length: 31596 bytes Concurrency Level: 4 Time taken for tests: 4.646 seconds Complete requests: 250 Failed requests: 0 Write errors: 0 Total transferred: 7960000 bytes HTML transferred: 7899000 bytes Requests per second: 53.81 [#/sec] (mean) Time per request: 74.338 [ms] (mean) Time per request: 18.585 [ms] (mean, across all concurrent requests) Transfer rate: 1673.10 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 1 Processing: 15 74 75.6 34 287 Waiting: 0 72 75.8 30 276 Total: 15 74 75.6 34 288 Percentage of the requests served within a certain time (ms) 50% 34 66% 39 75% 139 80% 192 90% 201 95% 210 98% 239 99% 245 100% 288 (longest request) |
К сожалению 53 запроса в секунду – не самый привлекательный результат.
Сравнение решений
Решение | Requests/second | % Apache FS | % Nginx FS | % Nginx GridFS | % Apache Ruby |
---|---|---|---|---|---|
Filesystem через Apache | 2625.37 | – | 40.03% | 242.22% | 4,878.96% |
Filesystem через Nginx | 6559.31 | 249.84% | – | 605.17% | 12,189.76% |
GridFS через nginx module | 1083.88 | 41.28% | 16.52% | – | 2014.27% |
Rails metal handler через Passenger | 53.81 |
Если вы хотите перейти от хранения файлов в локальной ФС, то GridFS это приемлемое решение. Причина использования GridFS состоит в том, что вы получаете потрясающую гибкость и масштабируемость из коробки в авто-реплицируемой шардируемой отказоустойчивой (сколько прилагательных 🙂 ) среде. Но естественно расплачиваетесь производительностью на отдельно-взятом узле, при этом однако есть возможность довольно просто увеличивать производительность всего кластера.
Ссылки
http://www.coffeepowered.net/2010/02/17/serving-files-out-of-gridfs/
Мне больше всего оказалась полезным информация про apache benchmark tool 🙂 Сам по себе ab не дает нагрузку на сервер? Можете поделиться способами тестирования производительности веб-приложений? С достоинствами/недостатками было бы вообще замечательно.
Ну если он запускается с другого сервера то точно нет 🙂
Да, думаю отдельным постом сделаю. А в общем скажу так, есть siege и ab. Мне нравится ab, т.к. он очень простой с одной стороны, а с другой – очень гибкий. Можно на баше или руби написать скрипт, который будет вызывать ab с разными параметрами и эмулировать таким образом целевую аудиторию с необходимыми действиями.
Спасибо, очень содержательно о GridFS. Сомнения разбились напрочь.