原文:StackExchange.Redis 官方文档(六) PipelinesMultiplexers

流水线和复用

糟糕的时间浪费。现代的计算机以惊人的速度产生大量的数据,而且高速网络通道(通常在重要的服务器之间同时存在多个链路)提供了很高的带宽,但是计算机花费了大量的时间在 等待数据 上面,这也是造成使用持久性链接的编程方式越来越流行的原因之一。常规的编码方式:

  1. string a = db.StringGet("a");
  2. string b = db.StringGet("b");

就步骤而言,它看起来像下面这样:

  1. [req1] # client: the client library constructs request 1
  2. [c=>s] # network: request one is sent to the server
  3. [server] # server: the server processes request 1
  4. [s=>c] # network: response one is sent back to the client
  5. [resp1] # client: the client library parses response 1
  6. [req2]
  7. [c=>s]
  8. [server]
  9. [s=>c]
  10. [resp2]

高亮 client 端正在做的事情:

  1. [req1]
  2. [====waiting=====]
  3. [resp1]
  4. [req2]
  5. [====waiting=====]
  6. [resp2]

如果按照时间缩放的话,就会看到大部分的时间都耗在了 等待 上面。

Pipelining

由于上述的原因,很多 redis 客户端允许使用 pipelining; 这是一种可以一次性通过管道发送多条消息的方式而不用一条一条的发送等.待,而且可以在等到回复时一并处理他们. .NET 的异步方法。

举例来说

  1. var aPending = db.StringGetAsync("a");
  2. var bPending = db.StringGetAsync("b");
  3. var a = db.Wait(aPending);
  4. var b = db.Wait(bPending);

在这里使用 db.Wait 可以自动采用配置的超时时间, 但也可以使用 aPending.Wait() 或者 Task.WaitAll(aPending, bPending);的方式,根据你自己的喜好来. 这样一来 20 个请求可能合并为一个请求。

Fire and Forget

pipelining 的一种特殊场景是,我们并不关心某个操作的返回结果,这样的话我们的代码可以马上接着往下执行,而那个放入到队列中的操作将会在后台执行. 通常来说,这意味我们可以把并行的操作放到一个单独的 caller 的连接上执行. 这种情况下, 我们可以使用 flags 参数达到这样的目的.

  1. // sliding expiration
  2. db.KeyExpire(key, TimeSpan.FromMinutes(5), flags: CommandFlags.FireAndForget);
  3. var value = (string)db.StringGet(key);

FireAndForget 标志使得client library 正常的把要做的事情的排成队列, 但是会马上返回一个默认的值,这个默认值没有任何的实用意义. 这也适用于 *Async 方法:会返回一个已经完成的 Task<T>.

Multiplexing 多路复用

pipelining 已经很好了,但是很多情况下一个代码块只需要一个单独的值 (或许这个代码块希望执行一些简单的操作,但是这些操作是相互依赖的). 这也就是说我们仍然会消耗大量的时间在client和server之间交互等待. 假如有一个业务繁忙的应用, 或许是一个网站服务器. 这些应用往往都是并发的, 所以如果有20个并行的应用请求数据,你可能采用建立20个链接的方式,或者异步使用同一个链接(最后一个请求需要等之前19个完成). 或者做个让步, 使用一个拥有5个链接的程序池 - 但是不管你怎么做,都会有大量的等待发生。StackExchange.Redis 没有做以上的事情 它只是尽可能的充分复用一个链接. 当被不同的调用者同时调用时,它会 自动地将不同的请求放到队列中, 所以无论请求使用同步或者异步的方式,要做的事情都会放到队列中. 所以我们可能有10个或者20个 "get a and b" 的场景,他们都会尽快的获取链接执行命令.

鉴于以上的原因,StackExchange.Redis 没有( 将来也不会 )提供 "blocking pops" (BLPOP, BRPOP and BRPOPLPUSH). 因为这会使得一个单独的调用者减慢整个的多路复用环境,堵塞其他所有的调用者. 唯一的例外 StackExchange.Redis 需要验证事务的先决条件时需要保证工作的时间. 这也是StackExchange.Redis 将这些条件包装在 Condition 的实例中. Read more about transactions here, 如果真的想用 "blocking pops", 这里墙裂建议你使用pub/sub的方式替代.

  1. sub.Subscribe(channel, delegate {
  2. string work = db.ListRightPop(key);
  3. if (work != null) Process(work);
  4. });
  5. //...
  6. db.ListLeftPush(key, newWork, flags: CommandFlags.FireAndForget);
  7. sub.Publish(channel, "");

这实现了相同的目的,而不需要阻塞操作:

  • data 没有通过 pub/sub 的方式发送; pub/sub 只是用来通知worker去检查队列是否有数据
  • 如果没有worker,新的item 会存在list里面; 这项工作也不算是完全失败
  • 一个worker 只能 pop 一个值; 就算有很多的 consumer 消费这个队列,其中的一些 consumer 被通知到也拿不到值去做接下来的事情
  • 当你重启一个worker时,你应该假定队列中有 work 这样可以消费积压的work
  • 但除此之外,语义与 blocking pops相同

StackExchange.Redis的复用特性使得使用普通的简单代码时,在一个连接上达到极高的吞吐量成为可能。.

Concurrency

pipeline / multiplexer / future-value 只会在 continuation-based 的异步代码上起到较好的作用

  1. string value = await db.StringGetAsync(key);
  2. if (value == null) {
  3. value = await ComputeValueFromDatabase(...);
  4. db.StringSet(key, value, flags: CommandFlags.FireAndForget);
  5. }
  6. return value;

转发请标注本文链接地址:(https://www.cnblogs.com/ArvinZhao/p/6825870.html)

StackExchange.Redis 官方文档(六) PipelinesMultiplexers的更多相关文章

  1. StackExchange.Redis 官方文档

    原文:StackExchange.Redis 官方文档 时隔多年的翻译终于完成了第六个,也是很重要的的官方文档,是介绍有关链接管理,管道流水线和多路复用的 官方地址在这里:官方文档 下面做个汇总: S ...

  2. StackExchange.Redis 官方文档(五) Keys, Values and Channels

    原文:StackExchange.Redis 官方文档(五) Keys, Values and Channels Keys, Values and Channels 在使用redis的过程中,要注意到 ...

  3. StackExchange.Redis 官方文档(一) Basics

    基本使用方法: StackExchange.Redis的核心是 StackExchange.Redis 命名空间的 ConnectionMultiplexer 类;它隐藏了多服务器的实现细节.Conn ...

  4. StackExchange.Redis 官方文档(四) KeysScan

    KEYS, SCAN, FLUSHDB 方法在哪? 经常有人问这些问题: 好像并没有看到 Keys(...) 或者 Scan(...)方法?那我要怎么查询数据库里面存有哪些key? 或者 好像没有Fl ...

  5. StackExchange.Redis 官方文档(三) Events

    事件 ConnectionMultiplexer类型提供了很多可以用来了解表面状态下正在发生着什么的事件.这对日志是很有用的. ConfigurationChanged - ConnectionMul ...

  6. StackExchange.Redis 官方文档(二) Configuration

    配置 有多种方式可以配置redis,StackExchange.Redis提供了一个丰富的配置模型,在执行Connect (or ConnectAsync) 时被调用: var conn = Conn ...

  7. Redis官方文档》持久化

    原文链接 译者:Alexandar Mahone 这篇文章从技术层面描述了Redis持久化,建议所有读者阅读.如果希望更多了解Redis持久化和持久性保障,建议阅读Redis持久化揭秘. Redis ...

  8. Redis官方文档资源

    官方文档: 如果要深入研究时,官方提供的文档是最权威的. 英文: https://redis.io/documentation 中文: http://www.redis.cn/documentatio ...

  9. 《Redis官方文档》用Redis构建分布式锁

    用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简 ...

随机推荐

  1. C++的new_handler

    这个new_handler其实对应于signal_handler 当operator new申请一个内存失败时,它会进行如下的处理步骤:1.如果存在客户指定的处理函数,则调用处理函数(new_hand ...

  2. jquery13 attr() prop() val() addClass()等 : 对元素属性的操作

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  3. Linq复杂对象查询

    复杂的查询对象, using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  4. JSP从选择到放弃

    JSP为什么会出现?出现的原因? ①因为在开发web网站时候,返现servlet做界面比较麻烦,于是出现了jsp. 运行在服务端(Java server pages)基于servlet,对servle ...

  5. spring源码分析之@Conditional

    根源在AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext,以AnnotationConfigApplica ...

  6. c# 多态的美丽(虚方法、抽象、接口实现)

    面向对象3大特性:封装.继承.多态. 面向对象2大原则: 1)里氏替换原则:子类可以给父类,父类不能赋给子类. 2)开放封闭原则: 封装变化,降低耦合.(对扩展开放,对修改封闭) ********** ...

  7. 00082_Set接口

    1.Set接口介绍 (1)Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的.那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的 ...

  8. screen-Orientation 横竖屏设置

    1.xml中设置,这个主要是在AndroidManifest.xml 中查找activity,然后在里面设置属性,如下 <application android:label="@str ...

  9. java产生随机数的三种方式

    转自:https://blog.csdn.net/YTTmiao/article/details/78187448 随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串.数字.或者随即生成一个 ...

  10. jQuery post 传递 iframe

    //使用POST链接iframe function doOpenPostIfrm(url, args, iframe) { //创建一个隐藏表单 var _form = $("<for ...