Class: RedisFailover::Client

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/redis_failover/client.rb

Overview

Redis failover-aware client. RedisFailover::Client is a wrapper over a set of underlying redis clients, which means all normal redis operations can be performed on an instance of this class. The class only requires a set of ZooKeeper server addresses to function properly. The client will automatically retry failed operations, and handle failover to a new master. The client registers and listens for watcher events from the Node Manager. When these events are received, the client fetches the latest set of redis nodes from ZooKeeper and rebuilds its internal Redis clients appropriately. RedisFailover::Client also directs write operations to the master, and all read operations to the slaves.

Examples:

Usage

zk_servers = 'localhost:2181,localhost:2182,localhost:2183'
client = RedisFailover::Client.new(:zkservers => zk_servers)
client.set('foo', 1) # will be directed to master
client.get('foo') # will be directed to a slave

Constant Summary collapse

ZNODE_UPDATE_TIMEOUT =

Maximum allowed elapsed time between notifications from the Node Manager. When this timeout is reached, the client will raise a NoNodeManagerError and purge its internal redis clients.

9
RETRY_WAIT_TIME =

Amount of time to sleep before retrying a failed operation.

3
REDIS_READ_OPS =

Redis read operations that are automatically dispatched to slaves. Any operation not listed here will be dispatched to the master.

Set[
  :echo,
  :exists,
  :get,
  :getbit,
  :getrange,
  :hexists,
  :hget,
  :hgetall,
  :hkeys,
  :hlen,
  :hmget,
  :hvals,
  :keys,
  :lindex,
  :llen,
  :lrange,
  :mapped_hmget,
  :mapped_mget,
  :mget,
  :scard,
  :sdiff,
  :sinter,
  :sismember,
  :smembers,
  :srandmember,
  :strlen,
  :sunion,
  :type,
  :zcard,
  :zcount,
  :zrange,
  :zrangebyscore,
  :zrank,
  :zrevrange,
  :zrevrangebyscore,
  :zrevrank,
  :zscore
].freeze
UNSUPPORTED_OPS =

Unsupported Redis operations. These don't make sense in a client that abstracts the master/slave servers.

Set[:select, :dbsize].freeze

Constants included from Util

Util::CONNECTIVITY_ERRORS, Util::DEFAULT_ZNODE_PATH, Util::REDIS_ERRORS

Instance Method Summary collapse

Methods included from Util

#decode, #different?, #encode, logger, #logger, logger=, #symbolize_keys

Constructor Details

#initialize(options = {}) ⇒ RedisFailover::Client

Creates a new failover redis client.

Parameters:

  • options (Hash) (defaults to: {})

    the options used to initialize the client instance

Options Hash (options):

  • :zkservers (String)

    comma-separated ZooKeeper host:port

  • :znode_path (String)

    znode path override for redis nodes

  • :password (String)

    password for redis nodes

  • :db (String)

    database to use for redis nodes

  • :namespace (String)

    namespace for redis nodes

  • :logger (Logger)

    logger override

  • :retry_failure (Boolean)

    indicates if failures are retried

  • :max_retries (Integer)

    max retries for a failure



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/redis_failover/client.rb', line 97

def initialize(options = {})
  Util.logger = options[:logger] if options[:logger]
  @zkservers = options.fetch(:zkservers) { raise ArgumentError, ':zkservers required'}
  @znode = options[:znode_path] || Util::DEFAULT_ZNODE_PATH
  @namespace = options[:namespace]
  @password = options[:password]
  @db = options[:db]
  @retry = options[:retry_failure] || true
  @max_retries = @retry ? options.fetch(:max_retries, 3) : 0
  @master = nil
  @slaves = []
  @node_addresses = {}
  @lock = Monitor.new
  @current_client_key = "current-client-#{self.object_id}"
  setup_zk
  build_clients
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Dispatches redis operations to master/slaves.



116
117
118
119
120
121
122
# File 'lib/redis_failover/client.rb', line 116

def method_missing(method, *args, &block)
  if redis_operation?(method)
    dispatch(method, *args, &block)
  else
    super
  end
end

Instance Method Details

#inspectString Also known as: to_s

Returns a string representation of the client.

Returns:

  • (String)

    a string representation of the client



134
135
136
# File 'lib/redis_failover/client.rb', line 134

def inspect
  "#<RedisFailover::Client (master: #{master_name}, slaves: #{slave_names})>"
end

#manual_failover(options = {}) ⇒ Object

Force a manual failover to a new server. A specific server can be specified via options. If no options are passed, a random slave will be selected as the candidate for the new master.

Parameters:

  • options (Hash) (defaults to: {})

    the options used for manual failover

Options Hash (options):

  • :host (String)

    the host of the failover candidate

  • :port (String)

    the port of the failover candidate



146
147
148
149
# File 'lib/redis_failover/client.rb', line 146

def manual_failover(options = {})
  ManualFailover.new(@zk, options).perform
  self
end

#reconnectObject

Reconnect will first perform a shutdown of the underlying redis clients. Next, it attempts to reopen the ZooKeeper client and re-create the redis clients after it fetches the most up-to-date list from ZooKeeper.



165
166
167
168
169
# File 'lib/redis_failover/client.rb', line 165

def reconnect
  purge_clients
  @zk ? @zk.reopen : setup_zk
  build_clients
end

#respond_to_missing?(method, include_private) ⇒ Boolean

Determines whether or not an unknown method can be handled.

Parameters:

  • method (Symbol)

    the method to check

  • include_private (Boolean)

    determines if private methods are checked

Returns:

  • (Boolean)

    indicates if the method can be handled



129
130
131
# File 'lib/redis_failover/client.rb', line 129

def respond_to_missing?(method, include_private)
  redis_operation?(method) || super
end

#shutdownObject

Gracefully performs a shutdown of this client. This method is mostly useful when the client is used in a forking environment. When a fork occurs, you can call this method in an after_fork hook, and then create a new instance of the client. The underlying ZooKeeper client and redis clients will be closed.



156
157
158
159
160
# File 'lib/redis_failover/client.rb', line 156

def shutdown
  @zk.close! if @zk
  @zk = nil
  purge_clients
end