redis-ha 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in redis-ha.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 John Maxwell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # RedisHA
2
+
3
+ THIS IS CURRENTLY NOT FUNCTIONING - IN DEVELOPMENT ONLY
4
+
5
+ RedisHA is a Highly Available solution for running Redis under situations other than as a cacheing layer, specifically for where single server operations are required and thus sharding is not an option (e.g. Queueing, Lua based ops).
6
+
7
+ RedisHA consists of two parts - a Router and a Manager.
8
+
9
+ ## Router
10
+
11
+ The Router layer acts as a single interface point to your Redis installations, and is essentially a high-performance reverse proxy layer to your Redis installations.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'redis-ha'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install redis-ha
26
+
27
+ ## Usage
28
+
29
+ TODO: Write usage instructions here
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/redis-ha ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path("../../lib", __FILE__)
4
+ $:.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'redis-ha'
7
+ require 'redis_ha/router'
8
+ require 'optparse'
9
+
10
+ options = {:debug => false, :hashing => false}
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: redis-ha [options]"
13
+
14
+ opts.on("-l", "--listen [PORT]", Integer, "Port to listen on") do |v|
15
+ options[:port] = v || 7379
16
+ end
17
+
18
+ opts.on("-b", "--bind [IP]", String, "Interface to bind to") do |v|
19
+ options[:bind] = v || "0.0.0.0"
20
+ end
21
+
22
+ opts.on("-s", "--servers [hostname:port]", String, "Servers to bind to") do |v|
23
+ options[:servers] = v
24
+ end
25
+
26
+ opts.on("-h", "--hashing", "Enable consistent hashing") do |v|
27
+ options[:hashing] = v
28
+ end
29
+
30
+ opts.on("-d", "--debug", "Enable debug mode") do |v|
31
+ options[:debug] = v
32
+ end
33
+
34
+ end.parse!
35
+
36
+ RedisHA::Router.start(options[:bind], options[:port], options) do |run|
37
+ servers = if options[:servers].include?(",")
38
+ options[:servers].split(",")
39
+ else
40
+ [options[:servers]]
41
+ end
42
+ servers.each do |serv|
43
+ host, port = serv.split(":")
44
+ run.upstream(:relay, host: host, port: port.to_i)
45
+ end
46
+ run.on_data do |data|
47
+ data
48
+ end
49
+
50
+ run.on_response do |upstream, response|
51
+ response if upstream == :relay
52
+ end
53
+
54
+ run.on_finish do |upstream|
55
+ :close if upstream == :relay
56
+ end
57
+ end
data/lib/redis-ha.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'redis_ha/version'
2
+ require 'redis_ha/logger'
3
+
4
+ module RedisHA
5
+ end
@@ -0,0 +1,18 @@
1
+ require 'active_support/concern'
2
+ require 'logger'
3
+
4
+ module RedisHA
5
+ module Logger
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ def logger
10
+ @logger ||= begin
11
+ log = ::Logger.new(STDOUT)
12
+ log.level = (@debug ? ::Logger::DEBUG : ::Logger::INFO)
13
+ log
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ require 'eventmachine'
2
+ require 'socket'
3
+
4
+ require 'redis_ha/router/upstream'
5
+ require 'redis_ha/router/connection'
6
+
7
+ module RedisHA
8
+ module Router
9
+
10
+ def self.start host, port, options={}, &block
11
+ EM.epoll
12
+ EM.run do
13
+ trap("TERM") { stop }
14
+ trap("INT") { stop }
15
+
16
+ EventMachine::start_server(host, port, RedisHA::Router::Connection, options[:debug]) do |serv|
17
+ serv.instance_eval &block
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.stop
23
+ EventMachine.stop
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,101 @@
1
+ module RedisHA
2
+ module Router
3
+ class Connection < EventMachine::Connection
4
+ include RedisHA::Logger
5
+
6
+ def on_data(&block); @on_data = block; end
7
+ def on_response(&block); @on_response = block; end
8
+ def on_finish(&block); @on_finish = block; end
9
+ def on_connect(&block); @on_connect = block; end
10
+
11
+ def initialize(debug_on=false)
12
+ @debug = debug_on
13
+ @upstreams = {}
14
+ end
15
+
16
+ def receive_data data
17
+ logger.debug [:connection, data]
18
+ processed = @on_data.call(data) if @on_data
19
+
20
+ return if processed == :async or processed.nil?
21
+ relay_to_upstreams(processed)
22
+ end
23
+
24
+ def relay_to_upstreams processed
25
+ if processed.is_a? Array
26
+ data, servers = *processed
27
+ servers = servers.collect {|s| @upstreams[s]}.compact
28
+ else
29
+ data = processed
30
+ servers ||= @upstreams.values.compact
31
+ end
32
+
33
+ servers.each do |s|
34
+ s.send_data data unless data.nil?
35
+ end
36
+ end
37
+
38
+ def upstream name, options
39
+ serv = EventMachine::bind_connect(*build_upstream_signature(options)) do |c|
40
+ c.name = name
41
+ c.plexer = self
42
+ c.proxy_incoming_to(self, 10240) if options[:relay_server]
43
+ end
44
+
45
+ self.proxy_incoming_to(serv, 10240) if options[:relay_client]
46
+
47
+ @upstreams[name] = serv
48
+ end
49
+
50
+ def peer
51
+ @peer ||= begin
52
+ peername = get_peername
53
+ peername ? Socket.unpack_sockaddr_in(peername).reverse : nil
54
+ end
55
+ end
56
+
57
+ def relay_from_upstream name, data
58
+ logger.debug [:relay_from_upsteam, name, data]
59
+ data = @on_response.call(name, data) if @on_response
60
+ send_data data unless data.nil?
61
+ end
62
+
63
+ def connected name
64
+ logger.debug [:connected]
65
+ @on_connect.call(name) if @on_connect
66
+ end
67
+
68
+ def unbind
69
+ logger.debug [:unbind, :connection]
70
+
71
+ @upstreams.values.compact.each do |serv|
72
+ serv.close_connection
73
+ end
74
+ end
75
+
76
+ def unbind_backend name
77
+ logger.debug [:unbind_backend, name]
78
+ @upstreams[name] = nil
79
+ close = :close
80
+
81
+ if @on_finish
82
+ close = @on_finish.call(name)
83
+ end
84
+
85
+ if (@upstreams.values.compact.size.zero? && close != :keep) || close == :close
86
+ close_connection_after_writing
87
+ end
88
+ end
89
+
90
+ private
91
+ def build_upstream_signature options
92
+ [options[:bind_host],
93
+ options[:bind_port],
94
+ options[:host],
95
+ options[:port],
96
+ RedisHA::Router::Upstream,
97
+ @debug]
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,34 @@
1
+ module RedisHA
2
+ module Router
3
+ class Upstream < EventMachine::Connection
4
+ include RedisHA::Logger
5
+
6
+ attr_accessor :plexer, :name, :debug
7
+
8
+ def initialize debug_on=false
9
+ @debug = debug_on
10
+ @connected = EM::DefaultDeferrable.new
11
+ end
12
+
13
+ def connection_completed
14
+ logger.debug [@name, :conn_complete]
15
+ @plexer.connected(@name)
16
+ @connected.succeed
17
+ end
18
+
19
+ def receive_data data
20
+ logger.debug [@name, data]
21
+ @plexer.relay_from_upstream(@name, data)
22
+ end
23
+
24
+ def send data
25
+ @connected.callback { send_data data }
26
+ end
27
+
28
+ def ubind
29
+ logger.debug [@name, :unbind]
30
+ @plexer.unbind_backend(@name)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module RedisHA
2
+ VERSION = "0.0.1"
3
+ end
data/redis-ha.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'redis_ha/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "redis-ha"
8
+ spec.version = RedisHA::VERSION
9
+ spec.authors = ["John Maxwell"]
10
+ spec.email = ["john@musicglue.com"]
11
+ spec.description = %q{RedisHA is an attempt at a highly available Redis Installation}
12
+ spec.summary = %q{See Description}
13
+ spec.homepage = "http://musicglue.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "eventmachine"
25
+ spec.add_dependency "activesupport"
26
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-ha
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - John Maxwell
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ none: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ none: false
28
+ prerelease: false
29
+ type: :development
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ none: false
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ none: false
44
+ prerelease: false
45
+ type: :development
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ none: false
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ none: false
60
+ prerelease: false
61
+ type: :runtime
62
+ - !ruby/object:Gem::Dependency
63
+ name: activesupport
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ none: false
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ none: false
76
+ prerelease: false
77
+ type: :runtime
78
+ description: RedisHA is an attempt at a highly available Redis Installation
79
+ email:
80
+ - john@musicglue.com
81
+ executables:
82
+ - redis-ha
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - bin/redis-ha
92
+ - lib/redis-ha.rb
93
+ - lib/redis_ha/logger.rb
94
+ - lib/redis_ha/router.rb
95
+ - lib/redis_ha/router/connection.rb
96
+ - lib/redis_ha/router/upstream.rb
97
+ - lib/redis_ha/version.rb
98
+ - redis-ha.gemspec
99
+ homepage: http://musicglue.com
100
+ licenses:
101
+ - MIT
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ hash: 2179501369200017504
111
+ segments:
112
+ - 0
113
+ version: '0'
114
+ none: false
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ hash: 2179501369200017504
120
+ segments:
121
+ - 0
122
+ version: '0'
123
+ none: false
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.25
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: See Description
130
+ test_files: []