当前位置:网站首页>.net core 关于redis的pipeline以及事务
.net core 关于redis的pipeline以及事务
2022-07-07 11:36:00 【小兜全糖(Cx)】
Redis本身是基于Request/Response协议(停等机制)的,正常情况下,客户端发送一个命令,等待Redis返回结果,Redis接收到命令,处理后响应。在这种情况下,如果同时需要执行大量的命令,那就是等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求。为了提升效率,这时候pipeline出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果,这和网络的Nagel算法有点像(TCP_NODELAY选项)。pipeline不仅减少了RTT,同时也减少了IO调用次数(IO调用涉及到用户态到内核态之间的切换)。
要支持Pipeline,其实既要服务端的支持,也要客户端支持。对于服务端来说,所需要的是能够处理一个客户端通过同一个TCP连接发来的多个命令,可以理解为,这里将多个命令切分,和处理单个命令一样(之前老生常谈的黏包现象),Redis就是这样处理的。而客户端,则是要将多个命令缓存起来,缓冲区满了或者达到发送条件就发送出去,最后才处理Redis的应答。
简单描述其实就是一次性发送多个redis命令道服务器,减少了请求次数
Redis的Pipeline和Transaction(Redis事务)不同,Transaction会存储客户端的命令,最后一次性执行,而Pipeline则是处理一条(批次),响应一条,从二者的不同处理机制来看,Redis事务中命令的执行是原子的(注意,其中一部分命令出现错误后续命令会继续执行,这里的原子说的是命令执行是完整的,中间不会被其他Redis命令所打断),而pipeline中命令的执行不一定是原子的。但是这里却有一点不同,就是pipeline机制中,客户端并不会调用read去读取socket里面的缓冲数据(除非已经发完pipeline中所有命令),这也就造成了,如果Redis应答的数据填满了该接收缓冲(SO_RECVBUF),那么客户端会通过ACK,WIN=0(接收窗口)来控制服务端不能再发送数据,那样子,数据就会缓冲在Redis的客户端应答缓冲区里面。所以需要注意控制Pipeline的大小
Batch批量操作
StackExchange.Redis中对于连续多次的缓存等请求,我们会多次调用相关的函数来执行Redis命令。然而这种方式有个弊端就是每一次的请求都需要等待返回结果
如果在网络状况不好的情况下,可能会造成不好的用户体验。
对于这种问题可以用StackExchange.Redis提供的CreateBatch()解决
public void TestPipeLine()
{
IDatabase db = StackExchangeRedisHelper.GetDatabase();
var batch = db.CreateBatch();
Task t1 = batch.StringSetAsync("name", "bob");
Task t2 = batch.StringSetAsync("age", 100);
batch.Execute();
Task.WaitAll(t1, t2);
Console.WriteLine("Age:" + db.StringGet("age"));
Console.WriteLine("Name:" + db.StringGet("name"));
}
redis 的事务有ACID四个特性
redis的事务实际上是运行了multi 命令,然后运行想要运行的命令,最后执行exec命令做一次提交就可以
StackExchange.Redis中的事物控制
multi命令只是保证一个事物中的所有命令可以在一起执行,显然只是实现这一点的话对于大部分的业务都是无法满足的。
所以Redis提供了Watch命令来监控一个key以达到乐观锁的效果。
在StackExchange.Redis是无法用watch multi命令来执行的,因为在并发环境下,会产生多个watch multi命令,全混在一起就乱套了。
但是StackExchange.Redis提供了一套非常简单易懂的创建事物的方式 ,下面为示例代码
public void TestTran()
{
IDatabase db = StackExchangeRedisHelper.GetDatabase();
string name = db.StringGet("name");
string age = db.StringGet("age");
Console.WriteLine("NAME:" + name);
Console.WriteLine("Age:" + age);
var tran = db.CreateTransaction();
tran.AddCondition(Condition.StringEqual("name", name));
Console.WriteLine("tran begin");
tran.StringSetAsync("name", "leap");
tran.StringSetAsync("age", 12);
Thread.Sleep(4000);
bool result = tran.Execute();
Console.WriteLine("执行结果:" + result);
Console.WriteLine("Age:" + db.StringGet("age"));
Console.WriteLine("Name:" + db.StringGet("name"));
}
.net core 中的使用
using CoreRedis.Config;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
namespace CoreRedis.RedisDataType
{
public class RedisPipelineTranc
{
private ConnectionMultiplexer connectionMultiplexer;
private readonly RedisConfig _redisConfig;
private IDatabase db;
public RedisPipelineTranc(IOptionsMonitor<RedisConfig> optionsMonitor)
{
_redisConfig = optionsMonitor.CurrentValue;
connectionMultiplexer = ConnectionMultiplexer.Connect(_redisConfig.Value);
db = connectionMultiplexer.GetDatabase();
}
public async Task<string> testPipelien()
{
// intialize key with empty string
await db.StringSetAsync("key", "");
// create transaction that utilize multiplexing and pipelining
ITransaction transacton = db.CreateTransaction();
Task<long> appendA = transacton.StringAppendAsync("key", "a");
Task<long> appendB = transacton.StringAppendAsync("key", "b");
Task<long> appendc = transacton.StringAppendAsync("key", "c");
if (await transacton.ExecuteAsync()) // sends "MULTI APPEND KEY a APPEND KEY b EXEC
// in single request to redis server
{
order here doesn't matter, result is always - "abc".
'a' and 'b' append always together in isolation of other Redis commands
'c' appends to "ab" because transaction is already executed successfully
//await appendA;
//await db.StringAppendAsync("key", "c");
//await appendB;
Task.WaitAll(appendA, appendB, appendc);
}
string value = db.StringGet("key"); // value is "abc"
return value;
}
}
}
边栏推荐
- Xshell connection server changes key login to password login
- Milkdown 控件图标
- Write it down once Net a new energy system thread surge analysis
- Enregistrement de la navigation et de la mise en service du robot ROS intérieur (expérience de sélection du rayon de dilatation)
- 如何让join跑得更快?
- Mongodb slice summary
- LIS longest ascending subsequence problem (dynamic programming, greed + dichotomy)
- Detr introduction
- cmake 学习使用笔记(一)
- [QNX Hypervisor 2.2用户手册]6.3.4 虚拟寄存器(guest_shm.h)
猜你喜欢
Xshell connection server changes key login to password login
LIS longest ascending subsequence problem (dynamic programming, greed + dichotomy)
Ogre introduction
Esp32 construction engineering add components
Cinnamon Applet 入门
Scrapy教程经典实战【新概念英语】
Japanese government and enterprise employees got drunk and lost 460000 information USB flash drives. They publicly apologized and disclosed password rules
记一次 .NET 某新能源系统 线程疯涨 分析
Custom thread pool rejection policy
JS slow motion animation principle teaching (super detail)
随机推荐
RealBasicVSR测试图片、视频
shell 批量文件名(不含扩展名)小写改大写
Getting started with MySQL
toRaw和markRaw
Mongodb meets spark (for integration)
LIS longest ascending subsequence problem (dynamic programming, greed + dichotomy)
QQ medicine, Tencent ticket
My "troublesome" subordinates after 00: not bad for money, against leaders, and resist overtime
MongoDB复制(副本集)总结
Flink | multi stream conversion
Distributed transaction solution
Signal strength (RSSI) knowledge sorting
SSRF漏洞file伪协议之[网鼎杯 2018]Fakebook1
Ikvm of toolbox Net project new progress
Talk about pseudo sharing
分屏bug 小记
Esp32 construction engineering add components
Cinnamon 任务栏网速
Vscode编辑器ESP32头文件波浪线不跳转彻底解决
cmake 学习使用笔记(一)