Как реализовать автоматическое обнаружение 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();
Другие вопросы по тегам