Redis中间件与Web中间件
易混淆概念辨析
在不同的上下文中,“Redis中间件”可以有不同的含义,这可能导致一些混淆。让我们来分解一下:
-
Web中间件与消息中间件的区别:
-
Web中间件:在ASP.NET Core(或类似框架)中,中间件是指处理HTTP请求管道的组件,例如处理请求、认证、日志记录等。这些中间件按顺序构成一个请求处理管道,每个中间件负责对请求进行处理或转发到下一个中间件。在.NET Core中,可以使用 Use 方法将中间件添加到请求处理管道中,例如
app.UseMiddleware()
。 -
消息中间件:消息中间件是一种用于处理消息传递的软件服务,典型的例子包括RabbitMQ、Kafka和Redis等。这些服务允许应用程序在分布式环境中异步发送和接收消息,而Redis服务作为分布式系统的一个请求处理环节,应该称为分布式系统的中间件。在这种情况下,Redis可以作为一种消息中间件来使用,用于发布/订阅模式或队列服务。
-
Web中间件与分布式系统中间件:当我们谈论一个web应用后端时,中间件指的是Web中间件,当我们谈论一个由多个服务组成的分布式系统时,中间件指的是分布式系统的其中一个服务。
-
-
Redis在.NET Core中的角色:
- Redis作为缓存或数据存储:在.NET Core中,Redis通常被用作缓存或数据存储,通过Redis数据库提供的快速读写速度来优化应用程序的性能。这时,Redis被视为一个托管服务,应用程序通过Redis进行数据存储或缓存访问,而不是通过HTTP请求处理管道。
-
混淆的来源:
- 可能的混淆源于术语的多义性。在某些情况下,人们可能将Redis称为中间件,指的是它作为一个提供服务的中介。然而,在严格的技术术语中,Redis通常不被称为Web中间件,而更倾向于被称为数据存储或缓存服务。
综上所述,确实存在一些术语上的混淆,特别是当人们在不同的上下文中使用相同的术语来指代不同的概念时。在.NET Core中,Redis通常不被称为Web中间件,而更适合被称为缓存或数据存储服务。而在消息传递系统中,Redis可以作为消息中间件使用,用于处理分布式系统中的消息传递。
分布式系统中Redis消息中间件使用
分布式系统中的通讯
不同于Web后端,分布式系统由多个独立的程序(也称为服务)组成。同一个程序内通信一般通过函数调用进行。不同程序间通信呢?一般采用消息传递的形式,正如Win32的消息循环一样。所以像Redis
、RabbitMQ
之类的消息中间件就成了分布式系统的重要组成部分
搭建一个分布式系统
-
我们设想这样一个分布式系统
-
服务A是一个webapi系统,提供一些api接口,比如签到接口,获取个人信息接口,获取业务数据接口。平时大家访问量不大,但是签到集中在短时间内,并且要将数据保存到数据库,由于磁盘IO速度限制,所以那时候服务A可能处理不过来,要将签到发送给Redis暂存起来
-
Redis是一个内存数据库,内存IO速度很快,与磁盘IO相比快了5个数量级
-
服务B是一个模板类型为C#控制台程序的签到服务,专门用于从Redis取出签到消息,并输出到控制台
-
-
Redis
Redis安装和基本使用(windows版)
redis通信过程为- 发起连接(可保持)
- 发送set/get请求
- 返回结果
redis添加一个名为
MQ1
的列表List
数据结构存放签到请求,使用LPUSH
+BRPOP
,列表表现为消息队列。 -
服务A
服务A使用CSRedisCore
作为Redis客户端//Program.cs //发起Redis连接 var csredis = new CSRedisClient("127.0.0.1:6379"); //注入到依赖容器 builder.Services.AddSingleton(csredis);
接到Http请求后,使用
LPUSH
将新的请求添加到列表的开始//SignController .cs [ApiController] [Route("[controller]/[action]")] public class SignController : Controller { private readonly CSRedisClient redisClient; public SignController(CSRedisClient redisClient) { this.redisClient = redisClient; } [HttpGet] public IActionResult Sign(string name) { redisClient.LPush("MQ1", name); return Ok(); } }
-
服务B
服务B在一个循环中使用BRPOP
阻塞式的从列表结尾取出旧的请求。设置阻塞超时时间为一个很大的秒数,直到有元素可供取出
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("服务启动!");
//发起Redis连接
var csredis = new CSRedisClient("127.0.0.1:6379");
try
{
while (true)
{
//这里阻塞时间不要大于Redis心跳时间1半
string name = csredis.BRPop(2, "MQ1");
Console.WriteLine(name);
}
}
catch (Exception)
{
}
Console.WriteLine("服务停止!");
}
}
测试
- 100客户端*100次请求:耗时17秒,每个请求平均耗时1.69ms
- 10000个请求中失败了99次
- 500客户端*100次请求:耗时17秒,每个请求平均耗时4.6ms
- 50000个请求中失败了4120次
- 我试了下把最大连接数从15增加到150,请求耗时并无改变,但失败的请求下降到2500多次。而且我观察到前面的几千次都失败了,耗时也很久,大概占了1/2,进程内存在这期间上涨,后面失败的很少,耗时也短。
但是我注释了Redis写入后结果并没太大变化。后面用读出redis消息队列中的值,发现几乎一瞬间就读完了。看起来不是redis慢,而是api服务器慢。也有可能是测试端的锅,毕竟500个线程似乎太多了。
总之初次接触,一脸迷惑。