NoSql对于事务的支持

NoSQL数据库(如MongoDB、Cassandra、Hbase、DynamoDB、Riak)让应用程序开发变得更简单。它们提供了相当灵活的数据模型和丰富的数据类型,而且与许多传统数据库系统相比,更易于安装和配置。但缺少原子事务支持却是一大退步。Daniel Abadi是耶鲁大学的一名副教授,主要从事数据库系统架构和实现研究。近日,他在一篇文章中剖析了NoSQL数据库不支持原子事务的原因,并提供了两种实现可扩展、事务型NoSQL数据库的方案。

原子事务允许对数据库中的不同数据项同时进行写操作,这些操作要么全部执行,要么全部不执行。而且,结合恰当的并发控制机制,原子性可以确保并发及后续事务要么可以看到原子事务所有已完成的写入,要么一个都看不到。缺少原子事务,应用程序开发人员就需要自己处理一组写操作仅有部分成功的情况。

也许有人会认为,NoSQL数据库比较新,还没有时间实现原子事务支持。实际上,Cassandra的“批量更新”特性可以视为向这个方向前进了一小步。不过,NoSQL数据库已经出现了将近十年,它们没有实现事务支持显然有更深层次的原因,那就是对可扩展性的关注。按照设计,大多数NoSQL系统都要能够跨多台不同的机器扩展,数据库中的数据分布在不同的机器上。一个事务中的写入操作可能会访问多个分区(在多台机器上)的数据,这就是“分布式事务”。在分布式事务中确保原子性需要参与事务的机器相互协作。每一台机器都必须确定,事务在其它机器上能够成功提交。而且,需要有一个协议,确保事务写入操作涉及的机器在写入数据状态稳定之前都不会出现故障。这个协作过程不仅会消耗大量的资源,而且会增加数据库请求延迟。更大的问题是,在协作过程完成之前,其它操作无法读取该事务写入的数据。并发事务延迟会导致其它与出现延迟的事务在时间上存在重叠的事务延迟,最终导致系统“阻塞(cloggage)”。分布式事务所需的分布式协作会严重影响数据库系统的性能,包括事务吞吐量和事务延迟。因此,大多数NoSQ系统都选择了不支持事务。

MongoDB、Riak、Hbase和Cassandra都支持单个的事务操作。这是因为单个键的所有信息都存储在单台机器上。因此,单个键的事务操作并不涉及上述复杂的分布式协作。由于分布式事务需要分布式协作,所以似乎必须在性能可扩展性和分布式事务支持之间进行权衡。事实上,许多NoSQL数据库提供商都是基于这个假设,在构建可扩展系统时,为了防止服务器性能退化,放弃支持分布式原子事务。

Daniel指出,这是完全错误的。可扩展系统是可以支持高性能分布式原子事务的。他们最近发表了一篇论文,提出了一种在可扩展系统中支持原子事务的、新的权衡策略,具体是在公平性、隔离性和吞吐量(FIT)三者之间进行取舍。其中,公平性是指任何事务的执行都不会因为其它事务被故意延迟,而隔离性可以确保相互冲突的事务可以看到其它事务的写入操作。一个支持分布式原子事务的可扩展数据库至少可以实现上述三个属性中的两个。FIT三者之间的取舍可以产生三种支持分布式原子事务的方案:

  • 保证公平性和隔离性而牺牲吞吐量的系统;
  • 保证公平性和吞吐量而牺牲隔离性的系统;
  • 保证隔离性和吞吐量而牺牲公平性的系统。

换句话说,下面两种方法都可以构建出具备高分布式事务吞吐量的可扩展系统。

放弃隔离性

如上所述,导致数据库系统阻塞的根本原因是分布式协作。更确切地说,如果一个事务正在执行,那么其它需要访问共享数据的事务必须等到分布式协作完成后才能进行。这种等待就是由强隔离性所保证的,因为它确保事务可以看到与它冲突的事务。如果放弃隔离性,那么其它事务就看不到其它事务的操作,也就不必等待分布式协作完成就可以执行和提交。而且,有一类数据库约束可以确保分布式数据库在事务弱隔离情况下的正确性。更多信息可以阅读Peter Bailis的文章《多分区原子读(RAMP)》。

放弃公平性

分布式协作同隔离机制在时间上存在重叠。所以,可以通过重新设定分布式协作的顺序最小化两者之间的时间重叠,从而减轻二者之间的相互影响。以此为基础构建的系统放弃了公平性,可以选择最合适的时间进行分布式协作,Daniel将这样的系统称为“隔离性-吞吐量”系统。比如,可以在事务之外进行协作,协作所需的时间不会增加并发事务的执行时间。

G-Store就是一个很好的“隔离性-吞吐量”系统示例。它支持多键事务,并将事务范围限制为应用程序动态定义的键集,即KeyGroup。该键集可以随需创建和销毁。当应用程序定义了一个KeyGroup,G-Store会将相应的键值对全部复制到一个领导节点上,该键集上的所有事务都会在该领导节点上执行。因此,G-Store事务并不需要在事务执行期间执行分布式提交协议。这里的关键是,G-Store仍然必须执行分布式协作,但协作过程在事务执行之前完成——在需要考虑事务隔离性之前。一旦协作过程完成,事务很快就会完成,共享数据的并发事务就不需要等待分布式协作。这样,G-Store就实现了高吞吐量和强隔离性。

因此,实现高吞吐量分布式事务的关键是按照上述方法在时间上将分布式协作同隔离机制分开。


感谢郭蕾对本文的审校。

<think>嗯,用户想了解Redis中的事务和发布订阅功能的使用指南。首先,我需要回顾一下Redis事务的基本概念。根据引用[2]和[3],Redis事务是一组命令的集合,具有隔离性和原子性。事务中的命令按顺序执行,不会被其他客户端打断,但要注意的是,Redis事务并不是严格意义上的原子操作,因为如果在执行过程中出现错误,只有部分命令可能被执行。 接下来是事务的使用步骤。用户可能需要知道如何开始事务(MULTI)、添加命令(如SET, INCR)、执行事务(EXEC)或取消事务(DISCARD)。还需要提到WATCH命令,用于监控键的变化,实现乐观锁,这在引用[5]中的Java代码示例里也有体现。比如,当使用WATCH监控某个键时,如果在事务执行前该键被修改,事务会被取消。 然后是事务的原子性和错误处理部分。需要区分命令入队错误和运行时错误。入队时的错误,比如命令不存在,会导致整个事务被拒绝;而运行时错误,比如对字符串进行INCR操作,只会导致该命令失败,其他命令仍会执行。这一点需要特别说明,避免用户误解。 关于发布订阅功能,这部分可能在引用中没有详细提到,但根据我的知识,Redis的发布订阅是一种消息通信模式,包括发布者、频道和订阅者。需要介绍PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令,以及使用场景,比如实时消息系统、事件通知等。还要提到订阅者如何监听频道,发布者如何发送消息,以及模式匹配订阅的使用方法。 结合引用中的信息,比如引用[4]提到Redis的应用场景包括消息队列,但发布订阅和列表实现的消息队列有所不同。发布订阅是即时的,而列表更适合持久化消息。需要解释两者的区别,帮助用户理解何时选择哪种方式。 用户可能需要代码示例,但根据用户提供的引用[4]和[5],特别是引用[5]中的Java代码,可以提供一个类似的事务示例,展示如何在Spring Data Redis中使用事务支持。同时,发布订阅的示例可以通过命令行或代码来演示,比如订阅频道的命令和发布消息的命令。 最后,注意事项部分需要总结事务和发布订阅的局限性。比如事务支持回滚,发布订阅的消息是即时的,没有持久化,订阅者断开后会丢失消息等。这些是用户在实际使用中需要注意的地方。 相关问题部分,需要结合用户可能遇到的后续问题,比如事务的原子性保证、与关系型数据库事务的区别、发布订阅和消息队列的对比,以及如何实现分布式锁等。这些问题可以帮助用户深入理解Redis的功能和应用场景。</think>### Redis 事务与发布订阅功能使用指南 #### 一、Redis 事务 ##### 1. 事务特性 - **原子性**:事务中的命令要么全部执行,要么全部不执行(但注意:若运行时出现错误,仅失败的命令不会生效,其他命令仍会执行)[^3] - **隔离性**:事务执行过程中不会被其他客户端请求打断[^3] - **无回滚机制**:与传统数据库不同,Redis 事务支持回滚操作,需开发者自行处理异常 ##### 2. 事务操作命令 ```bash # 开启事务 MULTI # 添加命令到队列(示例) SET key1 "value1" INCR counter ZADD rankings 100 "userA" # 执行事务 EXEC # 取消事务 DISCARD ``` ##### 3. 监控机制(WATCH) 通过 `WATCH` 实现乐观锁,监控键值变化: ```bash WATCH key1 # 监控键 MULTI SET key1 "new_value" EXEC # 若其他客户端修改了 key1,此处事务自动取消 ``` 引用示例代码中的事务实现:[^5] ```java redisTemplate.execute(new SessionCallback<Object>() { @Override public Object execute(RedisOperations operations) { operations.watch("key1"); operations.multi(); // ... 事务操作 operations.exec(); // 提交事务 } }); ``` ##### 4. 错误处理 - **命令入队错误**(如语法错误):整个事务拒绝执行 - **运行时错误**(如对字符串执行 `INCR`):仅该命令失败,其他命令正常执行[^2] --- #### 二、发布订阅(Pub/Sub) ##### 1. 核心命令 | 命令 | 说明 | |----------------------|-----------------------------| | `SUBSCRIBE channel` | 订阅指定频道 | | `PSUBSCRIBE pattern` | 按模式匹配订阅(支持通配符 `*`)| | `PUBLISH channel msg`| 向频道发布消息 | | `UNSUBSCRIBE` | 取消订阅 | ##### 2. 操作示例 ```bash # 客户端A订阅频道 SUBSCRIBE news # 客户端B发布消息 PUBLISH news "Redis 6.0 released!" # 客户端A接收结果: # 1) "message" # 2) "news" # 3) "Redis 6.0 released!" ``` ##### 3. 特性说明 - **实时性**:消息即时推送,无持久化存储 - **无确认机制**:订阅者离线期间的消息会丢失 - **应用场景**:实时通知、聊天系统、状态广播[^4] --- #### 三、对比与注意事项 | 特性 | 事务 | 发布订阅 | |---------------------|-----------------------------|-------------------------| | 数据持久化 | 支持 | 不支持 | | 网络影响 | 命令批量发送减少网络开销 | 实时推送增加网络负载 | | 典型应用场景 | 计数器更新、多命令原子操作[^4] | 实时消息推送、事件通知 | **重要注意事项**: 1. 事务中避免耗时操作,会阻塞其他请求 2. 发布订阅需配合其他机制实现消息持久化 3. 事务的 `WATCH` 可防止数据竞争,但需合理设置超时 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值