使用Redis进行简单分布式处理
大家有没有想要随意实现分布式处理的时候呢?我是有的。
将任务分散到多台服务器上进行处理,并最后将它们的结果整合起来进行处理,这是一种常见的模式。
在尝试实施这种东西时,通常会引入像Kafka之类的消息队列或者Storm、Flink之类的分布式处理引擎,但是对于数据较小且不需要确切一次投递和容错的情况,这样的配置往往会让解决问题变得更加复杂。
在这种情况下,只需要一个Redis就能够粗略地解决问题,我会介绍这种方法给你。
Redis是一种开源的内存数据结构存储系统。
Redis是一个开源的内存NoSQL数据库,通常被用作键值存储(KVS)来缓存数据等。
Redis是一个开源(BSD许可证),用作数据库、缓存和消息代理的内存数据结构存储库。
然而,实际上可以将其用作不仅支持缓存还支持多种数据结构的数据库或消息代理,就像官方文档中所述。
我们将使用支持数据结构之一的List类型和作为消息代理的Pub/Sub功能来实现分布式处理。
以下是一种可能的中文释义:建筑设计
rpop
+-------+ ----------> +----------+
lpush | | publish | Worker 1 |
+--------+ ----------> | | <---------- +----------+
| Master | subscribe | Redis | rpop
+--------+ <---------- | | ----------> +----------+
| | publish | Worker 2 |
+-------+ <---------- +----------+
通过使用lpush、rpop命令来实现List类型的FIFO队列,并通过Pub/Sub将处理结果返回到Master端。由于每个处理过程可以通过键值进行唯一标识,因此可以通过区分键值来连接多个分布式处理,尽管这看起来有点本末倒置,但通过使用Redis Cluster可以扩展Redis本身的规模。然而,由于这种粗糙的分布式处理方式,如果Worker在rpop后崩溃,结果就会丢失,因此在Master端必须实现一些检测方法,例如统计由Master发布的结果数量,来检测这种情况。
示例代码 lì
由于没有特别需要写的东西,我会放一些Ruby的示例代码在这里。
当Master接收到使用reduce键订阅的分布式计算结果时,将停止操作,并将想要进行分布式处理的作业推入使用mapper键的队列中。
# master.rb
require 'redis'
redis = Redis.new
queue = Redis.new
targets = 1..100
t = Thread.new do
count = 0
redis.subscribe('reduce') do |on|
on.message do |channel, message|
puts message
count += 1
redis.unsubscribe if count == targets.size
end
end
end
targets.each do |i|
queue.lpush('mapper', i)
end
t.join
工人方面可以通过不断轮询先前的mapper键队列来接收工作,然后处理它们并发布到reduce键以返回结果。
# worker.rb
require 'redis'
redis = Redis.new
loop do
job = redis.rpop('mapper')
if job.nil?
sleep 5
next
end
dosomething = "mapped#{job}"
redis.publish('reduce', dosomething)
end
就这么多了。
最后
我們使用這個方法成功地將曾經長時間串行運行的 rspec 測試分散執行以實現加速。
在執行測試時,允許至少執行一次,且對可靠性的要求並不是很高。
雖然有幾個現有的測試分散處理框架可供選擇,但考慮到結構的簡單性和通用性,我們選擇了這種方法。
我认为,只要有足够的可信度要求,即使粗糙也足够了。因此,理解权衡并善于采纳这种方法可能是个不错的选择。