galerab 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/galerab +67 -0
- data/files/galerab +22 -0
- data/files/galerab.yml +17 -0
- data/lib/galerab.rb +10 -0
- data/lib/galerab/backend.rb +25 -0
- data/lib/galerab/balancing_proxy.rb +68 -0
- data/lib/galerab/configuration.rb +7 -0
- data/lib/galerab/proxy.rb +16 -0
- data/spec/lib/backend_spec.rb +55 -0
- data/spec/lib/configuration_spec.rb +33 -0
- data/spec/spec_helper.rb +8 -0
- metadata +160 -0
data/bin/galerab
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'galerab'
|
4
|
+
|
5
|
+
path = ARGV.include?('-c') && ARGV[ARGV.index('-c') + 1]
|
6
|
+
|
7
|
+
unless path
|
8
|
+
path = ENV['GALERAB_CONFIG_PATH']
|
9
|
+
|
10
|
+
unless path
|
11
|
+
puts "Missing path for configuration file"
|
12
|
+
puts "Usage: command -c path/file.yml"
|
13
|
+
abort
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
puts "[#{Process.pid}] galerab starting with config file at #{ARGV[1]}"
|
19
|
+
|
20
|
+
confs = Configuration.new(path).conf
|
21
|
+
|
22
|
+
confs.each do |conf|
|
23
|
+
backend = Backend.new(conf[1])
|
24
|
+
conf = conf[1]
|
25
|
+
|
26
|
+
fork do
|
27
|
+
t = Thread.new do
|
28
|
+
while true
|
29
|
+
# Here we check if the backend is ready
|
30
|
+
next_backend = backend.get_next
|
31
|
+
puts "\nChecking if (wsrep_ready == ON) #{next_backend}\n"
|
32
|
+
|
33
|
+
begin
|
34
|
+
Sequel.connect(
|
35
|
+
"mysql://#{conf["user"]}:#{conf["password"]}@#{next_backend}/#{conf["database"]}"
|
36
|
+
).fetch("show status like 'wsrep_ready'") do |row|
|
37
|
+
#row[:Value] = "OFF"
|
38
|
+
if row[:Value] == "OFF"
|
39
|
+
puts "#{next_backend} is not ready"
|
40
|
+
backend.not_ready.push(next_backend) unless backend.not_ready.include?(next_backend)
|
41
|
+
elsif row[:Value] == "ON"
|
42
|
+
puts "#{next_backend} is ready"
|
43
|
+
backend.not_ready.delete(next_backend) if backend.not_ready
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue
|
47
|
+
puts "#{next_backend} is not ready"
|
48
|
+
backend.not_ready.push(next_backend) unless backend.not_ready.include?(next_backend)
|
49
|
+
end
|
50
|
+
|
51
|
+
sleep conf["check_every"]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
t.join
|
56
|
+
BalancingProxy::Server.run(backend)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
trap (:SIGHUP) do
|
61
|
+
$stdout.puts "Received SIGHUP, reloading config file"
|
62
|
+
backend.conf = YAML.load_file(ARGV[1])
|
63
|
+
$stdout.puts backend.conf["balancer_ports"].inspect
|
64
|
+
end
|
65
|
+
|
66
|
+
# release child processes before exit
|
67
|
+
confs.each { |conf| Process.wait }
|
data/files/galerab
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
# Carry out specific functions when asked to by the system
|
4
|
+
case "$1" in
|
5
|
+
start)
|
6
|
+
echo "Starting script galerab "
|
7
|
+
nohup /usr/sbin/balancer </dev/null >/dev/null 2>&1 &
|
8
|
+
;;
|
9
|
+
stop)
|
10
|
+
echo "Stopping script galerab"
|
11
|
+
kill `ps -ef | grep balancer | grep -v grep | awk '{print $2}'`
|
12
|
+
reload)
|
13
|
+
echo "reloading script galerab"
|
14
|
+
kill -s SIGHUP `ps -ef | grep balancer | grep -v grep | awk '{print $2}'`
|
15
|
+
;;
|
16
|
+
*)
|
17
|
+
echo "Usage: /etc/init.d/galerab {start|stop}"
|
18
|
+
exit 1
|
19
|
+
;;
|
20
|
+
esac
|
21
|
+
|
22
|
+
exit 0
|
data/files/galerab.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
1:
|
2
|
+
backends: ["localhost"]
|
3
|
+
check_every: 10
|
4
|
+
user: root
|
5
|
+
password: root
|
6
|
+
database: mysql
|
7
|
+
balancer_port: 3307
|
8
|
+
backend_port: 3306
|
9
|
+
|
10
|
+
2:
|
11
|
+
backends: ["192.168.1.11"]
|
12
|
+
check_every: 10
|
13
|
+
user: root
|
14
|
+
password: root
|
15
|
+
database: mysql
|
16
|
+
balancer_port: 3308
|
17
|
+
backend_port: 3306
|
data/lib/galerab.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Backend
|
2
|
+
attr_accessor :not_ready, :conf
|
3
|
+
|
4
|
+
def initialize(conf)
|
5
|
+
@next_host = 0
|
6
|
+
@list = conf['backends']
|
7
|
+
@conf = conf
|
8
|
+
@not_ready = Array.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# round robin load-balancing
|
12
|
+
def get_next
|
13
|
+
@next_host = @next_host + 1
|
14
|
+
@next_host = 0 if @next_host >= @list.size
|
15
|
+
unless @not_ready.include?(@list[@next_host])
|
16
|
+
@list[@next_host]
|
17
|
+
else
|
18
|
+
begin
|
19
|
+
get_next
|
20
|
+
rescue SystemStackError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module BalancingProxy
|
2
|
+
extend self
|
3
|
+
|
4
|
+
# Callbacks for em-proxy events
|
5
|
+
#
|
6
|
+
module Callbacks
|
7
|
+
include ANSI::Code
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def on_select
|
11
|
+
lambda do |backend|
|
12
|
+
puts black_on_white { 'on_select'.ljust(12) } + " #{backend.inspect}"
|
13
|
+
backend.increment_counter if Backend.strategy == :balanced
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_connect
|
18
|
+
lambda do |backend|
|
19
|
+
puts black_on_magenta { 'on_connect'.ljust(12) } + ' ' + bold { backend }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_data
|
24
|
+
lambda do |data|
|
25
|
+
puts black_on_yellow { 'on_data'.ljust(12) }, data
|
26
|
+
data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_response
|
31
|
+
lambda do |backend, resp|
|
32
|
+
puts black_on_green { 'on_response'.ljust(12) } + " from #{backend}", resp
|
33
|
+
resp
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_finish
|
38
|
+
lambda do |backend|
|
39
|
+
puts black_on_cyan { 'on_finish'.ljust(12) } + " for #{backend}", ''
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module Server
|
46
|
+
def run(backend)
|
47
|
+
# run the proxy server and wait for connections
|
48
|
+
balancer_port = backend.conf["balancer_port"]
|
49
|
+
backend_port = backend.conf["backend_port"]
|
50
|
+
puts ANSI::Code.bold { "Launching proxy at 0.0.0.0:#{balancer_port}...\n" }
|
51
|
+
|
52
|
+
Proxy.start(:host => '0.0.0.0', :port => balancer_port, :debug => false) do |conn|
|
53
|
+
backend_host = backend.get_next
|
54
|
+
if backend_host
|
55
|
+
conn.server backend_host, :host => backend_host, :port => backend_port
|
56
|
+
puts ANSI::Code.bold { "Farwarding to #{backend_host}\n" }
|
57
|
+
|
58
|
+
conn.on_connect &Callbacks.on_connect
|
59
|
+
conn.on_data &Callbacks.on_data
|
60
|
+
conn.on_response &Callbacks.on_response
|
61
|
+
conn.on_finish &Callbacks.on_finish
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module_function :run
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Proxy
|
2
|
+
def self.stop
|
3
|
+
puts "Terminating ProxyServer"
|
4
|
+
EventMachine.stop
|
5
|
+
end
|
6
|
+
|
7
|
+
# this is not used
|
8
|
+
def self.kill_childs(servers, signal)
|
9
|
+
servers.each do |server|
|
10
|
+
puts "Killing process #{server[:pid]} with #{signal} signal."
|
11
|
+
Process.kill(signal, server[:pid])
|
12
|
+
end
|
13
|
+
|
14
|
+
Process.kill(signal, Process.pid)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuration do
|
4
|
+
before(:each) do
|
5
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when loading the file" do
|
9
|
+
it "should load the YAML file" do
|
10
|
+
@conf.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should find two balancers in the config file" do
|
14
|
+
@conf.size.should be == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gets the backends for balancer 1" do
|
18
|
+
@conf[1]['backends'].size.should be == 3
|
19
|
+
@conf[1]['backends'][0].should be == "192.168.10.101"
|
20
|
+
@conf[1]['backends'][1].should be == "192.168.10.102"
|
21
|
+
@conf[1]['backends'][2].should be == "192.168.10.103"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads the other parameters" do
|
25
|
+
@conf[1]['check_every'].size.should be == 8
|
26
|
+
@conf[1]['user'].should be == "your_user"
|
27
|
+
@conf[1]['password'].should be == "your_password"
|
28
|
+
@conf[1]['database'].should be == "your_db"
|
29
|
+
@conf[1]['balancer_port'].should be == 3307
|
30
|
+
@conf[1]['backend_port'].should be == 3306
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Backend do
|
36
|
+
before(:each) do
|
37
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf.first
|
38
|
+
@backend = Backend.new(@conf[1])
|
39
|
+
end
|
40
|
+
|
41
|
+
context "round robin load balancing" do
|
42
|
+
it "returns the next backend" do
|
43
|
+
@backend.get_next.should be == "192.168.10.102"
|
44
|
+
@backend.get_next.should be == "192.168.10.103"
|
45
|
+
@backend.get_next.should be == "192.168.10.101"
|
46
|
+
@backend.get_next.should be == "192.168.10.102" # and again... that's why it is called round robin
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not return a backend that is not ready" do
|
50
|
+
@backend.not_ready.push("192.168.10.103")
|
51
|
+
@backend.get_next.should be == "192.168.10.102"
|
52
|
+
@backend.get_next.should be == "192.168.10.101"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuration do
|
4
|
+
before(:each) do
|
5
|
+
@conf = Configuration.new(ENV['GALERAB_CONFIG_PATH']).conf
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when loading the file" do
|
9
|
+
it "should load the YAML file" do
|
10
|
+
@conf.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should find two balancers in the config file" do
|
14
|
+
@conf.size.should be == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gets the backends for balancer 1" do
|
18
|
+
@conf[1]['backends'].size.should be == 3
|
19
|
+
@conf[1]['backends'][0].should be == "192.168.10.101"
|
20
|
+
@conf[1]['backends'][1].should be == "192.168.10.102"
|
21
|
+
@conf[1]['backends'][2].should be == "192.168.10.103"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads the other parameters" do
|
25
|
+
@conf[1]['check_every'].size.should be == 8
|
26
|
+
@conf[1]['user'].should be == "your_user"
|
27
|
+
@conf[1]['password'].should be == "your_password"
|
28
|
+
@conf[1]['database'].should be == "your_db"
|
29
|
+
@conf[1]['balancer_port'].should be == 3307
|
30
|
+
@conf[1]['backend_port'].should be == 3306
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: galerab
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Riccardo Tacconi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mysql2
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.11
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.11
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sequel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.40.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.40.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: em-proxy
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.1.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.7
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: ansi
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.4.3
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.4.3
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '2.5'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.5'
|
110
|
+
description: This load balancer is a transparent proxy to route r/w requests to MySql
|
111
|
+
backends
|
112
|
+
email: rtacconi@virtuelogic.net
|
113
|
+
executables:
|
114
|
+
- galerab
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/galerab.rb
|
119
|
+
- lib/galerab/backend.rb
|
120
|
+
- lib/galerab/balancing_proxy.rb
|
121
|
+
- lib/galerab/configuration.rb
|
122
|
+
- lib/galerab/proxy.rb
|
123
|
+
- bin/galerab
|
124
|
+
- files/galerab
|
125
|
+
- files/galerab.yml
|
126
|
+
- spec/lib/backend_spec.rb
|
127
|
+
- spec/lib/configuration_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: http://github.com/rtacconi/galerab
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
- lib
|
137
|
+
- lib/galera
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 1.8.24
|
153
|
+
signing_key:
|
154
|
+
specification_version: 3
|
155
|
+
summary: Load balancer for galera cluster
|
156
|
+
test_files:
|
157
|
+
- spec/lib/backend_spec.rb
|
158
|
+
- spec/lib/configuration_spec.rb
|
159
|
+
- spec/spec_helper.rb
|
160
|
+
has_rdoc:
|