ar_mysql_flexmaster 0.0.6 → 0.0.8

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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # ArMysqlFlexmaster
2
2
 
3
- TODO: Write a gem description
3
+ Mysql Flexmaster is an adapter for ActiveRecord that allows an application node to choose
4
+ among a list of potential masters at runtime. It trades some properties of a more traditional
5
+ HA solution (load balancing, middleware) for simplicity of operation.
4
6
 
5
7
  ## Installation
6
8
 
@@ -16,9 +18,85 @@ Or install it yourself as:
16
18
 
17
19
  $ gem install ar_mysql_flexmaster
18
20
 
19
- ## Usage
21
+ ## Configuration:
20
22
 
21
- TODO: Write usage instructions here
23
+ database.yml contains a list of hosts -- all of them potential masters, all of them potential replicas.
24
+ It should look like this:
25
+
26
+ ```
27
+ production:
28
+ adapter: mysql_flexmaster
29
+ username: flex
30
+ hosts: ["db01:3306", "db02:3306"]
31
+
32
+ production_slave:
33
+ adapter: mysql_flexmaster
34
+ username: flex
35
+ slave: true
36
+ hosts: ["db01:3306", "db02:3306"]
37
+ ```
38
+
39
+
40
+ ## How it works
41
+
42
+ ### Overview
43
+
44
+ The mysql "READ_ONLY" flag is used to indicate a current master amongst the cluster. Only one member
45
+ of the replication chain may be read-write at any given time. The application picks in run time, based
46
+ on the read_only flag, which host is correct.
47
+
48
+ ### boot time
49
+
50
+ Your activerecord application will pick a correct mysql host for the given configuration by probing hosts until
51
+ it finds the correct host.
52
+
53
+ For master configurations (slave: true is not specified):
54
+
55
+ The application will probe each host in turn, and find the mysql candidate among these nodes
56
+ that is read-write (SET GLOBAL READ_ONLY=0). If it finds more than one node where READ_ONLY == 0, it will
57
+ abort.
58
+
59
+ For slave configurations (slave: true specified):
60
+
61
+ The application will choose a replica at random from amongst those where READ_ONLY == 1.
62
+
63
+ ### run time
64
+
65
+ Before each transaction is begun on the master, the application checks the status of the READ_ONLY variable.
66
+ If READ_ONLY == 0, it will proceed with the transaction as normal. If READ_ONLY == 1, it will drop the current
67
+ connection and re-poll the cluster for the current master, sleeping up to a default of 5 seconds to wait for
68
+ the new master to be promoted. When it finds the new master, it will begin the transaction there.
69
+
70
+ ### promoting a new master
71
+
72
+ *The bin/master_cut script in this project will perform steps 3-5 for you.*
73
+
74
+ The process of promoting a new master to head the cluster should be as follows:
75
+
76
+ 1. identify a new candidate master
77
+ 1. ensure that all other replicas in the cluster are chained off the candidate master; you want the
78
+ chain to look like this:
79
+
80
+ ```
81
+ <existing master> -> <candidate master> -> <other replicas>
82
+ -> <other replicas>
83
+
84
+ ```
85
+
86
+ 1. set the old master to READ_ONLY = 1
87
+ 1. record the master-bin-log position of the candidate master (if you want to re-use the old master)
88
+ 1. set the new master to READ_ONLY = 0
89
+
90
+ The application will eventually shift slave traffic to another node in the cluster, if available, and
91
+ will drop their connection to the old master whenever a transaction is attempted, or after a certain
92
+ number of queries.
93
+
94
+
95
+ ### caveats, gotchas
96
+
97
+ - Any explicit ( BEGIN ... END ) transaction that are in-flight when the old master goes READ_ONLY
98
+ will crash. In theory there's a workaround for this problem, in pratice it's rather unwieldy due
99
+ to a lack of shared global variables in mysql.
22
100
 
23
101
  ## Contributing
24
102
 
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
12
12
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
13
  gem.name = "ar_mysql_flexmaster"
14
14
  gem.require_paths = ["lib"]
15
- gem.version = "0.0.6"
15
+ gem.version = "0.0.8"
16
16
 
17
17
  gem.add_runtime_dependency("mysql2")
18
18
  gem.add_runtime_dependency("activerecord")
@@ -1,3 +1,4 @@
1
+ require 'active_record'
1
2
  require 'active_record/connection_adapters/mysql2_adapter'
2
3
  require 'timeout'
3
4
 
@@ -1,2 +1,3 @@
1
+ require 'active_record/connection_adapters/mysql_flexmaster_adapter'
1
2
  module ArMysqlFlexmaster
2
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_mysql_flexmaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-17 00:00:00.000000000 Z
12
+ date: 2013-02-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mysql2
@@ -137,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
137
  version: '0'
138
138
  segments:
139
139
  - 0
140
- hash: -3392143039168594248
140
+ hash: 1068549902361046667
141
141
  required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  none: false
143
143
  requirements:
@@ -146,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  version: '0'
147
147
  segments:
148
148
  - 0
149
- hash: -3392143039168594248
149
+ hash: 1068549902361046667
150
150
  requirements: []
151
151
  rubyforge_project:
152
152
  rubygems_version: 1.8.24