promiscuous-poseidon_cluster 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -7
- data/lib/poseidon/cluster.rb +14 -9
- data/lib/poseidon/consumer_group.rb +41 -40
- data/poseidon_cluster.gemspec +3 -4
- data/spec/lib/poseidon/cluster_spec.rb +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b88185138e6a8e8de7ce363a550b4630f6e95c8f
|
4
|
+
data.tar.gz: b234eaee3e59a7441458f4506a09fd5c5e929e2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 167be7e9484234a3fd4d282567c1230d1d231463be6ed38bb0adfbddfcc91d198de5af2d636caa0a2b588044afbd9e0c43948a6b10d4ffdd0f581104ac334318
|
7
|
+
data.tar.gz: 3952e0a94d4efe8ef020812ba0dd6b9379b4bdbe530cfbcb61da532a2286eaff5a79c6574fe772e5168cd11605bdc80b9b77a2313a83f49cc263e7bf365d445a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
poseidon_cluster (0.
|
4
|
+
poseidon_cluster (0.4.0)
|
5
5
|
poseidon (>= 0.0.5.pre1)
|
6
6
|
zk
|
7
7
|
|
@@ -22,7 +22,7 @@ GEM
|
|
22
22
|
multi_json (>= 1.8.4)
|
23
23
|
mime-types (2.3)
|
24
24
|
multi_json (1.10.1)
|
25
|
-
poseidon (0.0.5
|
25
|
+
poseidon (0.0.5)
|
26
26
|
rake (10.3.2)
|
27
27
|
rest-client (1.6.7)
|
28
28
|
mime-types (>= 1.16)
|
@@ -53,13 +53,10 @@ GEM
|
|
53
53
|
thor (0.19.1)
|
54
54
|
tins (1.3.0)
|
55
55
|
yard (0.8.7.4)
|
56
|
-
zk (1.9.
|
56
|
+
zk (1.9.5)
|
57
57
|
logging (~> 1.8.2)
|
58
58
|
zookeeper (~> 1.4.0)
|
59
|
-
zookeeper (1.4.
|
60
|
-
zookeeper (1.4.9-java)
|
61
|
-
slyphon-log4j (= 1.2.15)
|
62
|
-
slyphon-zookeeper_jar (= 3.3.5)
|
59
|
+
zookeeper (1.4.10)
|
63
60
|
|
64
61
|
PLATFORMS
|
65
62
|
java
|
data/lib/poseidon/cluster.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'socket'
|
2
|
-
require 'timeout'
|
3
|
-
require 'zk'
|
4
|
-
require 'poseidon'
|
5
2
|
require 'thread'
|
6
3
|
|
4
|
+
require 'poseidon'
|
5
|
+
require 'zk'
|
6
|
+
|
7
7
|
module Poseidon::Cluster
|
8
8
|
MAX_INT32 = 0x7fffffff
|
9
9
|
@@sem = Mutex.new
|
@@ -12,17 +12,22 @@ module Poseidon::Cluster
|
|
12
12
|
# @return [Integer] an incremented number
|
13
13
|
# @api private
|
14
14
|
def self.inc!
|
15
|
-
@@sem.synchronize
|
15
|
+
@@sem.synchronize do
|
16
|
+
@@inc += 1;
|
17
|
+
|
18
|
+
if @@inc > MAX_INT32
|
19
|
+
@@inc = 1
|
20
|
+
end
|
21
|
+
|
22
|
+
@@inc
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
26
|
# @return [String] an globally unique identifier
|
19
27
|
# @api private
|
20
28
|
def self.guid
|
21
|
-
[::Socket.gethostname, ::Process.pid, ::Time.now.
|
29
|
+
[::Socket.gethostname, ::Process.pid, ::Time.now.nsec, inc!].join('-')
|
22
30
|
end
|
23
|
-
|
24
31
|
end
|
25
32
|
|
26
|
-
|
27
|
-
require "poseidon/#{name}"
|
28
|
-
end
|
33
|
+
require 'poseidon/consumer_group'
|
@@ -21,7 +21,7 @@
|
|
21
21
|
#
|
22
22
|
# @api public
|
23
23
|
class Poseidon::ConsumerGroup
|
24
|
-
DEFAULT_CLAIM_TIMEOUT =
|
24
|
+
DEFAULT_CLAIM_TIMEOUT = 5
|
25
25
|
DEFAULT_LOOP_DELAY = 1
|
26
26
|
|
27
27
|
# Poseidon::ConsumerGroup::Consumer is internally used by Poseidon::ConsumerGroup.
|
@@ -41,7 +41,6 @@ class Poseidon::ConsumerGroup
|
|
41
41
|
options.delete(:trail)
|
42
42
|
super group.id, broker.host, broker.port, group.topic, partition, offset, options
|
43
43
|
end
|
44
|
-
|
45
44
|
end
|
46
45
|
|
47
46
|
# @param [Integer] pnum number of partitions size
|
@@ -97,7 +96,7 @@ class Poseidon::ConsumerGroup
|
|
97
96
|
def initialize(name, brokers, zookeepers, topic, options = {})
|
98
97
|
@name = name
|
99
98
|
@topic = topic
|
100
|
-
@zk = ::ZK.new(zookeepers.join(
|
99
|
+
@zk = ::ZK.new(zookeepers.join(','), {:thread => :per_callback})
|
101
100
|
# Poseidon::BrokerPool doesn't provide default value for this option
|
102
101
|
# Configuring default value like this isn't beautiful, though.. by kssminus
|
103
102
|
options[:socket_timeout_ms] ||= 10000
|
@@ -147,8 +146,8 @@ class Poseidon::ConsumerGroup
|
|
147
146
|
registries.each do |_, path|
|
148
147
|
zk.mkdir_p(path)
|
149
148
|
end
|
150
|
-
zk.create(consumer_path, "{}", ephemeral
|
151
|
-
zk.register(registries[:consumer]) {
|
149
|
+
zk.create(consumer_path, "{}", {:ephemeral => true})
|
150
|
+
zk.register(registries[:consumer]) { rebalance! }
|
152
151
|
|
153
152
|
# Rebalance
|
154
153
|
rebalance!
|
@@ -156,10 +155,12 @@ class Poseidon::ConsumerGroup
|
|
156
155
|
end
|
157
156
|
|
158
157
|
# Reloads metadata/broker/partition information
|
159
|
-
def
|
160
|
-
@metadata = @topic_metadata = nil
|
158
|
+
def reload_metadata
|
159
|
+
@metadata = nil; @topic_metadata = nil
|
161
160
|
metadata
|
162
|
-
|
161
|
+
topic_metadata
|
162
|
+
|
163
|
+
true
|
163
164
|
end
|
164
165
|
|
165
166
|
# Closes the consumer group gracefully, only really useful in tests
|
@@ -178,7 +179,7 @@ class Poseidon::ConsumerGroup
|
|
178
179
|
# @param [Integer] partition
|
179
180
|
# @return [Integer] the latest stored offset for the given partition
|
180
181
|
def offset(partition)
|
181
|
-
data, _ = zk.get
|
182
|
+
data, _ = zk.get(offset_path(partition), {:ignore => :no_node})
|
182
183
|
data.to_i
|
183
184
|
end
|
184
185
|
|
@@ -186,9 +187,9 @@ class Poseidon::ConsumerGroup
|
|
186
187
|
# @param [Integer] partition
|
187
188
|
# @param [Integer] offset
|
188
189
|
def commit(partition, offset)
|
189
|
-
zk.set
|
190
|
+
zk.set(offset_path(partition), offset.to_s)
|
190
191
|
rescue ZK::Exceptions::NoNode
|
191
|
-
zk.create
|
192
|
+
zk.create(offset_path(partition), offset.to_s, {:ignore => :node_exists})
|
192
193
|
end
|
193
194
|
|
194
195
|
# Sorted partitions by broker address (so partitions on the same broker are clustered together)
|
@@ -198,7 +199,7 @@ class Poseidon::ConsumerGroup
|
|
198
199
|
|
199
200
|
topic_metadata.available_partitions.sort_by do |part|
|
200
201
|
broker = metadata.brokers[part.leader]
|
201
|
-
[broker.host, broker.port].join(
|
202
|
+
[broker.host, broker.port].join(':')
|
202
203
|
end
|
203
204
|
end
|
204
205
|
|
@@ -239,6 +240,7 @@ class Poseidon::ConsumerGroup
|
|
239
240
|
unless opts[:commit] == false || commit == false
|
240
241
|
commit consumer.partition, consumer.offset
|
241
242
|
end
|
243
|
+
|
242
244
|
true
|
243
245
|
end
|
244
246
|
|
@@ -345,7 +347,7 @@ class Poseidon::ConsumerGroup
|
|
345
347
|
# Yield over an empty array if nothing claimed,
|
346
348
|
# to allow user to e.g. break out of the loop
|
347
349
|
unless ok
|
348
|
-
yield
|
350
|
+
yield(-1, [])
|
349
351
|
end
|
350
352
|
|
351
353
|
# Sleep if either not claimes or nothing returned
|
@@ -366,28 +368,21 @@ class Poseidon::ConsumerGroup
|
|
366
368
|
# * let POS be our index position in CG and let N = size(PT)/size(CG)
|
367
369
|
# * assign partitions from POS*N to (POS+1)*N-1
|
368
370
|
def rebalance!
|
369
|
-
return if @pending
|
370
|
-
|
371
|
-
@pending = true
|
372
371
|
@mutex.synchronize do
|
373
|
-
@pending = nil
|
374
|
-
|
375
372
|
release_all!
|
376
|
-
|
373
|
+
reload_metadata
|
377
374
|
|
378
|
-
|
379
|
-
|
380
|
-
|
375
|
+
consumer_ids = zk.children(registries[:consumer], {:watch => true}).sort
|
376
|
+
partition_list = partitions
|
377
|
+
responsible_for = self.class.pick(partition_list.size, consumer_ids, id)
|
381
378
|
|
382
|
-
|
383
|
-
if @pending
|
384
|
-
release_all!
|
385
|
-
break
|
386
|
-
end
|
379
|
+
return if responsible_for.nil?
|
387
380
|
|
388
|
-
|
389
|
-
|
390
|
-
|
381
|
+
partition_list[responsible_for].each do |partition|
|
382
|
+
if consumer = claim!(partition.id)
|
383
|
+
@consumers.push(consumer)
|
384
|
+
end
|
385
|
+
end
|
391
386
|
end
|
392
387
|
end
|
393
388
|
|
@@ -395,26 +390,33 @@ class Poseidon::ConsumerGroup
|
|
395
390
|
def release_all!
|
396
391
|
@consumers.each {|c| release!(c.partition) }
|
397
392
|
@consumers.clear
|
393
|
+
|
394
|
+
true
|
398
395
|
end
|
399
396
|
|
400
397
|
private
|
401
398
|
|
402
399
|
# Claim the ownership of the partition for this consumer
|
403
|
-
# @raise [Timeout::Error]
|
404
400
|
def claim!(partition)
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
401
|
+
sleep_duration = 0.1
|
402
|
+
num_tries = ((options[:claim_timout] || DEFAULT_CLAIM_TIMEOUT)/sleep_duration).floor.to_i
|
403
|
+
created = nil
|
404
|
+
|
405
|
+
num_tries.times do
|
406
|
+
created = zk.create(claim_path(partition), id, {:ephemeral => true, :ignore => :node_exists})
|
407
|
+
break if created
|
408
|
+
|
409
|
+
sleep(sleep_duration)
|
411
410
|
end
|
412
|
-
|
411
|
+
|
412
|
+
return nil unless created
|
413
|
+
|
414
|
+
Consumer.new(self, partition, options.dup)
|
413
415
|
end
|
414
416
|
|
415
417
|
# Release ownership of the partition
|
416
418
|
def release!(partition)
|
417
|
-
zk.delete
|
419
|
+
zk.delete(claim_path(partition), {:ignore => :no_node})
|
418
420
|
end
|
419
421
|
|
420
422
|
# @return [String] zookeeper ownership claim path
|
@@ -431,5 +433,4 @@ class Poseidon::ConsumerGroup
|
|
431
433
|
def consumer_path
|
432
434
|
"#{registries[:consumer]}/#{id}"
|
433
435
|
end
|
434
|
-
|
435
436
|
end
|
data/poseidon_cluster.gemspec
CHANGED
@@ -5,10 +5,10 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.name = File.basename(__FILE__, '.gemspec')
|
6
6
|
s.summary = "Poseidon cluster extensions"
|
7
7
|
s.description = "Cluster extensions for Poseidon, a producer and consumer implementation for Kafka >= 0.8"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
|
-
s.authors = ["Black Square Media"]
|
11
|
-
s.email = "
|
10
|
+
s.authors = ["Black Square Media", "Crowdtap Inc."]
|
11
|
+
s.email = "ops@crowdtap.com"
|
12
12
|
s.homepage = "https://github.com/promiscuous-io/poseidon_cluster"
|
13
13
|
|
14
14
|
s.require_path = 'lib'
|
@@ -24,5 +24,4 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_development_dependency "rspec-its"
|
25
25
|
s.add_development_dependency "yard"
|
26
26
|
s.add_development_dependency "coveralls"
|
27
|
-
|
28
27
|
end
|
@@ -8,12 +8,12 @@ describe Poseidon::Cluster do
|
|
8
8
|
|
9
9
|
(0...5).map do
|
10
10
|
Thread.new { 100.times { described_class.inc! }}
|
11
|
-
end.each
|
11
|
+
end.each(&:join)
|
12
12
|
(described_class.inc! - num).should == 502
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should generate GUIDs' do
|
16
|
-
described_class.guid.should match(/\A[\w\-\.]+?\-\d{1,5}\-\d{
|
16
|
+
described_class.guid.should match(/\A[\w\-\.]+?\-\d{1,5}\-\d{9}\-\d{1,3}\z/)
|
17
17
|
end
|
18
18
|
|
19
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: promiscuous-poseidon_cluster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Black Square Media
|
8
|
+
- Crowdtap Inc.
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-04-09 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: poseidon
|
@@ -124,7 +125,7 @@ dependencies:
|
|
124
125
|
version: '0'
|
125
126
|
description: Cluster extensions for Poseidon, a producer and consumer implementation
|
126
127
|
for Kafka >= 0.8
|
127
|
-
email:
|
128
|
+
email: ops@crowdtap.com
|
128
129
|
executables: []
|
129
130
|
extensions: []
|
130
131
|
extra_rdoc_files: []
|