Распределенный кеш на основе Nginx и proxy_cache

Thank you for reading this post, don't forget to subscribe!

При исполь­зо­ва­нии кеши­ро­ва­ния место на дис­ке рано или позд­но закон­чит­ся. В таком слу­чае обыч­но исполь­зу­ют очист­ки кеша. Напри­мер, уда­лять все фай­лы, кото­рые на запра­ши­ва­лись боль­ше 7 дней. В Nginx это настра­и­ва­ет­ся так:

# пра­ви­ло уда­ле­ния фай­лов из кеша

Но ясно, это ухуд­шит опыт пользователей.

Распределенный кеш

В каче­стве аль­тер­на­ти­вы мож­но исполь­зо­вать рас­пре­де­лен­ный кеш. В таком слу­чае, на каж­дом сер­ве­ре будет сохра­нять­ся толь­ко часть обще­го кеша. А зна­чит, общее коли­че­ство фай­лов, кото­рые мож­но хра­нить в кеше, будет намно­го больше.

Такой вари­ант будет поле­зен при отда­че боль­шо­го коли­че­ства фай­лов. Осо­бен­но боль­ших, вро­де видео или фоток. При­ме­нять это сто­ит, напри­мер, в рам­ках систе­мы опти­ми­за­ции затрат на CDN.

Распределение запросов

Все, что нуж­но сде­лать — заста­вить nginx часть запро­сов отправ­лять на сосед­ний сер­вер. Для нача­ла собе­рем про­стую кон­фи­гу­ра­цию отда­чи фай­лов с раз­ных сер­ве­ров (без кеша).

Пусть у нас есть два сервера:

  • 165.227.150.69
  • 207.154.211.168

Если запрос при­шел на пер­вый сер­вер, мы хотим толь­ко поло­ви­ну запро­сов отдать с него же. А вто­рую поло­ви­ну отпра­вить на вто­рой сер­вер. То же самое и для вто­ро­го сер­ве­ра, толь­ко для вто­рой поло­ви­ны запросов:

Рас­пре­де­ле­ние дела­ет­ся на осно­ве upstream hash:

[codesyntax lang="php"]

[/codesyntax]

Рас­пре­де­ле­ние запро­сов в Nginx на осно­ве consistent hash

Тут мы:

  • С помо­щью бло­ка upstream cluster опре­де­ля­ем спи­сок сер­ве­ров. На них будет отправ­лен исход­ный запрос. Так, один из них — это и есть сам сер­вер, а вто­рой — его сосед.
  • hash $request_uri consistent опре­де­ля­ет прин­цип рас­пре­де­ле­ния запро­сов (в нашем слу­чае — consistent hashing).
  • Пер­вый вир­ту­аль­ный сер­вер слу­ша­ет порт 80. Он про­сто отправ­ля­ет запрос на upstream.
  • Вто­рой вир­ту­аль­ный сер­вер обслу­жи­ва­ет запрос (в при­ме­ре — php скрипт).

Добавляем кеш

Теперь доста­точ­но в нашу кон­фи­гу­ра­цию доба­вить про­ме­жу­точ­ный вир­ту­аль­ный сер­вер, кото­рый будет кеши­ро­вать дан­ные. Вир­ту­аль­ный сер­вер с пор­та 81 пере­не­сем на 82. А порт 81 зай­мем сер­ве­ром для кеширования:

[codesyntax lang="php"]

[/codesyntax]

Рас­пре­де­лен­ный кеш запросов

Теперь, кро­ме рас­пре­де­ле­ния запро­сы еще и кеши­ру­ют­ся. Часть фай­лов кеша будет скла­ды­вать­ся на один сер­вер. Вто­рая часть — на дру­гой. Места для хра­не­ния кеша ста­ло в два раза боль­ше. То, что мы и хоте­ли получить.

Внутренний трафик

Обра­ти­те вни­ма­ние. Один сер­вер прок­си­ру­ет часть запро­сов со вто­ро­го. Это может вызвать про­бле­мы, если сер­ве­ра отда­ле­ны гео­гра­фи­че­ски. В таком слу­чае, име­ет смысл исполь­зо­вать груп­пы сер­ве­ров, кото­рые рас­по­ло­же­ны рядом (в одном ДЦ).

Тра­фик меж­ду узла­ми зна­чи­тель­но вырас­тит, если сер­ве­ров ста­нет очень мно­го. Так­же реша­ет­ся груп­пи­ров­кой сер­ве­ров (напри­мер, по 10 в одной группе).

Доступность

Теперь сер­ве­ра зави­сят друг от дру­га. И если поло­ма­ет­ся один, эту ошиб­ку сра­зу уви­дят поль­зо­ва­те­ли. Для обес­пе­че­ния высо­кой доступ­но­сти, сле­ду­ет все­гда ста­вить (мини­мум) по паре сер­ве­ров, кото­рые будут высту­пать копи­я­ми друг дру­га. Тогда при сбое одно­го мож­но будет авто­ма­ти­че­ски пере­клю­чать­ся на другой.

  • Nginx поз­во­ля­ет настро­ить рас­пре­де­лен­ный кеш меж­ду несколь­ки­ми сер­ве­ра­ми. Его сто­ит исполь­зо­вать для повы­ше­ния эффек­тив­но­сти кеша (боль­ше места = боль­ше hitrate).
  • Не сто­ит исполь­зо­вать более 10 сер­ве­ров в одной груп­пе рас­пре­де­лен­но­го кеша.
  • Для обес­пе­че­ния высо­кой доступ­но­сти сто­ит иметь рабо­та­ю­щую копию каж­до­го сервера.