使用 Redis 实现分布式系统轻量级协调技术

定时任务执行器 立即下载

在分布式系统中,各个进程(本文使用进程来描述分布式系统中的运行主体,它们可以在同一个物理节点上也可以在不同的物理节点上)相互之间通常是需要协调进行运作的,有时是不同进程所处理的数据有依赖关系,必须按照一定的次序进行处理,有时是在一些特定的时间需要某个进程处理某些事务等等,人们通常会使用分布式锁、选举算法等技术来协调各个进程之间的行为。因为分布式系统本身的复杂特性,以及对于容错性的要求,这些技术通常是重量级的,比如 Paxos 算法,欺负选举算法,ZooKeeper 等,侧重于消息的通信而不是共享内存,通常也是出了名的复杂和难以理解,当在具体的实现和实施中遇到问题时都是一个挑战。

Redis 经常被人们认为是一种 NoSQL 软件,但其本质上是一种分布式的数据结构服务器软件,提供了一个分布式的基于内存的数据结构存储服务。在实现上,仅使用一个线程来处理具体的内存数据结构,保证它的数据操作命令的原子特性;它同时还支持基于 Lua 的脚本,每个 Redis 实例使用同一个 Lua 解释器来解释运行 Lua 脚本,从而 Lua 脚本也具备了原子特性,这种原子操作的特性使得基于共享内存模式的分布式系统的协调方式成了可能,而且具备了很大的吸引力,和复杂的基于消息的机制不同,基于共享内存的模式对于很多技术人员来说明显容易理解的多,特别是那些已经了解多线程或多进程技术的人。在具体实践中,也并不是所有的分布式系统都像分布式数据库系统那样需要严格的模型的,而所使用的技术也不一定全部需要有坚实的理论基础和数学证明,这就使得基于 Redis 来实现分布式系统的协调技术具备了一定的实用价值,实际上,人们也已经进行了不少尝试。本文就其中的一些协调技术进行介绍。

signal/wait 操作

在分布式系统中,有些进程需要等待其它进程的状态的改变,或者通知其它进程自己的状态的改变,比如,进程之间有操作上的依赖次序时,就有进程需要等待,有进程需要发射信号通知等待的进程进行后续的操作,这些工作可以通过 Redis 的 Pub/Sub 系列命令来完成,比如:

import redis, time
rc = redis.Redis()

def wait( wait_for ):
 ps = rc.pubsub()
 ps.subscribe( wait_for )
 ps.get_message()
 wait_msg = None
 while True:
 msg = ps.get_message()
 if msg and msg['type'] == 'message':
 wait_msg = msg 
 break
 time.sleep(0.001)
 ps.close()
 return wait_msg

def signal_broadcast( wait_in, data ):
 wait_count = rc.publish(wait_in, data)
 return wait_count

用这个方法很容易进行扩展实现其它的等待策略,比如 try wait,wait 超时,wait 多个信号时是要等待全部信号还是任意一个信号到达即可返回等等。因为 Redis 本身支持基于模式匹配的消息订阅(使用 psubscribe 命令),设置 wait 信号时也可以通过模式匹配的方式进行。

和其它的数据操作不同,订阅消息是即时易逝的,不在内存中保存,不进行持久化保存,如果客户端到服务端的连接断开的话也是不会重发的,但是在配置了 master/slave 节点的情况下,会把 publish 命令同步到 slave 节点上,这样我们就可以同时在 master 以及 slave 节点的连接上订阅某个频道,从而可以同时接收到发布者发布的消息,即使 master 在使用过程中出故障,或者到 master 的连接出了故障,我们仍然能够从 slave 节点获得订阅的消息,从而获得更好的鲁棒性。另外,因为数据不用写入磁盘,这种方法在性能上也是有优势的。

上面的方法中信号是广播的,所有在 wait 的进程都会收到信号,如果要将信号设置成单播,只允许其中一个收到信号,则可以通过约定频道名称模式的方式来实现,比如:

频道名称 = 频道名前缀 (channel) + 订阅者全局唯一 ID(myid)

其中唯一 ID 可以是 UUID,也可以是一个随机数字符串,确保全局唯一即可。在发送 signal 之前先使用“pubsub channels channel*”命令获得所有的订阅者订阅的频道,然后发送信号给其中一个随机指定的频道;等待的时候需要传递自己的唯一 ID,将频道名前缀和唯一 ID 合并为一个频道名称,然后同前面例子一样进行 wait。示例如下:

import random

single_cast_script="""
 local channels = redis.call('pubsub', 'channels', ARGV[1]..'*');
 if #channels == 0 then
 return 0;
 end;
 local index= math.mod(math.floor(tonumber(ARGV[2])), #channels) + 1;
 return redis.call( 'publish', channels[index], ARGV[3]); 
 """

def wait_single( channel, myid):
 return wait( channel + myid )

def signal_single( channel, data):
 rand_num = int(random.random() * 65535)
 return rc.eval( single_cast_script, 0, channel, str(rand_num), str(data) )

分布式锁 Distributed Locks

分布式锁的实现是人们探索的比较多的一个方向,在 Redis 的官方网站上专门有一篇文档介绍基于 Redis 的分布式锁,其中提出了 Redlock 算法,并列出了多种语言的实现案例,这里作一简要介绍。

Redlock 算法着眼于满足分布式锁的三个要素:

  • 安全性:保证互斥,任何时间至多只有一个客户端可以持有锁
  • 免死锁:即使当前持有锁的客户端崩溃或者从集群中被分开了,其它客户端最终总是能够获得锁。
  • 容错性:只要大部分的 Redis 节点在线,那么客户端就能够获取和释放锁。

锁的一个简单直接的实现方法就是用 SET NX 命令设置一个设定了存活周期 TTL 的 Key 来获取锁,通过删除 Key 来释放锁,通过存活周期来保证避免死锁。不过这个方法存在单点故障风险,如果部署了 master/slave 节点,则在特定条件下可能会导致安全性方面的冲突,比如:

  1. 客户端 A 从 master 节点获得锁
  2. master 节点在将 key 复制到 slave 节点之前崩溃了
  3. slave 节点提升为新的 master 节点
  4. 客户端 B 从新的 master 节点获得了锁,而这个锁实际上已经由客户端 A 所持有,导致了系统中有两个客户端在同一时间段内持有同一个互斥锁,破坏了互斥锁的安全性。

在 Redlock 算法中,通过类似于下面这样的命令进行加锁:

SET resource_name my_random_value NX PX 30000

这里的 my_random_value 为全局不同的随机数,每个客户端需要自己产生这个随机数并且记住它,后面解锁的时候需要用到它。

解锁则需要通过一个 Lua 脚本来执行,不能简单地直接删除 Key,否则可能会把别人持有的锁给释放了:

if redis.call("get",KEYS[1]) == ARGV[1] then
 return redis.call("del",KEYS[1])
else
 return 0
end

这个 ARGV[1] 的值就是前面加锁的时候的 my_random_value 的值。

如果需要更好的容错性,可以建立一个有 N(N 为奇数)个相互独立完备的 Redis 冗余节点的集群,这种情况下,一个客户端获得锁和释放锁的算法如下:

  1. 先获取当前时间戳 timestamp_1,以毫秒为单位。
  2. 以相同的 Key 和随机数值,依次从 N 个节点获取锁,每次获取锁都设置一个超时,超时时限要保证小于所有节点上该锁的自动释放时间,以免在某个节点上耗时过长,通常都设的比较短。
  3. 客户端将当前时间戳减去第一步中的时间戳 timestamp_1,计算获取锁总消耗时间。只有当客户端获得了半数以上节点的锁,而且总耗时少于锁存活时间,该客户端才被认为已经成功获得了锁。
  4. 如果获得了锁,则其存活时间为开始预设锁存活时间减去获取锁总耗时间。
  5. 如果客户端不能获得锁,则应该马上在所有节点上解锁。
  6. 如果要重试,则在随机延时之后重新去获取锁。
  7. 获得了锁的客户端要释放锁,简单地在所有节点上解锁即可。

Redlock 算法不需要保证 Redis 节点之间的时钟是同步的(不论是物理时钟还是逻辑时钟),这点和传统的一些基于同步时钟的分布式锁算法有所不同。Redlock 算法的具体的细节可以参阅 Redis 的官方文档,以及文档中列出的多种语言版本的实现。

选举算法

在分布式系统中,经常会有些事务是需要在某个时间段内由一个进程来完成,或者由一个进程作为 leader 来协调其它的进程,这个时候就需要用到选举算法,传统的选举算法有欺负选举算法(霸道选举算法)、环选举算法、Paxos 算法、Zab 算法 (ZooKeeper) 等,这些算法有些依赖于消息的可靠传递以及时钟同步,有些过于复杂,难以实现和验证。新的 Raft 算法相比较其它算法来说已经容易了很多,不过它仍然需要依赖心跳广播和逻辑时钟,leader 需要不断地向 follower 广播消息来维持从属关系,节点扩展时也需要其它算法配合。

选举算法和分布式锁有点类似,任意时刻最多只能有一个 leader 资源。当然,我们也可以用前面描述的分布式锁来实现,设置一个 leader 资源,获得这个资源锁的为 leader,锁的生命周期过了之后,再重新竞争这个资源锁。这是一种竞争性的算法,这个方法会导致有比较多的空档期内没有 leader 的情况,也不好实现 leader 的连任,而 leader 的连任是有比较大的好处的,比如 leader 执行任务可以比较准时一些,查看日志以及排查问题的时候也方便很多,如果我们需要一个算法实现 leader 可以连任,那么可以采用这样的方法:

import redis

rc = redis.Redis()
local_selector = 0

def master():
 global local_selector
 master_selector = rc.incr('master_selector')
 if master_selector == 1:
 # initial / restarted
 local_selector = master_selector
 else:
 if local_selector > 0:
 # I'm the master before
 if local_selector > master_selector:
 # lost, maybe the db is fail-overed.
 local_selector = 0
 else:
 # continue to be the master
 local_selector = master_selector
 if local_selector > 0:
 # I'm the current master
 rc.expire('master_selector', 20)
 return local_selector > 0

这个算法鼓励连任,只有当前的 leader 发生故障或者执行某个任务所耗时间超过了任期、或者 Redis 节点发生故障恢复之后才需要重新选举出新的 leader。在 master/slave 模式下,如果 master 节点发生故障,某个 slave 节点提升为新的 master 节点,即使当时 master_selector 值尚未能同步成功,也不会导致出现两个 leader 的情况。如果某个 leader 一直连任,则 master_selector 的值会一直递增下去,考虑到 master_selector 是一个 64 位的整型类型,在可预见的时间内是不可能溢出的,加上每次进行 leader 更换的时候 master_selector 会重置为从 1 开始,这种递增的方式是可以接受的,但是碰到 Redis 客户端(比如 Node.js)不支持 64 位整型类型的时候就需要针对这种情况作处理。如果当前 leader 进程处理时间超过了任期,则其它进程可以重新生成新的 leader 进程,老的 leader 进程处理完毕事务后,如果新的 leader 的进程经历的任期次数超过或等于老的 leader 进程的任期次数,则可能会出现两个 leader 进程,为了避免这种情况,每个 leader 进程在处理完任期事务之后都应该检查一下自己的处理时间是否超过了任期,如果超过了任期,则应当先设置 local_selector 为 0 之后再调用 master 检查自己是否是 leader 进程。

消息队列

消息队列是分布式系统之间的通信基本设施,通过消息可以构造复杂的进程间的协调操作和互操作。Redis 也提供了构造消息队列的原语,比如 Pub/Sub 系列命令,就提供了基于订阅/发布模式的消息收发方法,但是 Pub/Sub 消息并不在 Redis 内保持,从而也就没有进行持久化,适用于所传输的消息即使丢失了也没有关系的场景。

如果要考虑到持久化,则可以考虑 list 系列操作命令,用 PUSH 系列命令(LPUSH, RPUSH 等)推送消息到某个 list,用 POP 系列命令(LPOP, RPOP,BLPOP,BRPOP 等)获取某个 list 上的消息,通过不同的组合方式可以得到 FIFO,FILO,比如:

import redis
rc = redis.Redis()

def fifo_push(q, data):
 rc.lpush(q, data)

def fifo_pop(q):
 return rc.rpop(q)

def filo_push(q, data):
 rc.lpush(q, data)

def filo_pop(q):
 return rc.lpop(q)

如果用 BLPOP,BRPOP 命令替代 LPOP, RPOP,则在 list 为空的时候还支持阻塞等待。不过,即使按照这种方式实现了持久化,如果在 POP 消息返回的时候网络故障,则依然会发生消息丢失,针对这种需求 Redis 提供了 RPOPLPUSH 和 BRPOPLPUSH 命令来先将提取的消息保存在另外一个 list 中,客户端可以先从这个 list 查看和处理消息数据,处理完毕之后再从这个 list 中删除消息数据,从而确保了消息不会丢失,示例如下:

def safe_fifo_push(q, data):
 rc.lpush(q, data)

def safe_fifo_pop(q, cache):
 msg = rc.rpoplpush(q, cache)
 # check and do something on msg
 rc.lrem(cache, 1) # remove the msg in cache list.
 return msg

如果使用 BRPOPLPUSH 命令替代 RPOPLPUSH 命令,则可以在 q 为空的时候阻塞等待。

结语

使用 Redis 作为分布式系统的共享内存,以共享内存模式为基础来实现分布式系统协调技术,虽然不像传统的基于消息传递的技术那样有着坚实的理论证明的基础,但是它在一些要求不苛刻的情况下不失为一种简单实用的轻量级解决方案,毕竟不是每个系统都需要严格的容错性等要求,也不是每个系统都会频繁地发生进程异常,而且 Redis 本身已经经受了工业界的多年实践和考验。另外,用 Redis 技术还有一些额外的好处,比如在开发过程中和生产环境中都可以直接观察到锁、队列的内容,实施的时候也不需要额外的特别配置过程等,它足够简单,在调试问题的时候逻辑清晰,进行排查和临时干预也比较方便。在可扩展性方面也比较好,可以动态扩展分布式系统的进程数目,而不需要事先预定好进程数目。

Redis 支持基于 Key 值 hash 的集群,在集群中应用本文所述技术时建议另外部署专用 Redis 节点(或者冗余 Redis 节点集群)来使用,因为在基于 Key 值 hash 的集群中,不同的 Key 值会根据 hash 值被分布到不同的集群节点上,而且对于 Lua 脚本的支持也受到限制,难以保证一些操作的原子性,这一点是需要考虑到的。使用专用节点还有一个好处是专用节点的数据量会少很多,当应用了 master/slave 部署或者 AOF 模式的时候,因为数据量少,master 和 slave 之间的同步会少很多,AOF 模式实时写入磁盘的数据也少很多,这样子也可以大大提高可用性。

本文示例所列 Python 代码在 Python3.4 下运行,Redis 客户端采用 redis 2.10.3,Redis 服务端版本为 3.0.1 版。

参考资料

学习

讨论

  • 加入 developerWorks 中文社区,查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
spring的三种任务调度实现方式lib 立即下载

相关推荐

Horae:开源轻量级、高性能的任务执行器

#horae horae : 时序女神,希腊神话中司掌季节时间和人间秩序的三女神,又译“荷莱”。 horae是一个基于redis和实现的轻量级、高性能的异步任务执行器,它的核心是disque提供的任务队列,而队列有先进先出的时序关系,故得名:horae。 horae的关注点不是队列服务的实现本身(已经有不少队列服务的实现了),而是希望借助于redis与disque提供的纯内存的高性能的队列机制,实现一个异步任务执行器。它可以自由配置任务来自哪种队列服务,它不关注任务执行的最终状态(它写向哪里)或与哪个系统交互,它给你提供一个执行器以及简单地编写任务执行逻辑的方式。 取决于需求,这个执行器在要求不高的时候,只需要一个单节点的redis服务器,即可运转。 如果你愿意牺牲一点性能,来换取更高的队列可靠性保障(这种情况我强烈推荐你使用AMQP协议以及它的开源队列实现:RabbitMQ)。如果你想这

好代码实践:基于Redis的轻量级分布式均衡消费队列

简介:好代码,给人第一个印象的感觉,就像一篇好文章一样,读起来朗朗上口。不同的文章有不同的风格体裁,不同的代码也有不同的编程风格要求。Python有严格的缩进,像诗歌一样工整对仗;C语言面向过程像散文一样形散神聚,意境深邃;Java语言面向对象又像是写小说一样,能勾勒出一个一个人物形象。但是无论哪一种文章体裁,他的可读性和可理解性都非常重要,只有文章是可读的可理解的,才会吸引更多的读者去读它,让他流传下去,代码也一样,它的可维护性和可读性也非常重要,保证代码可用性,提高代码的简洁程度和可维护程度,才能让我.

云栖技术精选 196

浅谈Redis在分布式系统中的协调性运用

在分布式系统中,各个进程(本文使用进程来描述分布式系统中的运行主体,它们可以在同一个物理节点上也可以在不同的物理节点上)相互之间通常是需要协调进行运作的,有时是不同进程所处理的数据有依赖关系,必须按照一定的次序进行处理,有时是在一些特定的时间需要某个进程处理某些事务等等,人们通常会使用分布式锁、选举算法等技术来协调各个进程之间的行为。因为分布式系统本身的复杂特性,以及对于容错性的要求,这些技术通常是重量级的,比如 Paxos 算法,欺负选举算法,ZooKeeper 等,侧重于消息的通信而不是共享内存,通常也是出了名的复杂和难以理解,当在具体的实现和实施中遇到问题时都是一个挑战。 Redis 经

一种使用 Redis 深度驱动的,为构建轻量级分布式应用程序(Microservices)的工程方案...

Hydra 是一个轻量级的 NodeJS 库,用于构建分布式计算应用程序,比如微服务。我们对轻量级的定义是:轻处理外部复杂性和基础设施依赖 —— 而不是有限的轻处理。Hydra 声称对基础设施的依赖很轻,这是因为它唯一的外部依赖是 Redis。 Hydra 利用 Redis 丰富的数据结构来实现重要的微服务所需的功能。 如 presence(在线状态)、service discovery (服...

o__cc的博客 213

R3LIVE 1.0 适配 Velodyne 16线雷达:3步配置解决150米漂移问题

本文详细解析了R3LIVE 1.0适配Velodyne 16线雷达时出现的150米漂移问题,并提供三步配置方案。通过调整雷达类型设置、运动补偿与时间对齐、视觉-激光联合优化等关键参数,有效解决了系统漂移问题,提升定位精度。适用于机器人定位与建图领域的开发者。

weixin_29054195的博客 268

Comsol固体力学仿真﹣﹣受均匀内压的厚壁球壳弹塑性分析(加载卸载全流程)

COMSOL固体力学及结构力学仿真较少,故而查询了有关资料,才建立了如下模型。图4 加载卸载全历程中的冯米塞斯应力变化。该有限元模型是通过扫掠而得的结构化网格。图2 加载卸载全历程中的塑型区域变化。图3 加载卸载全历程中的位移应力变化。图6 关键节点第一,第三主应力分布。图5 关键节点应力场与塑性区分布。《弹塑性力学》大作业,记录一下。图1 球体的有限元网格模型。

weixin_62236383的博客 1484

基于Redis实现消息队列的实践

2、定义三个延迟队列BeforeQueue、RunningQueue、CompleteQueue,对队列的任务进行存取,BeforeQueue用于对待执行状态的任务的存取,Running用于对执行中状态的任务的存取,CompleteQueue用于对执行完成状态的任务的存取,在三个任务队列中,取出元素是阻塞的,即如果队列中没有新的任务,当前线程会一直阻塞等待,直到有新的任务进入;因为它是有序集合,有序集合的存储元素值是不能重复的,但分值可以重复,也就是说当消息值重复时,只能存储一条信息在 ZSet 中。

竹林幽深 771

使用 Python 和可视化编程控制树莓派机械臂myCobot

这些模块包括逻辑、循环、数学、文本、列表、颜色、变量、函数以及控制机械臂的函数等等,所以用户可以轻松入门编程,只需单击右上角的运行就可以启动程序,做一些有趣的应用。可以搭配任意摄像头进行图像识别,具有4个 USB 端口,可以通过 Raspberry Pi 的微型 HDMI 端口连接到显示器. 最后,40 个GPIO 接头可以进行更多扩展应用,机械臂每个接口都有清晰的标记,面板上还有一个电源开关和一个直流电源插孔。您现在可以将机器人放在地板或桌子上,并用力拧紧吸盘,以确保机械臂的底座在操作过程中不会移动。

m0_62456998的博客 3965

Redis入门实战:使用Redis实现分布式任务调度的负载均衡

1.背景介绍 随着互联网业务的不断发展,分布式系统已经成为了我们处理大规模数据和高并发请求的首选方案。在分布式系统中,任务调度和负载均衡是非常重要的组件,它们可以确保系统的高性能和高可用性。 Redis是一个开源的高性能键值存储系统,它具有高性能、高可扩展性和高可靠性等优点。在分布式任务调度和负载均衡方面,Redis提供了一些有趣的特性,例如数据结构的丰富性、发布-订阅机制等。 在本文中,我...

AI天才研究院 5631

RS422总线

①.RS422发送驱动器无高阻三态(浮空)状态RS422收发芯片,发送脚固定强驱动输出,永远钳位 A/B 差分电平,不能关断、不能悬空,只要芯片上电,TX+、TX - 就强制输出互补电压(一路高、一路低)。多条发送并联在同一组差分线上:两个驱动器一个拉 A 高、一个拉 A 低,B 线反向拉扯 → 电源→地大电流对灌,瞬间芯片过流发烫烧毁、总线电平短路错乱。注意:RS485 带DE/RE 收发使能脚:不用发送时可关闭驱动器,输出变成高阻浮空,让出总线,因此能多节点分时发送。③.多点通信方式,一主多从方式;

zhuimeng_1234的博客 222

使用fairseq从头开始训练一个中英神经机器翻译模型

前言 由于毕设是做神经机器翻译相关,所以先尝试一下神经机器翻译的整个流程是非常有必要的。故将在news-commentary-v15语料上训练有监督中英NMT模型的整个流程,包括工具和数据的准备、数据的预处理、训练及解码等过程,以及过程中遇到的问题和解决方案记录在此,以供后期回顾,也希望能够给予别人一些帮助。附本人博客 1 相关工具及目录结构 1.1 相关工具 除jieba是使用pip install安装外,其他几个工具都是建议直接克隆库到自己的用户目录中,方便使用其脚本(moses/subword-nmt

qq_42734797的博客 2万+

用redis实现消息队列(实时消费+ack机制)

消息队列 首先做简单的引入。 MQ主要是用来: 解耦应用、 异步化消息 流量削峰填谷 目前使用的较多的有ActiveMQ、RabbitMQ、ZeroMQ、Kafka、MetaMQ、RocketMQ等。网上的资源对各种情况都有详细的解释,在此不做过多赘述。本文仅介绍如何使用Redis实现轻量级MQ的过程。 为什么要用Redis实现轻量级...

weixin_34166472的博客 2307

从零开始:ENSP与VirtualBox的兼容性迷宫与突围指南

本文深入解析eNSP与VirtualBox的兼容性问题,特别是报错40的解决方案。从诊断根源、彻底卸载残留到推荐黄金版本组合,提供了一套完整的实战指南,帮助网络工程师和技术学习者快速解决AR_Base等设备的启动故障,优化虚拟化环境性能。

weixin_29284885的博客 476

redis系列文章

1.基于共享内存模式的分布式系统轻量级协调技术方案,redis实现分布式系统轻量协调技术,包括: signal/wait操作、分布式锁、选举算法、消息队列 ——http://www.ibm.com/developerworks/cn/opensource/os-cn-redis-coordinate/index.html 2.用redis支持优先级消息队列的简单实现 ——http://ww

xiejun_xiaowu 397

【Ragflow】9.问答为什么比搜索响应慢?从源码角度深入分析

前几天看到有群友提到一个现象:Ragflow的搜索界面的问答速度很快,但聊天界面的问答速度很慢,究竟是什么原因?在深入挖掘源码之后,逐渐发现了问题的答案。

兴趣使然的创作者 2898

CANoe软件之离线报文回放与分析实战

本文详细介绍了如何使用CANoe软件进行离线报文回放与分析,帮助工程师将现场故障数据转化为可反复研究的实验室资源。通过实战步骤,指导如何搭建分析工程、加载DBC文件解码信号,并利用Trace和Graphics窗口进行深度数据筛选与图形化分析,从而高效定位汽车电子故障,是提升诊断效率的关键技能。

weixin_29227585的博客 527

Redis100篇 - Redis vs Zookeeper 分布式协调工具对比

Redis与Zookeeper分布式协调工具对比分析 本文深入对比Redis和Zookeeper在分布式协调场景下的应用差异。Zookeeper作为专为协调设计的工具,具备强一致性、临时节点、Watch机制等核心能力,适合服务发现、Leader选举等严格一致性要求的场景。Redis则凭借高性能和原子操作特性,可用于轻量级分布式锁等协调任务,但缺乏可靠的临时节点机制。 文章通过Java代码示例展示了两者在分布式锁实现上的区别:Zookeeper通过Curator框架实现公平锁,会话断开自动释放;Redis通过

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【Redis】分布式系统中的应用——分布式锁、Session 共享、限流熔断、任务队列

在单机环境下,我们可以用或来保证线程安全。但在分布式系统中,多个节点需要协调资源访问,这时候就需要分布式锁了。💡吐槽时间:分布式锁就像抢厕所坑位,谁先占到就是谁的,但问题是——万一有人赖着不走怎么办?这就需要 Redis 来当“管理员”了!Redis 在分布式系统中的应用场景远不止我们今天提到的这些,但它确实为很多经典问题提供了优雅的解决方案。无论是分布式锁、Session 共享,还是限流熔断和任务队列,Redis 都以其高性能和灵活性赢得了开发者的青睐。🎉最后吐槽一句。

silverclayz的技术分享 1623

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Python + Redis + RabbitMQ:构建高可用分布式系统的黄金三角方案

掌握Python分布式系统开发的高效方案,结合Redis缓存与RabbitMQ消息队列,实现任务异步处理与数据高可用。适用于高并发、微服务架构场景,提升系统稳定性与扩展性。构建可扩展分布式架构的实用指南,值得收藏。

ProcePerch的博客 1009

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

zookeeper和redis的应用场景,redis是否能替代zookeeper

zookeeper和redis的应用场景,redis是否能替代zookeeper

梨木乔 1312

Redis Stream:轻量级Kafka替代方案的技术实践

消息队列作为分布式系统解耦的核心组件,其技术选型直接影响系统架构的复杂度与性能。传统方案如Kafka虽具备高吞吐特性,但在中小规模场景下存在资源消耗过大、运维成本高等问题。Redis Stream基于其内置的流数据结构,通过消费组机制实现了完整的消息队列功能,特别适合吞吐量在万级以下的场景。该方案利用Redis原生持久化机制保障数据可靠性,配合Spring生态可实现快速集成,在资源占用和部署复杂度上相比Kafka具有显著优势。典型应用包括实时订单处理、物流跟踪等业务场景,实测在16核服务器上可达6-8万/秒

weixin_29052717的博客 275

从科幻隐喻到工程实践:解码分布式系统状态协调框架设计

在分布式系统与微服务架构中,状态监控与节点协调是保障系统稳定性的核心技术。其核心原理在于通过统一的心跳机制与状态同步协议,确保多节点在复杂环境下能够协同工作,实现数据一致性。这项技术的工程价值在于为大规模、高并发的系统提供了可靠的控制平面,能够有效应对节点故障、网络分区等挑战。典型的应用场景包括微服务网格的健康检查、配置的全局分发、以及跨数据中心的批量运维操作。本文通过一个以“第七旋臂执政官光码协议”为隐喻的框架案例,深入剖析了如何将“全局节奏发生器”与“本地状态调节器”相结合,构建一套**声明式、意图驱动

weixin_30470643的博客 351
上一篇: 一种基于“哨兵”的分布式缓存设计
下一篇: 用ElasticSearch,LogStash,Kibana搭建实时日志收集系统
笑天居士
博客等级 码龄24年 292粉丝 136原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值