Redis
 sql >> डेटाबेस >  >> NoSQL >> Redis

रेडिस प्रहरी के साथ उच्च उपलब्धता:रेडिस मास्टर/स्लेव सेट से कनेक्ट करना

एक सिंगल, स्टैंडअलोन रेडिस सर्वर से कनेक्ट करना काफी आसान है:बस होस्ट, पोर्ट को इंगित करें, और प्रमाणीकरण पासवर्ड प्रदान करें, यदि कोई हो। अधिकांश रेडिस क्लाइंट कुछ प्रकार के यूआरआई कनेक्शन विनिर्देशों के लिए भी समर्थन प्रदान करते हैं।

हालांकि, उच्च उपलब्धता (HA) प्राप्त करने के लिए, आपको एक मास्टर और स्लेव कॉन्फ़िगरेशन को परिनियोजित करने की आवश्यकता है। इस पोस्ट में, हम आपको दिखाएंगे कि HA कॉन्फ़िगरेशन में Redis सर्वर से एक ही समापन बिंदु के माध्यम से कैसे कनेक्ट किया जाए।

Redis में उच्च उपलब्धता

Redis में उच्च उपलब्धता मास्टर-स्लेव प्रतिकृति के माध्यम से प्राप्त की जाती है। एक मास्टर रेडिस सर्वर में कई रेडिस सर्वर दास के रूप में हो सकते हैं, अधिमानतः कई डेटा केंद्रों में विभिन्न नोड्स पर तैनात किए जाते हैं। जब मास्टर उपलब्ध नहीं होता है, तो दासों में से एक को नया मास्टर बनने के लिए पदोन्नत किया जा सकता है और बिना किसी रुकावट के डेटा की सेवा जारी रख सकता है।

Redis की सरलता को देखते हुए, कई उच्च-उपलब्धता उपकरण उपलब्ध हैं जो मास्टर-स्लेव प्रतिकृति कॉन्फ़िगरेशन की निगरानी और प्रबंधन कर सकते हैं। हालांकि, रेडिस के साथ बंडल में आने वाला सबसे आम एचए समाधान रेडिस सेंटिनल्स है। Redis Sentinels अलग-अलग प्रक्रियाओं के एक सेट के रूप में चलते हैं जो संयोजन में Redis मास्टर-स्लेव सेट की निगरानी करते हैं और स्वचालित विफलता और पुन:कॉन्फ़िगरेशन प्रदान करते हैं।

Redis Sentinels के माध्यम से कनेक्ट करना

Redis Sentinels मास्टर-स्लेव सेट के लिए कॉन्फ़िगरेशन प्रदाता के रूप में भी कार्य करता है। यही है, रेडिस क्लाइंट मास्टर / स्लेव प्रतिकृति सेट के वर्तमान मास्टर और सामान्य स्वास्थ्य का पता लगाने के लिए रेडिस प्रहरी से जुड़ सकता है। रेडिस प्रलेखन विवरण प्रदान करता है कि ग्राहकों को प्रहरी के साथ कैसे बातचीत करनी चाहिए। हालांकि, रेडिस से जुड़ने के इस तंत्र में कुछ कमियां हैं:

  • क्लाइंट सपोर्ट की जरूरत है :रेडिस प्रहरी से कनेक्शन के लिए एक प्रहरी "जागरूक" क्लाइंट की आवश्यकता होती है। सबसे लोकप्रिय रेडिस क्लाइंट ने अब रेडिस सेंटिनल्स का समर्थन करना शुरू कर दिया है, लेकिन कुछ अभी भी नहीं करते हैं। उदाहरण के लिए, node_redis (Node.js), phpredis (PHP) और scala-redis (Scala) कुछ अनुशंसित क्लाइंट हैं जिनके पास अभी भी Redis Sentinel समर्थन नहीं है।
  • जटिलता :रेडिस सेंटिनल्स को कॉन्फ़िगर करना और कनेक्ट करना हमेशा सीधा नहीं होता है, खासकर जब तैनाती डेटा केंद्रों या उपलब्धता क्षेत्रों में होती है। उदाहरण के लिए, प्रहरी उन सभी डेटा सर्वरों और प्रहरी के आईपी पते (डीएनएस नाम नहीं) याद रखते हैं जो वे कभी भी आते हैं और जब डेटा केंद्रों में नोड्स गतिशील रूप से चले जाते हैं तो गलत तरीके से कॉन्फ़िगर हो सकते हैं। रेडिस प्रहरी भी अन्य प्रहरी के साथ आईपी जानकारी साझा करते हैं। दुर्भाग्य से, वे स्थानीय आईपी के आसपास से गुजरते हैं जो क्लाइंट के एक अलग डेटा सेंटर में होने पर समस्याग्रस्त हो सकता है। ये मुद्दे संचालन और विकास दोनों में महत्वपूर्ण जटिलताएं जोड़ सकते हैं।
  • सुरक्षा :रेडिस सर्वर स्वयं सर्वर पासवर्ड के माध्यम से आदिम प्रमाणीकरण प्रदान करता है, प्रहरी के पास स्वयं ऐसी कोई सुविधा नहीं है। तो एक रेडिस सेंटिनल जो इंटरनेट के लिए खुला है, उन सभी मास्टर्स की संपूर्ण कॉन्फ़िगरेशन जानकारी को उजागर करता है जिसे इसे प्रबंधित करने के लिए कॉन्फ़िगर किया गया है। इस प्रकार Redis Sentinels को हमेशा सही ढंग से कॉन्फ़िगर किए गए फ़ायरवॉल के पीछे तैनात किया जाना चाहिए। विशेष रूप से मल्टी-ज़ोन कॉन्फ़िगरेशन के लिए फ़ायरवॉल कॉन्फ़िगरेशन को ठीक करना वास्तव में मुश्किल हो सकता है।

एकल समापन बिंदु

मास्टर-स्लेव सेट के लिए एकल नेटवर्क कनेक्शन एंडपॉइंट कई तरीकों से प्रदान किया जा सकता है। यह वर्चुअल आईपी या डीएनएस नामों की रीमैपिंग या रेडिस सर्वर के सामने प्रॉक्सी सर्वर (जैसे HAProxy) का उपयोग करके किया जा सकता है। जब भी वर्तमान मास्टर की विफलता का पता चलता है (सेंटिनल द्वारा), आईपी या डीएनएस नाम दास को विफल कर दिया जाता है जिसे रेडिस सेंटिनल्स द्वारा नया मास्टर बनने के लिए पदोन्नत किया गया है। ध्यान दें कि इसमें समय लगता है और एंडपॉइंट से नेटवर्क कनेक्शन को फिर से स्थापित करने की आवश्यकता होगी। Redis Sentinels एक मास्टर को डाउन के रूप में तभी पहचानता है जब वह कुछ समय के लिए डाउन हो जाता है (डिफ़ॉल्ट 30 सेकंड) और फिर एक गुलाम को बढ़ावा देने के लिए वोट करता है। एक दास के प्रचार पर, आईपी पते/डीएनएस प्रविष्टि/प्रॉक्सी को नए मास्टर को इंगित करने के लिए बदलना होगा।

मास्टर-स्लेव सेट से कनेक्ट करना

एक ही समापन बिंदु का उपयोग करते हुए मास्टर-स्लेव प्रतिकृति सेट से कनेक्ट करते समय महत्वपूर्ण विचार यह है कि किसी भी कनेक्शन विफलताओं के लिए स्वचालित विफलता के दौरान समायोजित करने के लिए कनेक्शन विफलताओं पर पुन:प्रयास के लिए प्रावधान करना चाहिए प्रतिकृति सेट।

हम इसे Java, Ruby, और Node.js में उदाहरणों के साथ दिखाएंगे। प्रत्येक उदाहरण में, हम वैकल्पिक रूप से HA Redis क्लस्टर से लिखते और पढ़ते हैं जबकि पृष्ठभूमि में एक विफलता होती है। वास्तविक दुनिया में, पुन:प्रयास करने के प्रयास विशेष अवधि या गणना तक सीमित रहेंगे

जावा से जुड़ना

Redis के लिए जेडिस अनुशंसित जावा क्लाइंट है।

एकल समापन बिंदु उदाहरण

public class JedisTestSingleEndpoint {
...
    public static final String HOSTNAME = "SG-cluster0-single-endpoint.example.com";
    public static final String PASSWORD = "foobared";
...
    private void runTest() throws InterruptedException {
        boolean writeNext = true;
        Jedis jedis = null;
        while (true) {
            try {
                jedis = new Jedis(HOSTNAME);
                jedis.auth(PASSWORD);
                Socket socket = jedis.getClient().getSocket();
                printer("Connected to " + socket.getRemoteSocketAddress());
                while (true) {
                    if (writeNext) {
                        printer("Writing...");
                        jedis.set("java-key-999", "java-value-999");
                        writeNext = false;
                    } else {
                        printer("Reading...");
                        jedis.get("java-key-999");
                        writeNext = true;
                    }
                    Thread.sleep(2 * 1000);
                }
            } catch (JedisException e) {
                printer("Connection error of some sort!");
                printer(e.getMessage());
                Thread.sleep(2 * 1000);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
        }
    }
...
}

विफलता के दौरान इस परीक्षण कोड का आउटपुट ऐसा दिखता है:

Wed Sep 28 10:57:28 IST 2016: Initializing...
Wed Sep 28 10:57:31 IST 2016: Connected to SG-cluster0-single-endpoint.example.com/54.71.60.125:6379 << Connected to node 1
Wed Sep 28 10:57:31 IST 2016: Writing...
Wed Sep 28 10:57:33 IST 2016: Reading...
..
Wed Sep 28 10:57:50 IST 2016: Reading...
Wed Sep 28 10:57:52 IST 2016: Writing...
Wed Sep 28 10:57:53 IST 2016: Connection error of some sort! << Master went down!
Wed Sep 28 10:57:53 IST 2016: Unexpected end of stream.
Wed Sep 28 10:57:58 IST 2016: Connected to SG-cluster0-single-endpoint.example.com/54.71.60.125:6379
Wed Sep 28 10:57:58 IST 2016: Writing...
Wed Sep 28 10:57:58 IST 2016: Connection error of some sort!
Wed Sep 28 10:57:58 IST 2016: java.net.SocketTimeoutException: Read timed out  << Old master is unreachable
Wed Sep 28 10:58:02 IST 2016: Connected to SG-cluster0-single-endpoint.example.com/54.71.60.125:6379
Wed Sep 28 10:58:02 IST 2016: Writing...
Wed Sep 28 10:58:03 IST 2016: Connection error of some sort!
...
Wed Sep 28 10:59:10 IST 2016: Connected to SG-cluster0-single-endpoint.example.com/54.214.164.243:6379  << New master ready. Connected to node 2
Wed Sep 28 10:59:10 IST 2016: Writing...
Wed Sep 28 10:59:12 IST 2016: Reading...

यह एक साधारण परीक्षण कार्यक्रम है। वास्तविक जीवन में, पुनर्प्रयासों की संख्या अवधि या गणना के अनुसार निर्धारित की जाएगी।

रेडिस सेंटिनल उदाहरण

जेडिस रेडिस सेंटिनल्स का भी समर्थन करता है। तो यहाँ वह कोड है जो उपरोक्त उदाहरण के समान काम करता है लेकिन प्रहरी से जुड़कर।

public class JedisTestSentinelEndpoint {
    private static final String MASTER_NAME = "mymaster";
    public static final String PASSWORD = "foobared";
    private static final Set sentinels;
    static {
        sentinels = new HashSet();
        sentinels.add("mymaster-0.servers.example.com:26379");
        sentinels.add("mymaster-1.servers.example.com:26379");
        sentinels.add("mymaster-2.servers.example.com:26379");
    }

    public JedisTestSentinelEndpoint() {
    }

    private void runTest() throws InterruptedException {
        boolean writeNext = true;
        JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels);
        Jedis jedis = null;
        while (true) {
            try {
                printer("Fetching connection from pool");
                jedis = pool.getResource();
                printer("Authenticating...");
                jedis.auth(PASSWORD);
                printer("auth complete...");
                Socket socket = jedis.getClient().getSocket();
                printer("Connected to " + socket.getRemoteSocketAddress());
                while (true) {
                    if (writeNext) {
                        printer("Writing...");
                        jedis.set("java-key-999", "java-value-999");
                        writeNext = false;
                    } else {
                        printer("Reading...");
                        jedis.get("java-key-999");
                        writeNext = true;
                    }
                    Thread.sleep(2 * 1000);
                }
            } catch (JedisException e) {
                printer("Connection error of some sort!");
                printer(e.getMessage());
                Thread.sleep(2 * 1000);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
        }
    }
...
}

आइए प्रहरी प्रबंधित विफलता के दौरान उपरोक्त कार्यक्रम के व्यवहार को देखें:

Wed Sep 28 14:43:42 IST 2016: Initializing...
Sep 28, 2016 2:43:42 PM redis.clients.jedis.JedisSentinelPool initSentinels
INFO: Trying to find master from available Sentinels...
Sep 28, 2016 2:43:42 PM redis.clients.jedis.JedisSentinelPool initSentinels
INFO: Redis master running at 54.71.60.125:6379, starting Sentinel listeners...
Sep 28, 2016 2:43:43 PM redis.clients.jedis.JedisSentinelPool initPool
INFO: Created JedisPool to master at 54.71.60.125:6379
Wed Sep 28 14:43:43 IST 2016: Fetching connection from pool
Wed Sep 28 14:43:43 IST 2016: Authenticating...
Wed Sep 28 14:43:43 IST 2016: auth complete...
Wed Sep 28 14:43:43 IST 2016: Connected to /54.71.60.125:6379
Wed Sep 28 14:43:43 IST 2016: Writing...
Wed Sep 28 14:43:45 IST 2016: Reading...
Wed Sep 28 14:43:48 IST 2016: Writing...
Wed Sep 28 14:43:50 IST 2016: Reading...
Sep 28, 2016 2:43:51 PM redis.clients.jedis.JedisSentinelPool initPool
INFO: Created JedisPool to master at 54.214.164.243:6379
Wed Sep 28 14:43:52 IST 2016: Writing...
Wed Sep 28 14:43:55 IST 2016: Reading...
Wed Sep 28 14:43:57 IST 2016: Writing...
Wed Sep 28 14:43:59 IST 2016: Reading...
Wed Sep 28 14:44:02 IST 2016: Writing...
Wed Sep 28 14:44:02 IST 2016: Connection error of some sort!
Wed Sep 28 14:44:02 IST 2016: Unexpected end of stream.
Wed Sep 28 14:44:04 IST 2016: Fetching connection from pool
Wed Sep 28 14:44:04 IST 2016: Authenticating...
Wed Sep 28 14:44:04 IST 2016: auth complete...
Wed Sep 28 14:44:04 IST 2016: Connected to /54.214.164.243:6379
Wed Sep 28 14:44:04 IST 2016: Writing...
Wed Sep 28 14:44:07 IST 2016: Reading...
...

जैसा कि लॉग से स्पष्ट है, एक क्लाइंट जो सेंटिनल्स का समर्थन करता है, एक विफलता घटना से काफी जल्दी ठीक हो सकता है।

रूबी से जुड़ना

Redis-rb, Redis के लिए अनुशंसित रूबी क्लाइंट है।

एकल समापन बिंदु उदाहरण

require 'redis'

HOST = "SG-cluster0-single-endpoint.example.com"
AUTH = "foobared"
...

def connect_and_write
  while true do
    begin
      logmsg "Attempting to establish connection"
      redis = Redis.new(:host => HOST, :password => AUTH)
      redis.ping
      sock = redis.client.connection.instance_variable_get(:@sock)
      logmsg "Connected to #{sock.remote_address.ip_address}, DNS: #{sock.remote_address.getnameinfo}"
      while true do
        if $writeNext
          logmsg "Writing..."
          redis.set("ruby-key-1000", "ruby-value-1000")
          $writeNext = false
        else
          logmsg "Reading..."
          redis.get("ruby-key-1000")
          $writeNext = true
        end
        sleep(2)
      end
    rescue Redis::BaseError => e
      logmsg "Connection error of some sort!"
      logmsg e.message
      sleep(2)
    end
  end
end

...
logmsg "Initiaing..."
connect_and_write

यहां एक विफलता के दौरान नमूना आउटपुट दिया गया है:

"2016-09-28 11:36:42 +0530: Initiaing..."
"2016-09-28 11:36:42 +0530: Attempting to establish connection"
"2016-09-28 11:36:44 +0530: Connected to 54.71.60.125, DNS: [\"ec2-54-71-60-125.us-west-2.compute.amazonaws.com\", \"6379\"] " << Connected to node 1
"2016-09-28 11:36:44 +0530: Writing..."
"2016-09-28 11:36:47 +0530: Reading..."
...
"2016-09-28 11:37:08 +0530: Writing..."
"2016-09-28 11:37:09 +0530: Connection error of some sort!"  << Master went down!
...
"2016-09-28 11:38:13 +0530: Attempting to establish connection"
"2016-09-28 11:38:15 +0530: Connected to 54.214.164.243, DNS: [\"ec2-54-214-164-243.us-west-2.compute.amazonaws.com\", \"6379\"] " << Connected to node 2
"2016-09-28 11:38:15 +0530: Writing..."
"2016-09-28 11:38:17 +0530: Reading..."

फिर से, वास्तविक कोड में सीमित संख्या में पुनर्प्रयास होने चाहिए।

रेडिस सेंटिनल उदाहरण

Redis-rb सेंटिनल्स को भी सपोर्ट करता है।

AUTH = 'foobared'

SENTINELS = [
  {:host => "mymaster0.servers.example.com", :port => 26379},
  {:host => "mymaster0.servers.example.com", :port => 26379},
  {:host => "mymaster0.servers.example.com", :port => 26379}
]
MASTER_NAME = "mymaster0"

$writeNext = true
def connect_and_write
  while true do
    begin
      logmsg "Attempting to establish connection"
      redis = Redis.new(:url=> "redis://#{MASTER_NAME}", :sentinels => SENTINELS, :password => AUTH)
      redis.ping
      sock = redis.client.connection.instance_variable_get(:@sock)
      logmsg "Connected to #{sock.remote_address.ip_address}, DNS: #{sock.remote_address.getnameinfo} "
      while true do
        if $writeNext
          logmsg "Writing..."
          redis.set("ruby-key-1000", "ruby-val-1000")
          $writeNext = false
        else
          logmsg "Reading..."
          redis.get("ruby-key-1000")
          $writeNext = true
        end
        sleep(2)
      end
    rescue Redis::BaseError => e
      logmsg "Connection error of some sort!"
      logmsg e.message
      sleep(2)
    end
  end
end

Redis-rb बिना किसी व्यवधान के प्रहरी विफलताओं को प्रबंधित करता है।

"2016-09-28 15:10:56 +0530: Initiaing..."
"2016-09-28 15:10:56 +0530: Attempting to establish connection"
"2016-09-28 15:10:58 +0530: Connected to 54.214.164.243, DNS: [\"ec2-54-214-164-243.us-west-2.compute.amazonaws.com\", \"6379\"] "
"2016-09-28 15:10:58 +0530: Writing..."
"2016-09-28 15:11:00 +0530: Reading..."
"2016-09-28 15:11:03 +0530: Writing..."
"2016-09-28 15:11:05 +0530: Reading..."
"2016-09-28 15:11:07 +0530: Writing..."
...
<<failover>>
...
"2016-09-28 15:11:10 +0530: Reading..."
"2016-09-28 15:11:12 +0530: Writing..."
"2016-09-28 15:11:14 +0530: Reading..."
"2016-09-28 15:11:17 +0530: Writing..."
...
# No disconnections noticed at all by the application

Node.js से जुड़ना

Node_redis Redis के लिए अनुशंसित Node.js क्लाइंट है।

एकल समापन बिंदु उदाहरण

...
var redis = require("redis");
var hostname = "SG-cluster0-single-endpoint.example.com";
var auth = "foobared";
var client = null;
...

function readAndWrite() {
  if (!client || !client.connected) {
    client = redis.createClient({
      'port': 6379,
      'host': hostname,
      'password': auth,
      'retry_strategy': function(options) {
        printer("Connection failed with error: " + options.error);
        if (options.total_retry_time > 1000 * 60 * 60) {
          return new Error('Retry time exhausted');
        }
        return new Error('retry strategy: failure');
      }});
    client.on("connect", function () {
      printer("Connected to " + client.address + "/" + client.stream.remoteAddress + ":" + client.stream.remotePort);
    });
    client.on('error', function (err) {
      printer("Error event: " + err);
      client.quit();
    });
  }

  if (writeNext) {
    printer("Writing...");
    client.set("node-key-1001", "node-value-1001", function(err, res) {
      if (err) {
        printer("Error on set: " + err);
        client.quit();
      }
      setTimeout (readAndWrite, 2000)
    });

    writeNext = false;
  } else {
    printer("Reading...");
    client.get("node-key-1001", function(err, res) {
      if (err) {
        client.quit();
        printer("Error on get: " + err);
      }
      setTimeout (readAndWrite, 2000)
    });
    writeNext = true;
  }
}
...
setTimeout(readAndWrite, 2000);
...

यहां बताया गया है कि फेलओवर कैसा दिखेगा:

2016-09-28T13:29:46+05:30: Writing...
2016-09-28T13:29:47+05:30: Connected to SG-meh0-6-master.devservers.mongodirector.com:6379/54.214.164.243:6379 << Connected to node 1
2016-09-28T13:29:50+05:30: Reading...
...
2016-09-28T13:30:02+05:30: Writing...
2016-09-28T13:30:04+05:30: Reading...
2016-09-28T13:30:06+05:30: Connection failed with error: null << Master went down
...
2016-09-28T13:30:50+05:30: Connected to SG-meh0-6-master.devservers.mongodirector.com:6379/54.71.60.125:6379 << Connected to node 2
2016-09-28T13:30:52+05:30: Writing...
2016-09-28T13:30:55+05:30: Reading...

आप अपनी आवश्यकताओं को पूरा करने के लिए पुनः प्रयास तर्क को बदलने के लिए कनेक्शन निर्माण के दौरान 'retry_strategy' विकल्प के साथ प्रयोग भी कर सकते हैं। क्लाइंट दस्तावेज़ीकरण का एक उदाहरण है।

रेडिस सेंटिनल उदाहरण

Node_redis वर्तमान में प्रहरी का समर्थन नहीं करता है, लेकिन Node.js के लिए लोकप्रिय Redis क्लाइंट, ioredis प्रहरी का समर्थन करता है। Node.js से प्रहरी से कैसे जुड़ें, इस पर इसके दस्तावेज़ देखें।

बढ़ाने के लिए तैयार हैं? हम आपकी पसंद के क्लाउड पर Redis™* के लिए होस्टिंग और पूरी तरह से प्रबंधित समाधान प्रदान करते हैं। दूसरों से हमारी तुलना करें और देखें कि हम आपको परेशानी और नकदी क्यों बचाते हैं।


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. लुआसॉकेट, लुआ 5.2 और रेडिस

  2. माध्यमिक सूचकांक पर रेडिस समर्थन

  3. निष्पादन का रेडिस पाइपलाइन आदेश

  4. एक ही कार्य को कई बार निष्पादित किया गया

  5. क्या मैं रूबी डाइजेस्ट ::SHA1 इंस्टेंस ऑब्जेक्ट को क्रमबद्ध कर सकता हूं?