jetpants 0.7.8 → 0.7.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +8 -6
- data/bin/jetpants +2 -2
- data/doc/commands.rdoc +3 -3
- data/doc/configuration.rdoc +40 -0
- data/doc/faq.rdoc +6 -2
- data/doc/jetpants_collins.rdoc +95 -0
- data/doc/plugins.rdoc +7 -4
- data/doc/requirements.rdoc +2 -2
- data/etc/jetpants.yaml.sample +5 -0
- data/lib/jetpants.rb +2 -0
- data/lib/jetpants/db/state.rb +18 -2
- data/lib/jetpants/host.rb +17 -6
- data/lib/jetpants/monkeypatch.rb +26 -0
- data/lib/jetpants/pool.rb +2 -2
- data/lib/jetpants/topology.rb +22 -0
- data/plugins/jetpants_collins/asset.rb +77 -0
- data/plugins/jetpants_collins/db.rb +77 -0
- data/plugins/jetpants_collins/host.rb +41 -0
- data/plugins/jetpants_collins/jetpants_collins.rb +214 -0
- data/plugins/jetpants_collins/pool.rb +145 -0
- data/plugins/jetpants_collins/shard.rb +106 -0
- data/plugins/jetpants_collins/topology.rb +239 -0
- metadata +37 -17
data/README.rdoc
CHANGED
@@ -8,16 +8,16 @@
|
|
8
8
|
|
9
9
|
== MOTIVATION:
|
10
10
|
|
11
|
-
\Jetpants was created by {Tumblr}[http://www.tumblr.com/] to help manage our database infrastructure. It handles automation tasks for our entire database topology, which as of
|
11
|
+
\Jetpants was created by {Tumblr}[http://www.tumblr.com/] to help manage our database infrastructure. It handles automation tasks for our entire database topology, which as of October 2012 consists of approximately:
|
12
12
|
* 200 dedicated database servers
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
13
|
+
* 5 global (unsharded) functional pools
|
14
|
+
* 58 shard pools
|
15
|
+
* 28 terabytes total of unique relational data on masters
|
16
|
+
* 100 billion total unique relational rows on masters
|
17
17
|
|
18
18
|
One of the primary requirements for \Jetpants was speed. On our hardware, <b>\Jetpants can divide a 750GB, billion-row shard in half in about six hours</b> -- or even faster if you're diving into thirds or fourths. It can also <b>clone slaves at line speed on gigabit ethernet</b>, including to multiple destinations at once, using a novel "chained copy" approach.
|
19
19
|
|
20
|
-
For more background on the initial motivations behind \Jetpants, please see {Evan Elias's presentation at
|
20
|
+
For more background on the initial motivations behind \Jetpants, please see {Evan Elias's presentation at Percona Live NYC 2012}[https://github.com/tumblr/jetpants/blob/master/doc/PerconaLiveNYC2012Presentation.pdf?raw=true].
|
21
21
|
|
22
22
|
== COMMAND SUITE FEATURES:
|
23
23
|
|
@@ -64,6 +64,8 @@ It is highly recommended that you tie \Jetpants into your site's asset tracker /
|
|
64
64
|
|
65
65
|
Other recommended uses of plugins include integration with your site's monitoring system, trending system, query killers, and environment-specific overrides to various core methods.
|
66
66
|
|
67
|
+
If you are using \Collins for asset management, \Jetpants now ships with a plugin that offers integration. Please see doc/jetpants_collins.rdoc ({view on GitHub}[https://github.com/tumblr/jetpants/blob/master/doc/jetpants_collins.rdoc]) for usage.
|
68
|
+
|
67
69
|
For more information on how to write plugins and use the Jetpants::CallbackHandler system, please see doc/plugins.rdoc ({view on GitHub}[https://github.com/tumblr/jetpants/blob/master/doc/plugins.rdoc])
|
68
70
|
|
69
71
|
== FREQUENTLY ASKED QUESTIONS:
|
data/bin/jetpants
CHANGED
@@ -170,10 +170,10 @@ module Jetpants
|
|
170
170
|
def pools_compact
|
171
171
|
puts
|
172
172
|
Jetpants.shards.each do |s|
|
173
|
-
puts "[%-
|
173
|
+
puts "[%-15s] %8s to %-11s = %3s GB" % [s.ip, s.min_id, s.max_id, s.data_set_size(true)]
|
174
174
|
end
|
175
175
|
Jetpants.functional_partitions.each do |p|
|
176
|
-
puts "[%-
|
176
|
+
puts "[%-15s] %-23s = %3s GB" % [p.ip, p.name, p.data_set_size(true)]
|
177
177
|
end
|
178
178
|
puts
|
179
179
|
end
|
data/doc/commands.rdoc
CHANGED
@@ -12,9 +12,9 @@ Here's a more thorough description of the commands, grouped by function:
|
|
12
12
|
|
13
13
|
\Jetpants copies data sets by shutting down the MySQL daemon on the source node and then copying all MySQL files. This is the fastest way to clone MySQL data sets, and is part of the reason why we recommend having 2 standby slaves per pool for high availability.
|
14
14
|
|
15
|
-
The copy method in \Jetpants uses a combination of tar, netcat (nc), and
|
15
|
+
The copy method in \Jetpants uses a combination of tar, netcat (nc), and whichever compression binary you have specified in your Jetpants configuration file (if any). It does not use encryption; we assume you are transferring over a secure local network. When copying to multiple destinations, \Jetpants creates a "copy chain" using tee and a fifo. For more information on this technique, please see {our post on the Tumblr engineering blog}[http://engineering.tumblr.com/post/7658008285/efficiently-copying-files-to-multiple-destinations].
|
16
16
|
|
17
|
-
This command does not require an asset tracker plugin, but DOES require that all your database nodes have
|
17
|
+
This command does not require an asset tracker plugin, but DOES require that all your database nodes have installed whichever compression binary you specified in the Jetpants config file.
|
18
18
|
|
19
19
|
|
20
20
|
== Master/slave state changes
|
@@ -73,7 +73,7 @@ Or if you're deploying a brand new pool in an existing topology:
|
|
73
73
|
5. Stop replicating writes from the parent shard, and then take the parent pool offline entirely.
|
74
74
|
6. Remove rows that replicated to the wrong child shard. This data will be sparse, since it's only the writes that were made since the shard split process started.
|
75
75
|
|
76
|
-
For more information, including diagrams of each step, please see {our presentation at
|
76
|
+
For more information, including diagrams of each step, please see {our presentation at Percona Live NYC 2012}[https://github.com/tumblr/jetpants/blob/master/doc/PerconaLiveNYC2012Presentation.pdf?raw=true].
|
77
77
|
|
78
78
|
Separately, \Jetpants also allows you to alter the range of the last shard in your topology. In a range-based sharding scheme, the last shard has a range of X to infinity; eventually this will be too large of a range, so you need to truncate that shard range and create a "new" last shard after it. We call this process "shard cutover".
|
79
79
|
|
data/doc/configuration.rdoc
CHANGED
@@ -20,8 +20,48 @@ mysql_repl_password:: mysql password for replication (mandatory)
|
|
20
20
|
mysql_root_password:: mysql root password (default: false, indicating that \Jetpants should use /root/.my.cnf instead)
|
21
21
|
mysql_grant_ips:: mysql user manipulations are applied to these IPs (array; mandatory)
|
22
22
|
mysql_grant_privs:: mysql user manipulations grant this set of privileges by default (array; default: \['ALL'])
|
23
|
+
compress_with:: command line to perform compression during large file copy operations; see below (default: false)
|
24
|
+
decompress_with:: command line to perform decompression during large file copy operations; see below (default: false)
|
23
25
|
export_location:: directory to use for data dumping (default: '/tmp')
|
24
26
|
verify_replication:: raise exception if the actual replication topology differs from Jetpants' understanding of it (ie, disagreement between asset tracker and probed state), or if MySQL's two replication threads are in different states (one running and the other stopped) on a DB node. (default: true. master promotion tool ignores this, since the demoted master may legitimately be dead/offline)
|
25
27
|
plugins:: hash of plugin name => arbitrary plugin data, usually a nested hash of settings (default: \{})
|
26
28
|
ssh_keys:: array of SSH private key file locations, if not using standard id_dsa or id_rsa. Passed directly to Net::SSH.start's :keys parameter (default: nil)
|
27
29
|
sharded_tables:: array of name => \{sharding_key=>X, chunks=>Y} hashes, describing all tables on shards. Required by shard split/rebuild processes (default: \[])
|
30
|
+
|
31
|
+
== Compression
|
32
|
+
|
33
|
+
\Jetpants has the ability to use compression during large file copy operations, which are performed by commands "jetpants clone_slave" and "jetpants shard_split". Compression is disabled by default in \Jetpants unless you specify a compression program to use via the <tt>compress_with</tt> and <tt>decompress_with</tt> config options. It is highly recommended that you do so, in order to speed up these operations when working with large data sets.
|
34
|
+
|
35
|
+
The command lines that you specify should accept input from STDIN and supply output to STDOUT, because they will be used in the middle of a series of piped commands. The binary specified should be in root's PATH on all database nodes. We recommend use of a parallel compression tool, to take advantage of multiple cores.
|
36
|
+
|
37
|
+
You will need to do some profiling to determine the best tool to use for your hardware and data set; there's no universal best choice of compression algorithm or settings.
|
38
|
+
|
39
|
+
Some example values of these parameters are as follows:
|
40
|
+
|
41
|
+
=== Disable compression (default)
|
42
|
+
|
43
|
+
compress_with: false
|
44
|
+
decompress_with: false
|
45
|
+
|
46
|
+
=== pigz
|
47
|
+
pigz is an open-source parallel gzip tool by Mark Adler. It is available as a package in several Linux distros. It performs well, but is very CPU intensive. More information: http://zlib.net/pigz/
|
48
|
+
|
49
|
+
compress_with: pigz
|
50
|
+
decompress_with: pigz -d
|
51
|
+
|
52
|
+
=== qpress
|
53
|
+
qpress is a multi-threaded portable file archiver using QuickLZ. A prebuilt package is not available for most Linux distros due to licensing reasons, but a binary can be downloaded from http://www.quicklz.com/. It performs extremely well, especially once tuned.
|
54
|
+
|
55
|
+
In order to read from STDIN and write to STDOUT, use <tt>qpress -io</tt>. In this case qpress still requires a filename during compression, even though it is unused. Decompression does not have the same requirement.
|
56
|
+
|
57
|
+
The example below uses 4 threads and a block size of 32768KB.
|
58
|
+
|
59
|
+
compress_with: qpress -ioT4K32768 dummyfilename
|
60
|
+
decompress_with: qpress -dioT4
|
61
|
+
|
62
|
+
=== lzop
|
63
|
+
lzop is a less CPU-intensive compressor. lzop is still single-threaded in v1.x, so its performance may not be ideal for the \Jetpants use-case. Multithreading is planned for v2.x. More information: http://www.lzop.org/
|
64
|
+
|
65
|
+
compress_with: lzop
|
66
|
+
decompress_with: lzop -d
|
67
|
+
|
data/doc/faq.rdoc
CHANGED
@@ -72,7 +72,11 @@ The main downside to the range-based approach is lack of even distribution of "h
|
|
72
72
|
|
73
73
|
\Jetpants clones slaves by stopping replication, shutting down the MySQL daemon, and then copying the raw files to the destination(s). This is the fastest way to get a consistent clone of a data set in MySQL. After the copy operation is complete, we start MySQL back up on the source and destinations, and then make the destination instances start slaving at the appropriate binlog coordinates.
|
74
74
|
|
75
|
-
We perform the copy operation using a combination of
|
75
|
+
We perform the copy operation using a combination of:
|
76
|
+
* <tt>tar</tt>, for archiving
|
77
|
+
* a compression tool, if specified in your \Jetpants config file; we recommend <tt>qpress</tt> or <tt>pigz</tt>
|
78
|
+
* <tt>nc</tt> (netcat), for transferring the data over the network
|
79
|
+
* If there are multiple destinations, we create a serial "copy chain" using <tt>tee</tt> and a FIFO.
|
76
80
|
|
77
81
|
Please note that we don't encrypt the data in this process, so we assume you are using it on a private LAN or over a VPN tunnel.
|
78
82
|
|
@@ -115,7 +119,7 @@ For any given operation that requires an asset tracker, there's one of two reaso
|
|
115
119
|
|
116
120
|
* The operation inherently involves generating a new configuration for your application -- for example, setting a shard to read-only or promoting a standby slave to an active slave. These operations are meaningless outside of your application, since MySQL has no notion of "standby slave" or "degraded shard". \Jetpants has a notion of these things, but needs to persist the information somewhere, and it makes more sense to have \Jetpants relay this information to an external hardware management tool rather than maintain a separate (and potentially conflicting) source of truth.
|
117
121
|
|
118
|
-
If you have enough servers to be using a sharded architecture, you hopefully already have some sort of hardware management / asset tracker system in place. \Jetpants is designed to be integrated with this system, but since every site runs something different, this requires that you write some custom plugin code to achieve.
|
122
|
+
If you have enough servers to be using a sharded architecture, you hopefully already have some sort of hardware management / asset tracker system in place. \Jetpants is designed to be integrated with this system, but since every site runs something different, this requires that you write some custom plugin code to achieve. (Unless you use \Collins for tracking hardware, in which case you can use the bundled jetpants_collins plugin.)
|
119
123
|
|
120
124
|
|
121
125
|
== Can I use \Jetpants with PostgreSQL?
|
@@ -0,0 +1,95 @@
|
|
1
|
+
= jetpants_collins
|
2
|
+
|
3
|
+
== OVERVIEW:
|
4
|
+
|
5
|
+
This \Jetpants plugin offers integration with the \Collins hardware asset tracking system. This allows \Jetpants to automatically query the list of pools, shards, hosts, and databases in your topology at start-up time. Furthermore, every change you make to your topology using \Jetpants (master promotions, shard splits, new slaves cloned, etc) will automatically be reflected in \Collins immediately.
|
6
|
+
|
7
|
+
== CONFIGURATION:
|
8
|
+
|
9
|
+
This plugin has a number of configuration options, some of which are mandatory.
|
10
|
+
|
11
|
+
user:: \Collins account username for \Jetpants to use (required)
|
12
|
+
password:: \Collins account password (required)
|
13
|
+
url:: \Collins URL (required)
|
14
|
+
timeout:: \Collins client timeout, in seconds (default: 30)
|
15
|
+
datacenter:: \Collins data center name that we're running \Jetpants in the context of (required if multi-datacenter, omit otherwise)
|
16
|
+
remote_lookup:: Supply "remoteLookup" parameter for \Collins requests, to search multiple datacenters (default: false)
|
17
|
+
|
18
|
+
To enable this plugin, add it to your \Jetpants configuration file (either <tt>/etc/jetpants.yaml</tt> or <tt>~/.jetpants.yaml</tt>). For example, in a single-datacenter environment, you configuration might look like this:
|
19
|
+
|
20
|
+
# ... rest of Jetpants config here
|
21
|
+
|
22
|
+
plugins:
|
23
|
+
jetpants_collins:
|
24
|
+
user: jetpants
|
25
|
+
password: xxx
|
26
|
+
url: http://collins.yourdomain.com:8080
|
27
|
+
|
28
|
+
# ... other plugins configured here
|
29
|
+
|
30
|
+
== ASSUMPTIONS AND REQUIREMENTS:
|
31
|
+
|
32
|
+
Use of this plugin assumes that you already have \Collins set up, and have performed hardware intake for all your servers already.
|
33
|
+
|
34
|
+
This plugin also makes some assumptions about the way in which you use \Collins, namely:
|
35
|
+
|
36
|
+
* All Linux servers have a TYPE of SERVER_NODE.
|
37
|
+
* All MySQL database server hosts will have a PRIMARY_ROLE of DATABASE.
|
38
|
+
* All MySQL database server hosts that are in-use will have a STATUS of either ALLOCATED or MAINTENANCE.
|
39
|
+
* All MySQL database server hosts that are in-use will have a POOL set matching the name of their pool/shard, and a SECONDARY_ROLE set matching their \Jetpants role within the pool (MASTER, ACTIVE_SLAVE, STANDBY_SLAVE, or BACKUP_SLAVE).
|
40
|
+
* You can initially assign PRIMARY_ROLE, STATUS, POOL, and SECONDARY_ROLE to database servers somewhat automatically; see GETTING STARTED, below.
|
41
|
+
* All database server hosts that are "spares" (not yet in use, but ready for use in shard splits, shard cutover, or slave cloning) need to have a STATUS of PROVISIONED. These nodes must meet the requirements of spares as defined by the REQUIREMENTS doc that comes with \Jetpants. They should NOT have a POOL set, but they may have a ROLE set to either MASTER or STANDBY_SLAVE. The role will be used to select spare nodes for shard splits and shard cutover.
|
42
|
+
* Database server hosts may optionally have an attribute called SLAVE_WEIGHT. The default weight, if omitted, is 100. This field has no effect in \Jetpants, but can be used by your custom configuration generator as needed, if your application supports a notion of different weights for slave selection.
|
43
|
+
* Arbitrary metadata regarding pools and shards will be stored in assets with a TYPE of CONFIGURATION. These assets will have a POOL matching the pool's name, a TAG matching the pool's name but prefixed with 'mysql-', a STATUS reflecting the pool's state, and a PRIMARY_ROLE of either MYSQL_POOL or MYSQL_SHARD depending on the type of pool. You can make jetpants_collins create these automatically; see GETTING STARTED, below.
|
44
|
+
|
45
|
+
Please note that jetpants_collins does not generate application configuration files, because every web app/framework uses a different format. You will need to write a custom plugin to generate a configuration file for your application as needed, by overriding the Topology#write_config method.
|
46
|
+
|
47
|
+
== GETTING STARTED:
|
48
|
+
|
49
|
+
Once you've met all of the requirements listed in the previous section, the next step is to tell \Jetpants about your existing pools/shards via <tt>jetpants console</tt>. You only need to do this process once.
|
50
|
+
|
51
|
+
Adding functional partitions (global / unsharded pools):
|
52
|
+
|
53
|
+
# Create the pool object, specifying pool name and IP of current master
|
54
|
+
p = Pool.new('my-pool-name', '10.42.3.4')
|
55
|
+
|
56
|
+
# Tell Jetpants about IPs of any existing active slaves (read slaves), if any.
|
57
|
+
# For example, say this pool has 2 active slaves and 2 standby slaves. \Jetpants
|
58
|
+
# can automatically figure out which slaves exist, but won't automatically know
|
59
|
+
# which ones are active for reads, so you need to tell it.
|
60
|
+
p.has_active_slave('10.42.3.30')
|
61
|
+
p.has_active_slave('10.42.3.32')
|
62
|
+
|
63
|
+
# Sync the information to Collins
|
64
|
+
p.sync_configuration
|
65
|
+
|
66
|
+
Repeat this process for each functional partition, if you have more than one.
|
67
|
+
|
68
|
+
Adding shard pools:
|
69
|
+
|
70
|
+
# Create and sync each shard object, specifying ID range and IP of current master
|
71
|
+
Shard.new( 1, 1000000, '10.42.4.10' ).sync_configuration
|
72
|
+
Shard.new(1000001, 2000000, '10.42.3.112').sync_configuration
|
73
|
+
Shard.new(2000001, 4000000, '10.42.3.45' ).sync_configuration
|
74
|
+
Shard.new(4000001, 'INFINITY', '10.42.3.26' ).sync_configuration
|
75
|
+
|
76
|
+
The max ID of the last shard must be 'INFINITY' in order for <tt>jetpants shard_cutover</tt> to work.
|
77
|
+
|
78
|
+
|
79
|
+
== MULTI-DATACENTER SUPPORT:
|
80
|
+
|
81
|
+
This plugin offers preliminary support for multi-datacenter \Collins deployments. The assumed topology is:
|
82
|
+
* Each datacenter has its own copy of \Collins, and they're configured to talk to each other
|
83
|
+
* Each datacenter has a node to run \Jetpants from, with the jetpants_collins configuration options differing between datacenters
|
84
|
+
* Every database pool has only one true, writable master. This is located in any datacenter.
|
85
|
+
* The true master may have several slaves in its own datacenter.
|
86
|
+
* The true master may have slaves in other datacenters, but should only have <i>one direct slave per remote datacenter</i>. These remote slaves should have a SECONDARY_ROLE of MASTER in their datacenter's copy of \Collins, and they may have additional slaves of their own (tiered replication).
|
87
|
+
* In other words, each datacenter -- and hence each copy of \Collins -- still has at most one MASTER per database pool. However only one of these nodes is the true, writable master; the others are actually slaves of master, and are read-only.
|
88
|
+
|
89
|
+
Also, jetpants_collins currently enforces several restrictions on interacting with databases in remote datacenters, to simplify handling of tiered replication:
|
90
|
+
|
91
|
+
* jetpants_collins won't change Collins attributes on remote server node assets. If you need to manipulate those assets, do it from the copy of \Jetpants and copy of \Collins in that datacenter.
|
92
|
+
* If a local slave node has a master in a remote datacenter, it is ignored/hidden by jetpants_collins. In other words, each datacenter's master is viewed as a "real" master, even if it's actually slaving from another remote master.
|
93
|
+
* If a local master node has a slave in a remote datacenter, it's treated as a backup_slave, in order to prevent cross-datacenter master promotions. If any of these remote slaves have slaves of their own, they're ignored/hidden by jetpants_collins.
|
94
|
+
|
95
|
+
Due to the nature of this implementation, it works best for setups with 1 active datacenter and 1 or more passive datacenters. This support will be expanded in future releases to better capture the tiered replication roles and support active/active topologies. At that time, these restrictions/simplifications will be lifted wherever possible.
|
data/doc/plugins.rdoc
CHANGED
@@ -8,9 +8,9 @@ It is highly recommended that you tie \Jetpants into your site's asset tracker (
|
|
8
8
|
|
9
9
|
Other recommended uses of plugins include integration with your site's monitoring system, trending system, query killers, and environment-specific overrides to various core methods.
|
10
10
|
|
11
|
-
== Asset tracker
|
11
|
+
== Asset tracker examples
|
12
12
|
|
13
|
-
===
|
13
|
+
=== simple_tracker
|
14
14
|
|
15
15
|
We supply a sample plugin called simple_tracker, demonstrating how to go about writing a very basic asset-tracking plugin. This plugin just uses an internal JSON file to keep track of database topology/state, and separately writes app configuration to a YAML file. This isn't actually suitable for production use, but should provide a reasonable starting point for learning the plugin system and building a real asset tracker.
|
16
16
|
|
@@ -24,8 +24,11 @@ When you first start using simple_tracker, there will be no pools, shards, or sp
|
|
24
24
|
* <tt>jetpants add_shard</tt>
|
25
25
|
* <tt>jetpants add_spare</tt>
|
26
26
|
|
27
|
+
=== jetpants_collins
|
27
28
|
|
28
|
-
|
29
|
+
We also supply a plugin called jetpants_collins, offering integration with the Collins asset management software. This is fully intended for production use, and powers our automation at Tumblr. For more information on jetpants_collins, please see jetpants_collins.rdoc ({view on GitHub}[https://github.com/tumblr/jetpants/blob/master/doc/jetpants_collins.rdoc]).
|
30
|
+
|
31
|
+
=== Rolling your own
|
29
32
|
|
30
33
|
If you're writing your own asset-tracker plugin, you will need to override the following methods:
|
31
34
|
|
@@ -58,7 +61,7 @@ You may also want to override or implement these, though it's not strictly manda
|
|
58
61
|
|
59
62
|
=== Name and location
|
60
63
|
|
61
|
-
If you define a plugin named "foo" in your \Jetpants config file, on startup \Jetpants will first attempt to require 'foo/foo',
|
64
|
+
If you define a plugin named "foo" in your \Jetpants config file, on startup \Jetpants will first attempt to require 'foo/foo' (for loading bundled plugins in <tt>jetpants/plugins/<>tt>), if that fails then simply 'foo' (for loading a stand-alone gem).
|
62
65
|
|
63
66
|
Plugins may be located anywhere on your Ruby load path, so packing them as standard gems should work perfectly. You may want to prefix the gem name with "\jetpants_" to avoid conflicts with other gems. \Jetpants also adds its plugins directory to its load path automatically, so that any pre-bundled plugins (like simple_tracker) can be loaded easily.
|
64
67
|
|
data/doc/requirements.rdoc
CHANGED
@@ -16,7 +16,7 @@ Plugins may freely override these assumptions, and upstream patches are very wel
|
|
16
16
|
* Required Linux binaries that must be installed and in root's PATH on all of your database machines:
|
17
17
|
* <tt>service</tt>, a wrapper around init scripts, supporting syntax <tt>service mysql start</tt>, <tt>service mysql status</tt>, etc. Some distros include this by default (typically as /sbin/service or /usr/sbin/service) while others offer it as a package. Implementation varies slightly between distros; currently \Jetpants expects <tt>service mysql status</tt> output to include either "not running" (RHEL/Centos) or "stop/waiting" (Ubuntu) in the output if the MySQL server is not running.
|
18
18
|
* <tt>nc</tt>, also known as netcat, a tool for piping data to or from a socket.
|
19
|
-
*
|
19
|
+
* Whichever compression tool you've specified in the \Jetpants config file for the <tt>compress_with</tt> and <tt>decompress_with</tt> options, if any. (if omitted, compression will not be used for file copy operations.)
|
20
20
|
* InnoDB / Percona XtraDB for storage engine. \Jetpants has not been tested with MyISAM, since \Jetpants is geared towards huge tables, and MyISAM is generally a bad fit.
|
21
21
|
* All MySQL instances run on port 3306, with only one instance per logical machine.
|
22
22
|
* A plugin could override this easily, but would require you to use the --report-host option on all slaves running MySQL 5.1, so that crawling the replication topology is possible. It would also have to override various methods that specify the MySQL init script location, config file location, data directory, etc.
|
@@ -64,4 +64,4 @@ By default, the <tt>standby_slaves_per_pool</tt> config option is set to 2. This
|
|
64
64
|
|
65
65
|
A "spare" machine in \Jetpants should be in a clean-slate state: MySQL should be installed and have the proper grants and root password, but there should be no data on these machines, and they should not be slaving. \Jetpants will set up replication appropriately when it assigns the nodes to their appropriate pools.
|
66
66
|
|
67
|
-
For more information on the shard split process implemented by \Jetpants, including diagrams of each stage of the process, please see {Evan Elias's presentation at
|
67
|
+
For more information on the shard split process implemented by \Jetpants, including diagrams of each stage of the process, please see {Evan Elias's presentation at Percona Live NYC 2012}[https://github.com/tumblr/jetpants/blob/master/doc/PerconaLiveNYC2012Presentation.pdf?raw=true], starting at slide 20.
|
data/etc/jetpants.yaml.sample
CHANGED
@@ -27,6 +27,11 @@ mysql_grant_privs:
|
|
27
27
|
# has higher capacity anyway.
|
28
28
|
export_location: /some/path/on/root/partition
|
29
29
|
|
30
|
+
# If you want to speed up large copy operations in Jetpants, supply relevant
|
31
|
+
# command lines here. See configuration.rdoc for more information on formatting.
|
32
|
+
compress_with: false
|
33
|
+
decompress_with: false
|
34
|
+
|
30
35
|
# List all tables defined on the shards, along with what column name corresponds
|
31
36
|
# to your app's sharding key (to determine which shard a given row lives on),
|
32
37
|
# and how many "chunks" to split the data set into when doing an import or
|
data/lib/jetpants.rb
CHANGED
@@ -36,6 +36,8 @@ module Jetpants
|
|
36
36
|
'plugins' => {}, # hash of plugin name => arbitrary plugin data (usually a nested hash of settings)
|
37
37
|
'ssh_keys' => nil, # array of SSH key file locations
|
38
38
|
'sharded_tables' => [], # array of name => {sharding_key=>X, chunks=>Y} hashes
|
39
|
+
'compress_with' => false, # command line to use for compression in large file transfers
|
40
|
+
'decompress_with' => false, # command line to use for decompression in large file transfers
|
39
41
|
}
|
40
42
|
%w(/etc/jetpants.yaml ~/.jetpants.yml ~/.jetpants.yaml).each do |path|
|
41
43
|
overrides = YAML.load_file(File.expand_path path) rescue {}
|
data/lib/jetpants/db/state.rb
CHANGED
@@ -105,7 +105,15 @@ module Jetpants
|
|
105
105
|
sleep(interval)
|
106
106
|
global_status[:Connections].to_i - conn_counter > threshold
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
|
+
# Confirms the binlog of this node has not moved during a duration
|
110
|
+
# of [interval] seconds.
|
111
|
+
def taking_writes?(interval=5.0)
|
112
|
+
coords = binlog_coordinates
|
113
|
+
sleep(interval)
|
114
|
+
coords != binlog_coordinates
|
115
|
+
end
|
116
|
+
|
109
117
|
# Returns true if this instance appears to be a standby slave,
|
110
118
|
# false otherwise. Note that "standby" in this case is based
|
111
119
|
# on whether the slave is actively receiving connections, not
|
@@ -249,9 +257,17 @@ module Jetpants
|
|
249
257
|
@slaves = []
|
250
258
|
slaves_mutex = Mutex.new
|
251
259
|
processes = mysql_root_cmd("SHOW PROCESSLIST", :terminator => ';').split("\n")
|
252
|
-
|
260
|
+
|
261
|
+
# We have to de-dupe the output, since it's possible in weird edge cases for
|
262
|
+
# the same slave to be listed twice
|
263
|
+
ips = {}
|
264
|
+
processes.grep(/Binlog Dump/).each do |p|
|
253
265
|
tokens = p.split
|
254
266
|
ip, dummy = tokens[2].split ':'
|
267
|
+
ips[ip] = true
|
268
|
+
end
|
269
|
+
|
270
|
+
ips.keys.concurrent_each do |ip|
|
255
271
|
db = ip.to_db
|
256
272
|
db.probe
|
257
273
|
slaves_mutex.synchronize {@slaves << db if db.master == self}
|
data/lib/jetpants/host.rb
CHANGED
@@ -192,7 +192,6 @@ module Jetpants
|
|
192
192
|
###### Directory Copying / Listing / Comparison methods ####################
|
193
193
|
|
194
194
|
# Quickly and efficiently recursively copies a directory to one or more target hosts.
|
195
|
-
# Requires that pigz is installed on source (self) and all targets.
|
196
195
|
# base_dir:: is base directory to copy from the source (self). Also the default destination base
|
197
196
|
# directory on the targets, if not supplied via next param.
|
198
197
|
# targets:: is one of the following:
|
@@ -225,6 +224,14 @@ module Jetpants
|
|
225
224
|
file_list = filenames.join ' '
|
226
225
|
port = (options[:port] || 7000).to_i
|
227
226
|
|
227
|
+
if Jetpants.compress_with || Jetpants.decompress_with
|
228
|
+
comp_bin = Jetpants.compress_with.split(' ')[0]
|
229
|
+
confirm_installed comp_bin
|
230
|
+
output "Using #{comp_bin} for compression"
|
231
|
+
else
|
232
|
+
output "Compression disabled -- no compression method specified in Jetpants config file"
|
233
|
+
end
|
234
|
+
|
228
235
|
# On each destination host, do any initial setup (and optional validation/erasing),
|
229
236
|
# and then listen for new files. If there are multiple destination hosts, all of them
|
230
237
|
# except the last will use tee to "chain" the copy along to the next machine.
|
@@ -233,7 +240,10 @@ module Jetpants
|
|
233
240
|
dir = destinations[t]
|
234
241
|
raise "Directory #{t}:#{dir} looks suspicious" if dir.include?('..') || dir.include?('./') || dir == '/' || dir == ''
|
235
242
|
|
236
|
-
|
243
|
+
if Jetpants.compress_with || Jetpants.decompress_with
|
244
|
+
decomp_bin = Jetpants.decompress_with.split(' ')[0]
|
245
|
+
t.confirm_installed decomp_bin
|
246
|
+
end
|
237
247
|
t.ssh_cmd "mkdir -p #{dir}"
|
238
248
|
|
239
249
|
# Check if contents already exist / non-empty.
|
@@ -244,8 +254,9 @@ module Jetpants
|
|
244
254
|
dirlist.each {|name, size| raise "File #{name} exists on destination and has nonzero size!" if size.to_i > 0}
|
245
255
|
end
|
246
256
|
|
257
|
+
decompression_pipe = Jetpants.decompress_with ? "| #{Jetpants.decompress_with}" : ''
|
247
258
|
if i == 0
|
248
|
-
workers << Thread.new { t.ssh_cmd "cd #{dir} && nc -l #{port}
|
259
|
+
workers << Thread.new { t.ssh_cmd "cd #{dir} && nc -l #{port} #{decompression_pipe} | tar xv" }
|
249
260
|
t.confirm_listening_on_port port
|
250
261
|
t.output "Listening with netcat."
|
251
262
|
else
|
@@ -254,16 +265,16 @@ module Jetpants
|
|
254
265
|
workers << Thread.new { t.ssh_cmd "cd #{dir} && mkfifo #{fifo} && nc #{tt.ip} #{port} <#{fifo} && rm #{fifo}" }
|
255
266
|
checker_th = Thread.new { t.ssh_cmd "while [ ! -p #{dir}/#{fifo} ] ; do sleep 1; done" }
|
256
267
|
raise "FIFO not found on #{t} after 10 tries" unless checker_th.join(10)
|
257
|
-
workers << Thread.new { t.ssh_cmd "cd #{dir} && nc -l #{port} | tee #{fifo}
|
268
|
+
workers << Thread.new { t.ssh_cmd "cd #{dir} && nc -l #{port} | tee #{fifo} #{decompression_pipe} | tar xv" }
|
258
269
|
t.confirm_listening_on_port port
|
259
270
|
t.output "Listening with netcat, and chaining to #{tt}."
|
260
271
|
end
|
261
272
|
end
|
262
273
|
|
263
274
|
# Start the copy chain.
|
264
|
-
confirm_installed 'pigz'
|
265
275
|
output "Sending files over to #{targets[0]}: #{file_list}"
|
266
|
-
|
276
|
+
compression_pipe = Jetpants.compress_with ? "| #{Jetpants.compress_with}" : ''
|
277
|
+
ssh_cmd "cd #{base_dir} && tar vc #{file_list} #{compression_pipe} | nc #{targets[0].ip} #{port}"
|
267
278
|
workers.each {|th| th.join}
|
268
279
|
output "File copy complete."
|
269
280
|
|
data/lib/jetpants/monkeypatch.rb
CHANGED
@@ -17,6 +17,32 @@ module Enumerable
|
|
17
17
|
def concurrent_each_with_index(&block)
|
18
18
|
each_with_index.concurrent_each(&block)
|
19
19
|
end
|
20
|
+
|
21
|
+
# Alternative for concurrent_map which also has the ability to limit how
|
22
|
+
# many threads are used. Much less elegant :(
|
23
|
+
def limited_concurrent_map(thread_limit=40)
|
24
|
+
lock = Mutex.new
|
25
|
+
group = ThreadGroup.new
|
26
|
+
items = to_a
|
27
|
+
results = []
|
28
|
+
pos = 0
|
29
|
+
|
30
|
+
# Number of concurrent threads is the lowest of: self length, supplied thread limit, global concurrency limit
|
31
|
+
[items.length, thread_limit, Jetpants.max_concurrency].min.times do
|
32
|
+
th = Thread.new do
|
33
|
+
while true do
|
34
|
+
my_pos = nil
|
35
|
+
lock.synchronize { my_pos = pos; pos += 1}
|
36
|
+
break unless my_pos < items.length
|
37
|
+
my_result = yield items[my_pos]
|
38
|
+
lock.synchronize { results[my_pos] = my_result }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
group.add th
|
42
|
+
end
|
43
|
+
group.list.each {|th| th.join}
|
44
|
+
results
|
45
|
+
end
|
20
46
|
end
|
21
47
|
|
22
48
|
# Add Jetpants-specific conversion methods to Object.
|
data/lib/jetpants/pool.rb
CHANGED
@@ -177,14 +177,14 @@ module Jetpants
|
|
177
177
|
end
|
178
178
|
|
179
179
|
binlog_pos = extended_info ? details[@master][:coordinates].join(':') : ''
|
180
|
-
print "\tmaster = %-
|
180
|
+
print "\tmaster = %-15s %-30s %s\n" % [@master.ip, @master.hostname, binlog_pos]
|
181
181
|
|
182
182
|
[:active, :standby, :backup].each do |type|
|
183
183
|
slave_list = slaves(type)
|
184
184
|
slave_list.sort.each_with_index do |s, i|
|
185
185
|
binlog_pos = extended_info ? details[s][:coordinates].join(':') : ''
|
186
186
|
slave_lag = extended_info ? "lag=#{details[s][:lag]}" : ''
|
187
|
-
print "\t%-7s slave #{i + 1} = %-
|
187
|
+
print "\t%-7s slave #{i + 1} = %-15s %-30s %-26s %s\n" % [type, s.ip, s.hostname, binlog_pos, slave_lag]
|
188
188
|
end
|
189
189
|
end
|
190
190
|
true
|