[Хд] logo

Multi Get в Memcache

Memcache предоставляет возможность получения значений нескольких ключей сразу. Зачем это может понадобиться и в каких случаях это нужно использовать? Посмотрим на структуру запросов от приложения к Memcache, когда идет получение нескольких ключей: Memcache get

Запрос к каждому ключу — это отдельный сетевой запрос:

  • Отправка из приложения в Memcache запроса с названием ключа
  • Отправка из Memcache в приложение ответа со значением ключа

Когда количество таких запросов переваливает за десятки с одной страницы Web сайта, следует подумать об оптимизации. Обычная функция memcache_get() позволяет передавать в параметры не один ключ, а массив ключей. Этот режим называется Multi Get. Тогда на сервер кэширования будет отправлен только один запрос и получен только один ответ с массивом значений: Memcache multi get

Использование

Рассмотрим небольшой пример. Пусть у нас есть список новостей. Каждая новость будет храниться в ключе под именем "news_item_[id]", где [id] — ID новости. Используя Multi Get мы сможем получить все новости за один запрос вместо нескольких десятков. Для этого достаточно передать массив ключей в функцию memcache_get() (либо метод get()):

<?

# Получаем список ID новостей (например, из базы данных)
$news_ids = [1, 2, 3, 4, 5];

$m = new Memcache;
foreach ( $news_ids as $id ) $keys[] = 'news_item_' . $id;
$news = $m->get($keys);

# Переменная $keys содержит список ключей, в переменную $news попадет список данных новостей

Производительность

Сравним скорость Multi GET и обычного memcache_get() для каждого ключа. Скрипт для сравнения на PHP:

<?
$tests = 15000;

$m = new Memcache;
$m->connect('localhost', '11211');

for ( $i = 0; $i < $tests; $i ++ )
{
        $m->set('test' . $i, md5($i));
}

$t = microtime(true);

for ( $i = 0; $i < $tests; $i ++ )
{
        $list_get[] = $m->get('test' . $i);
        $keys[] = 'test' . $i;
}

echo 'Fetched ' . $tests . ' objects with standard get in ' . (microtime(true) - $t) . 's';
echo "\n";

$t = microtime(true);

$list_mget = $m->get($keys);

echo 'Fetched ' . $tests . ' objects with multiple get in ' . (microtime(true) - $t) . 's';
echo "\n";

# Отправим 15000 запросов одним запросом и несколькими

Результаты будут приблизительно такими:

Fetched 15000 objects with standard get in 0.47441411018372s
Fetched 15000 objects with multiple get in 0.023789882659912s

В случае Multi Get мы потратили на порядок меньше времени. Тестирование выполнялось на одном сервере. Это значит, что подключение к Memcache по сети даст еще большее отличие.

Когда следует применять Multi Get?

На практике у Вас не будет возможности собрать все ключи и отправить запрос на сервер из одного участка кода. Это неудобно, т.к. приведет к крайне плохой гибкости приложения. Однако есть ряд случаев, когда это все же следует применять.

Перебор списков

Как в примере с новостям, логика Web приложения часто содержит перебор списков пользователей, картинок, новостей, комментариев и т.п. В этом случае Multi Get будет очень полезен и прост в реализации. Нужно отметить, что на практике необходимо дополнительно проверять наличие значений в возвращаемых ключах, т.к. каких-то значений может не быть:

<?
$news_ids = [1, 2, 3, 4, 5];

$m = new Memcache;
foreach ( $news_ids as $id ) $keys[] = 'news_item_' . $id;
$news = $m->get($keys);
foreach ( $news as $i => $post )
{
	if ( !$post ) $post = get_post( $keys[$i] );
	echo $post['title'] . '<br/>';
}

# Функция get_post() должна вернуть данные новости из базы данных

Cron задачи

В отдельной Cron задаче намного проще собрать необходимые для выборки ключи, чем в целом приложении. Их можно собирать и обрабатывать частями, например по 10 штук. Популярный пример — рассылка новостей по почте:

<?
$users_ids = [1, 2, 3, 4, 5, ...];

foreach ( $users_ids as $i => $id )
{
	if ( count($keys) < 10 )
	{
		# собираем список ключей по 10 штук максимум
		$keys[] = 'user' . $id;

		# продолжаем, только если еще не конец списка
		if ( $keys[$i+1] ) continue;
	}

	# получаем данные пользователей
	$users = $m->get($keys);
	foreach ( $users as $user )
	{
		mail($user['email'], 'Э', 'Чо');
	}
	
	# очищаем массив ключей
	$keys = [];
}

# Получаем сразу по 10 значений данных пользователей вместо одного

Самое важное

Использование множественного запроса Multi Get в Memcache позволяет снизить количество обращений от приложения к серверу кэша. Это уменьшает сетевой трафик и ускоряет работу приложения.

  read in english
[Хд]

Подписывайтесь на отборные материалы по продвинутой разработке

Google Email

Esc, чтобы подписаться позже