Redis RU101课程 Introduction to Redis Data Structures 第3周学习笔记

2024-02-04 12:38

本文主要是介绍Redis RU101课程 Introduction to Redis Data Structures 第3周学习笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Transactions

Introduction

为了保证单条命令的原子性,Redis使用了单线程,命令都是顺序依次执行(unlink是个例外,是异步的)。

事务保证了将多条命令作为一个单元执行。

Using Transactions

事务所有命令:

127.0.0.1:6379> help @transactionsDISCARD -summary: Discard all commands issued after MULTIsince: 2.0.0EXEC -summary: Execute all commands issued after MULTIsince: 1.2.0MULTI -summary: Mark the start of a transaction blocksince: 1.2.0UNWATCH -summary: Forget about all watched keyssince: 2.2.0WATCH key [key ...]summary: Watch the given keys to determine execution of the MULTI/EXEC blocksince: 2.2.0

MULTI相当于begin transaction, MULTI后面的命令会存入命令队列,EXEC一次性执行队列中所有命令,DISCARD放弃队列中所有命令。

可以用2个client来演示事务的隔离性。

multi中不能再嵌套multi,也就是事务不能嵌套。

对于语法错误和数据类型操作错误,不会影响事务中其它的操作,或者说不会引发rollback。其实redis就不支持rollback:

127.0.0.1:6379> set key01 1
OK
127.0.0.1:6379> set key02 a
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby key01 1
QUEUED
127.0.0.1:6379> incrby key02 1
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get key01
"2"

rollback的开销很大,避免rollback也保证了最小延迟和最大吞吐。

对于系统错误,如内存不够,Redis会保证不会出现部分写和不一致性。

传统数据库交易中的命令是马上执行,因此消耗了系统资源;Redis中是将所有命令放入队列,然后一次性执行。

扩展阅读

  • Redis Clients Handling
  • Transactions

Optimistic Concurrency Control

Optimistic Concurrency Control是指监控1个或多个key的变化,如果改变了就放弃事务。这通常是由于你已经读取了这个值。

Optimistic Concurrency Control是通过WATCH和UNWATCH实现的。WATCH必须在事务开始前,事务结束后,会自动UNWATCH。

WATCH命令不是全局的,只影响到调用它的客户端。

client1> set key01 200
OK
client1> watch key01
OK
client1> multi
OK
client1> incrby key01 1
QUEUED
client2> get key01
"200"
client2> decr key01
(integer) 199
client1> exec
(nil)
client1> get key01
"199"

EXEC何时会失败呢? 这里的失败可认为是DISCARD。当命令有语法错误,或WATCH的key被更改时,都会失败。但如果只是操作错误的数据类型,如对字符串加1,则只是忽略这个命令而已。

Object Storage with Hashes

Introduction

用String和Hash都可以存取对象存储,但前者不能增量存取,后者可以单独操作filed,如读写,测试存在,但TTL是针对整个key来设的。

Storing a Simple Object

Hash的多field加value的结构非常类似JSON,而且灵活的schema避免了alter table操作。

HSET可实现JSON结构。相关命令包括HGET, HMGET和HGETALL(阻塞操作,建议小于100 field时用),HSCAN(非阻塞操作)。

小数据集时用HMGET方便,大数据集时建议HSCAN。

HSET时,会自动创建不存在的field,相关包括HEXISTS, HSETNX。

HINCR,HINCRBYFLOAT可对field执行数字操作。

HDEL可删除filed。

Storing Complex Objects

复杂对象,在关系型数据库里就是主从表,在NOSQL中就是带子文档的JSON。

可以用3种方式实现:

  1. 多个Hash
  2. 多个Hash+Set
  3. 单个Hash

Redis推荐方式3,完全平的方式。好处是简单,支持原子操作,无需事务。实现非常类似于层级文件系统到对象存储文件名的映射,用不同的filed name即可实现。例如假设B为子文档:

hmset key B:C value B:D value

不好的地方是删除子文档时需要删除多个field。还有就是设计上的考虑,子文档放在那个父文档中,后续子文档移动时会涉及很多操作。还有就是对象会比拆开存要大。

第2种方式即将子文档单独存为Hash,它和父文档的关系需要通过应用体现,当然在key命名上也可以提示。这种方式的好处为,可独立存放,可扩展,可单独设置TTL。不好的地方是一个对象需要多个key表示,关系需要维护。然后对象所有key需要存在一个shard,这是后话。

Use Case: Inventory Control

Use Case Overview

售票系统,每个用户可以买多张票,有3场比赛,柔道资格赛,男子100m决赛和女子4x100接力预赛。

Inventory Control

流程参考这个图:

在此流程中,减库存和生成订单需放在一个事务中。

示例程序为uc02-inventory-control/inventory.py

示例程序演示了3个测试场景,依次由简单到复杂:

  • 票不够(仅检查票)
  • 票够钱不够,这里假设用户为joan时,钱总是不够(检查票和钱)
  • 持票超过30秒,票返回库存

7个用户, 数据结构如下:

127.0.0.1:6379> scan 0 match uc02:customer* count 30000
1) "0"
2) 1) "uc02:customer:jim"2) "uc02:customer:joan"3) "uc02:customer:jamie"4) "uc02:customer:amy"5) "uc02:customer:mary"6) "uc02:customer:bill"7) "uc02:customer:fred"127.0.0.1:6379> type uc02:customer:jim
hash127.0.0.1:6379> hgetall uc02:customer:jim
1) "id"
2) "jim"
3) "customer_name"
4) "jim somebody"

有3个比赛的票,数据结构如下, 注意其中的余票数和票价:

127.0.0.1:6379> scan 0 match uc02:event:* count 30000
1) "0"
2) 1) "uc02:event:320-GHI-921"2) "uc02:event:123-ABC-723"3) "uc02:event:737-DEF-911"
127.0.0.1:6379> type uc02:event:320-GHI-921
hash
127.0.0.1:6379> hgetall uc02:event:320-GHI-9211) "sku"2) "320-GHI-921"3) "name"4) "Womens Judo Qualifying"5) "disabled_access"6) "False"7) "medal_event"8) "False"9) "venue"
10) "Nippon Budokan"
11) "category"
12) "Martial Arts"
13) "capacity"
14) "14471"
15) "available:General"
16) "500"
17) "price:General"
18) "15.25"
19) "held:General"
20) "0"127.0.0.1:6379> hgetall uc02:event:123-ABC-7231) "sku"2) "123-ABC-723"3) "name"4) "Men's 100m Final"5) "disabled_access"6) "True"7) "medal_event"8) "True"9) "venue"
10) "Olympic Stadium"
11) "category"
12) "Track & Field"
13) "capacity"
14) "60102"
15) "available:General"
16) "10"
17) "price:General"
18) "25.0"127.0.0.1:6379> hgetall uc02:event:737-DEF-9111) "sku"2) "737-DEF-911"3) "name"4) "Women's 4x100m Heats"5) "disabled_access"6) "True"7) "medal_event"8) "False"9) "venue"
10) "Olympic Stadium"
11) "category"
12) "Track & Field"
13) "capacity"
14) "60102"
15) "available:General"
16) "10"
17) "price:General"
18) "19.5"
19) "held:General"
20) "0"

为防止在订票期间库存发生改变,程序使用WATCH监控了相关的库存(例如uc02:event:123-ABC-723)。

订单的数据结构如下,和库存之间通过sku关联:

127.0.0.1:6379> scan 0 match uc02:sales_order:* count 30000
1) "0"
2) 1) "uc02:sales_order:CUJXZN-ITBCOW"2) "uc02:sales_order:RSNKID-SOCIFH"
127.0.0.1:6379> type uc02:sales_order:CUJXZN-ITBCOW
hash
127.0.0.1:6379> hgetall uc02:sales_order:CUJXZN-ITBCOW1) "order_id"2) "CUJXZN-ITBCOW"3) "customer"4) "bill"5) "tier"6) "General"7) "qty"8) "5"9) "cost"
10) "125.0"
11) "event_sku"
12) "123-ABC-723"
13) "ts"
14) "1606361972"

Python代码建议好好看看。

Reservations

场景2中加入了信用卡验证的环节。因此售票过程分多个事务完成。

首先扣票是第一个事务,扣票成功后会生成临时的持票记录。第二个事务围为信用卡验证环节,如果信用卡验证失败,就将持有票返回票库,成功则生成订单,清空持票记录。

通过调试python(python -m pdb)程序,我们得到持票的数据结构, 包括扣票数量,票级别和扣票时间,field名字的后缀时随机字符串:

127.0.0.1:6379> scan 0 match uc02:ticket_hold* count 30000
1) "0"
2) 1) "uc02:ticket_hold:737-DEF-911"
127.0.0.1:6379> type uc02:ticket_hold:737-DEF-911
hash
127.0.0.1:6379> hgetall uc02:ticket_hold:737-DEF-911
1) "qty:KUEBNB-BKFHGK"
2) "5"
3) "tier:KUEBNB-BKFHGK"
4) "General"
5) "ts:KUEBNB-BKFHGK"
6) "1606368660"

对应的库存记录中,在held:General字段也会记录扣票数量。

Expiration of Reservations

场景3模拟的是自动将持票退回库存的场景。比如购票过程中网断了。程序自动生成了3条持票记录,然后进入循环,每个1秒检查持票记录,超过30秒后自动将票返回票库。直到没有持票就退出循环。注意,这里并没有设TTL。

持票定义如下,可以看到到期时间一次为14秒后,8秒后和立刻:

  holds = {'qty:VPIR6X': 3, 'tier:VPIR6X': tier, 'ts:VPIR6X': int(cur_t - 16),'qty:B1BFG7': 5, 'tier:B1BFG7': tier, 'ts:B1BFG7': int(cur_t - 22),'qty:UZ1EL0': 7, 'tier:UZ1EL0': tier, 'ts:UZ1EL0': int(cur_t - 30)}

因此输出如下:

uc02:event:320-GHI-921
== Create ticket holds, expire > 30 sec, return tickets to inventory
320-GHI-921, Available:485, Reservations:['3', '5', '7']
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:492, Reservations:['3', '5', None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:497, Reservations:['3', None, None]
320-GHI-921, Available:500, Reservations:[None, None, None]

最后的建议是,当持票记录多时,建议从Hash改为Sorted Set,然后将时间戳作为value。这样方便提取最先过期的持票记录。
None, None]
320-GHI-921, Available:497, Reservations:[‘3’, None, None]
320-GHI-921, Available:497, Reservations:[‘3’, None, None]
320-GHI-921, Available:497, Reservations:[‘3’, None, None]
320-GHI-921, Available:500, Reservations:[None, None, None]


最后的建议是,当持票记录多时,建议从Hash改为Sorted Set,然后将时间戳作为value。这样方便提取最先过期的持票记录。

这篇关于Redis RU101课程 Introduction to Redis Data Structures 第3周学习笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677530

相关文章

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Redis的持久化之RDB和AOF机制详解

《Redis的持久化之RDB和AOF机制详解》:本文主要介绍Redis的持久化之RDB和AOF机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

SpringBoot连接Redis集群教程

《SpringBoot连接Redis集群教程》:本文主要介绍SpringBoot连接Redis集群教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 依赖2. 修改配置文件3. 创建RedisClusterConfig4. 测试总结1. 依赖 <de

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

浅析如何保证MySQL与Redis数据一致性

《浅析如何保证MySQL与Redis数据一致性》在互联网应用中,MySQL作为持久化存储引擎,Redis作为高性能缓存层,两者的组合能有效提升系统性能,下面我们来看看如何保证两者的数据一致性吧... 目录一、数据不一致性的根源1.1 典型不一致场景1.2 关键矛盾点二、一致性保障策略2.1 基础策略:更新数

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir