Как реализовать автоматическое обнаружение AWS Elasticache для node.js
Я noob узла и пытаюсь понять, как можно реализовать автоматическое обнаружение в приложении node.js. Я собираюсь использовать модуль кластера и хочу, чтобы каждый рабочий процесс поддерживался в актуальном состоянии (и постоянно подключался) к узлам эластичного кэша.
Поскольку не существует концепции разделяемой памяти (как, например, PHP APC), нужно ли иметь код, который запускается на каждом рабочем месте, который просыпается каждые X секунд и каким-то образом обновляет список IP-адресов и повторно подключает клиент memcache?
Как люди решают это сегодня? Пример кода будет высоко ценится.
1 ответ
Обратите внимание, что в настоящее время автоматическое обнаружение доступно только для кластеров кэша, на которых работает механизм memcached.
Для Cache Engine версии 1.4.14 или выше необходимо создать сокет TCP/IP для конечной точки конфигурации кластера кэша (или любой конечной точки узла кэша) и отправить эту команду:
config get cluster
С Node.js вы можете использовать для этого класс net.Socket.
Ответ состоит из двух строк:
Номер версии информации о конфигурации. Каждый раз, когда узел добавляется или удаляется из кластера кэша, номер версии увеличивается на единицу.
Список узлов кеша. Каждый узел в списке представлен группой hostname | ip-address | port, а каждый узел отделяется пробелом.
Возврат каретки и символ перевода строки (CR + LF) появляются в конце каждой строки.
Здесь вы можете найти более подробное описание того, как добавить автообнаружение в вашу клиентскую библиотеку.
Используя модуль кластера, вам нужно хранить одну и ту же информацию в каждом процессе (то есть дочернем), и я бы использовал "setInterval" для дочернего элемента, чтобы периодически проверять (например, каждые 60 секунд) список узлов и повторно подключаться, только если список изменился (это не должно случаться очень часто).
При желании вы можете обновить список только на главном компьютере и использовать "worker.send" для обновления рабочих. Это могло бы синхронизировать все процессы, выполняющиеся на одном сервере, но не помогло бы в многосерверной архитектуре, поэтому очень важно использовать согласованное хеширование, чтобы иметь возможность изменить список узлов и потерять " минимальное количество ключей, хранящихся в кластере memcached.
Я бы использовал глобальную переменную для хранения такого рода конфигурации.
Подумав дважды, вы можете использовать AWS SDK для Node.js, чтобы получить список узлов ElastiCache (и это работает также для движка Redis).
В этом случае код будет выглядеть примерно так:
var util = require('util'),
AWS = require('aws-sdk'),
Memcached = require('memcached');
global.AWS_REGION = 'eu-west-1'; // Just as a sample I'm using the EU West region
global.CACHE_CLUSTER_ID = 'test';
global.CACHE_ENDPOINTS = [];
global.MEMCACHED = null;
function init() {
AWS.config.update({
region: global.AWS_REGION
});
elasticache = new AWS.ElastiCache();
function getElastiCacheEndpoints() {
function sameEndpoints(list1, list2) {
if (list1.length != list2.length)
return false;
return list1.every(
function(e) {
return list2.indexOf(e) > -1;
});
}
function logElastiCacheEndpoints() {
global.CACHE_ENDPOINTS.forEach(
function(e) {
util.log('Memcached Endpoint: ' + e);
});
}
elasticache.describeCacheClusters({
CacheClusterId: global.CACHE_CLUSTER_ID,
ShowCacheNodeInfo: true
},
function(err, data) {
if (!err) {
util.log('Describe Cache Cluster Id:' + global.CACHE_CLUSTER_ID);
if (data.CacheClusters[0].CacheClusterStatus == 'available') {
var endpoints = [];
data.CacheClusters[0].CacheNodes.forEach(
function(n) {
var e = n.Endpoint.Address + ':' + n.Endpoint.Port;
endpoints.push(e);
});
if (!sameEndpoints(endpoints, global.CACHE_ENDPOINTS)) {
util.log('Memached Endpoints changed');
global.CACHE_ENDPOINTS = endpoints;
if (global.MEMCACHED)
global.MEMCACHED.end();
global.MEMCACHED = new Memcached(global.CACHE_ENDPOINTS);
process.nextTick(logElastiCacheEndpoints);
setInterval(getElastiCacheEndpoints, 60000); // From now on, update every 60 seconds
}
} else {
setTimeout(getElastiCacheEndpoints, 10000); // Try again after 10 seconds until 'available'
}
} else {
util.log('Error describing Cache Cluster:' + err);
}
});
}
getElastiCacheEndpoints();
}
init();