Redis(二)网络协议和异步方式(乐观锁&悲观锁、事务)

本文涉及的产品
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: Redis(二)网络协议和异步方式(乐观锁&悲观锁、事务)



一、redis网络模型

redis是基于reactor模式设计的内存数据库。

使用reactor模型的好处:

使用 I/O 多路复用来实现对外部请求的处理,可以减少网络连接和读写等待时间。

在网络 I/O 操作中能并发处理大量的客户端请求,实现高吞吐率,高并发。

redis的单线程

redis 单线程是指其网络事件处理模块 是单线程,即指令的执行是在单线程上操作。但是其包括IO读取,网络IO操作都是通过多线程执行的。

执行模块单线程的优点:

  • 采用单线程,避免了不必要的上下文切换和竞争条件;不存在多线程导致的切换而消耗CPU
  • 不用考虑各种锁的问题,不存在加锁和释放锁的的操作,没有因为可能出现的死锁而导致的性能消耗
  • 简单可维护,多线程模式会使得程序的编写更加复杂和麻烦,单线程实现易实现

原因:

  1. redis主要的瓶颈还是在网络IO上,所以在网络IO仍然可以使用多线程接收,发送数据。
  2. 但是redis的数据操作是在内存上,存内存操作的速度还是非常快的,不需要使用多线程来处理。
  3. 并且多线程还有加锁、切换上下文等情景,可能效率还没有单线程高。
  4. 而MySQL由于操作数据是磁盘IO,所以MySQL是采用多线程,会涉及到多线程并发的情况。

二、redis pipeline

redis pipeline 是一个客户端提供的机制,指将多个命令打包同时发送给redis服务端.

例如多个连续的incr指令,使用pipeline(管道)后,多个连续的incr指令会被统一写到发送缓冲区,只会花费一次网络来回开销,这个开销会随着n数值的增大,大幅减少网络io开销,从而提升整体服务的性能。

但是当发送缓冲区或者接收缓冲区满了的话,也会导致阻塞。导致客户端负载过重,整个请求时间变长。所以在使用pipeline时需要注意发送指令的大小。

三、redis事务

事务:用户定义一系列数据库操作,这些操作视为一个完整的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。

事务提供了一种将多个命令打包,然后一次性有序(FIFO)执行的机制。

redis同一个客户端也有连续执行多条指令的场景,所以redis也有事务的执行功能。redis指令执行是单线程的,所以没有mysql事务并发读异常。

事务相关指令

功能 Redis Mysql
开启事务 MULTI begin / start transaction
提交事务 EXEC commit
取消事务 DISCARD rollback
监听 WATCH

MySQL中没有监听功能;watch是redis独有的其功能是检测 key 的变动;

若在事务执行中,key 变动则取消事务;需要在事务开启前调用,乐观锁实现(cas机制);若被取消则事务返回 nil;

乐观锁&悲观锁

悲观锁在执行时,会将其他处理数据库的请求拦截,使其他请求等待。 在mysql中增删改操作、select for update 语句都是悲观锁

乐观锁在执行时,不会将数据锁住,其他客户端可以修改数据,当数据被修改了,本地就不更新,返回失败。

可以从例子看出上述事务逻辑是乐观锁实现,失败需要重试,增加特务逻辑的复杂度。

监听机制原理

监控机制触发:所有对数据库进行修改的命令,如SET、LPUSH、SADD、ZREM、DEL、FLUSHDB等,在执行之后都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的key,有的话touchWatchKey函数会将监视的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端事物安全性已经被破坏。

判断事物是否安全 :当服务器接收到一个客户端发来的EXEC命令时,服务器将会根据这个客户端是否打开REDIS_DIRTY_CAS标识来决定是否执行事物。

在实际工程应用中一般不会用到上述的事务操作。更多的使用脚本执行,例如lua 脚本。在了解lua脚本之前先熟悉一下ACID特性。

ACID特性分析

A 原子性:事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败;redis 不支持回滚;即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。

C 一致性:事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测;这里的一致性是指预期的一致性而不是异常后的一致性;所以 redis 也不满足;这个争议很大:redis 能确保事务执行前后的数据的完整约束;但是并不满足业务功能上的一致性;比如转账功能,一个扣钱一个加钱;可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功;系统凭空多了钱;

I 隔离性:各个事务之间互相影响的程度;redis 是单线程执行,天然具备隔离性;

D 持久性:redis 只有在 aof 持久化策略的时候,并且需要在 redis.conf 中 appendfsync=always 才具备持久性;实际项目中几乎不会使用 aof 持久化策略;

redis天然只满足一致性和隔离性。原子性和持久性不满足。

lua脚本

lua脚本具备原子性;不具备一致性,出现错误不会回滚。同样满足隔离性;持久性不满足。 lua 脚本实现原子性;

redis 中加载了一个 lua 虚拟机;用来执行 redis lua 脚本;

redis lua 脚本的执行是原子性的;当某个脚本正在执行的时候,不会有其他命令或者脚本被执行;

lua 脚本当中的命令会直接修改数据状态;

lua脚本指令

测试使用
EVAL script numkeys key [key ...] arg [arg ...]
# 线上使用
EVALSHA sha1 numkeys key [key ...] arg [arg ...]

注意:如果项目中使用了 lua 脚本,可以不需要使用上面的事务命令;

例如:

异步机制

redis执行命令是在单线程上执行的,且命令结果需要立即返回,所以采用同步IO形式。

但是有些Redis命令不需要等待执行结果,就可以直接返回,例如键值对的删除、清楚数据库等,这类操作就可以采用异步机制。

Redis提供了异步线程机制:

Redis启动时会启动一些子线程,让后将一些任务交给子线程在后台完成,而不需要主线程去执行。这样就可以减轻主线程压力,避免一些阻塞任务降低redis性能。

主线程接收到操作 1 后,操作 1 并不用给客户端返回具体的数据,主线程可以把它交给后台子线程来完成,同时只要给客户端返回一个“OK”结果就行。

在子线程执行操作 1 的时候,客户端又向 Redis 实例发送了操作 2,客户端是需要使用操作 2 返回的数据结果的,如果操作 2 不返回结果,那么客户端将一直处于等待状态。

操作 1 就不算关键路径上的操作,因为它不用给客户端返回具体数据,所以可以由后台子线程异步执行。

操作 2 需要把结果返回给客户端,它就是关键路径上的操作,所以主线程必须立即把这个操作执行完。

  • Redis 主线程启动后,会使用操作系统提供的 pthread_create 函数创建 3 个子线程,负责AOF日志写操作、键值对删除、文件关闭的异步执行。
  • 主线程通过一个链表形式的任务队列和子线程进行交互。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
17天前
|
NoSQL Java Redis
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
26 0
|
17天前
|
存储 消息中间件 缓存
Redis系列学习文章分享---第十七篇(Redis原理篇--数据结构,网络模型)
Redis系列学习文章分享---第十七篇(Redis原理篇--数据结构,网络模型)
30 0
|
20天前
|
缓存 NoSQL Redis
redis管道操作(节省网络IO开销)
pipeline中发送的每个command都会被server立即执行,如果执行失败,将会在此后的响应中得到信息;也就是pipeline并不是表达“所有command都一起成功”的语义,管道中前面命令失败,后面命令不会有影响,继续执行。
18 1
|
24天前
|
JSON Java API
【Android】使用 Retrofit2 发送异步网络请求的简单案例
**摘要:** Retrofit是Android和Java的HTTP客户端库,简化了RESTful API交互。它通过Java接口定义HTTP请求,并提供注解管理参数、HTTP方法等。要使用Retrofit,首先在AndroidManifest.xml中添加`INTERNET`权限,然后在`build.gradle`中引入Retrofit和Gson依赖。创建服务器响应数据类和描述接口的接口,如`Result`和`Api`。通过Retrofit.Builder配置基础URL并构建实例,之后调用接口方法创建Call对象并发送异步请求。
50 1
|
10天前
|
监控 NoSQL Redis
Redis事务和Redis管道
Redis事务和Redis管道
21 0
|
10天前
|
安全 NoSQL Java
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
|
1月前
|
监控 网络协议 Java
Java一分钟之-Netty:高性能异步网络库
【6月更文挑战第11天】Netty是Java的高性能异步网络框架,基于NIO,以其高吞吐量、低延迟、灵活性和安全性受到青睐。常见问题包括内存泄漏、ChannelHandler滥用和异常处理不当。要规避这些问题,需正确释放ByteBuf,精简ChannelPipeline,妥善处理异常,并深入理解Netty原理。通过代码审查、遵循最佳实践和监控日志,可提升代码质量和性能。掌握Netty,打造高效网络服务。
26 2
|
1月前
|
分布式计算 NoSQL 大数据
MaxCompute产品使用合集之自定义udf连接云上vpc网络的redis获取数据的步骤是什么
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
13天前
|
JavaScript API
vue 异步网络请求 axios 【实用教程】(含访问本地接口)
vue 异步网络请求 axios 【实用教程】(含访问本地接口)
18 0
|
17天前
|
NoSQL Redis
Redis系列学习文章分享---第五篇(Redis实战篇--优惠券秒杀,全局唯一id 添加优惠券 实现秒杀下单 库存超卖问题分析 乐观锁解决超卖 实现一人一单功能 集群下的线程并发安全问题)
Redis系列学习文章分享---第五篇(Redis实战篇--优惠券秒杀,全局唯一id 添加优惠券 实现秒杀下单 库存超卖问题分析 乐观锁解决超卖 实现一人一单功能 集群下的线程并发安全问题)
23 0