如何为node.js实施AWS Elasticache自动发现

时间:2013-06-11 14:30:22

标签: node.js amazon-web-services amazon-elasticache

我是一个节点菜鸟,试图了解如何在node.js应用程序中实现auto discovery。我将使用cluster module并希望每个工作进程保持最新(并持久连接到)弹性缓存节点。

由于没有共享内存的概念(如PHP APC),您是否必须拥有在每个工作程序中运行的代码,每X秒唤醒一次并以某种方式更新IP列表并重新连接内存缓存客户端? / p>

今天人们如何解决这个问题?示例代码将非常感激。

1 个答案:

答案 0 :(得分:3)

请注意,此时,Auto Discovery仅适用于运行memcached引擎的缓存群集。

对于缓存引擎版本1.4.14或更高版本,您需要为缓存群集配置端点(或任何缓存节点端点)创建TCP / IP套接字并发送此命令:

config get cluster

使用Node.js,您可以使用net.Socket class来实现。

答复由两行组成:

  • 配置信息的版本号。每次在缓存集群中添加或删除节点时,版本号都会增加一个。

  • 缓存节点列表。列表中的每个节点由主机名| ip-address |端口组表示,每个节点由空格分隔。

回车符和换行符(CR + LF)出现在每一行的末尾。

您可以在此处找到有关如何add Auto Discovery to your client library的详尽说明。

使用群集模块,您需要在每个进程(即子进程)中存储相同的信息,我将使用" setInterval"每个孩子定期检查(例如每60秒)节点列表,如果列表已经改变,则重新连接 (这不应经常发生)。

您可以选择仅更新主服务器上的列表并使用" worker.send"更新工人。这可以使单个服务器中运行的所有进程保持同步,但在多服务器体系结构中无济于事,因此使用一致哈希非常重要,以便能够更改节点列表和松散的"最小值"存储在memcached群集中的密钥数量。

我会使用全局变量来存储这种配置。

您可以使用适用于Node.js的AWS SDK 来获取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();