# <span style="font-family: Microsoft YaHei">Head of head</span>
在golang的整个生态里,redis client lib全部都使用多连接或者连接池。这是让人难以理解的,所以我和xiaofei一起写了一个同时支持同步和异步的redis client lib:RedisGo-Async。
github地址:https://github.com/gistao/RedisGo-Async。
qq群:131958277。
# <span style="font-family: Microsoft YaHei">同步模式</span>
A -> B
A <- B
A请求,并获取结果,经历1个RTT,这里称之为同步模式。
为了实现高QPS,需要M个AB来处理任务,这样可以得到一个公式:M/RTT。
# <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#%E5%BC%82%E6%AD%A5%E6%A8%A1%E5%BC%8F)异步模式</span>
A -> -> -> B
A <- <- <- B
A请求,不等待应答继续请求,并获取全部结果,经历1个RTT,这里称之为异步模式。
为了实现高QPS,同样可以得到一个公式:C,C表示发包频率。
# <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#%E5%A4%8D%E6%9D%82%E5%BA%A6)复杂度</span>
异步模式一般使用回调,较同步方式复杂的多。但GoRedis-Async提供的两种模式的使用是一样的。
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">conn := pool.Get()
ret, err := conn.Do()
doSomething(ret)` `</pre>
</div>
当你想在两种模式下切换时,这些代码都不用更改。
值得注意的是pipelining,同步模式的使用如下
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">conn.Send(A)
conn.Send(B)
conn.Flush()
conn.Recive() // ret <-A
conn.Recive() // ret <-B</pre>
</div>
而异步模式是天然支持pipelining的,所以使用还是
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">conn.Do(A)
conn.Do(B)</pre>
</div>
有时你会希望同时向Redis serverA,B,C请求,最后一次性来处理结果。同步模式的使用如下
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">connA.Send()
connA.Flush()
connB.Send()
connB.Flush()
connC.Send()
connC.Flush()
connA.Recive()
connB.Recive()
connC.Recive()</pre>
</div>
异步模式使用如下
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">retA := connA.AsyncDo()
retB := connB.AsyncDo()
retC := connC.AsyncDo()
retA.Get()
retC.Get()
retB.Get()</pre>
</div>
# <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#%E6%89%A9%E5%B1%95%E6%80%A7)扩展性</span>
## <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#%E5%90%8C%E6%AD%A5%E6%A8%A1%E5%BC%8Fmrtt)同步模式:M/RTT</span>
在GoRedis-Async里,M表示
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">Pool.MaxActive</pre>
</div>
这个值是固定的,取决于当前测试环境:
1. 应用程序和Redis server的网络RTT
2. 应用程序里的并发度
3. Redis server的连接数上限
4. 本机的连接数上限
5. 本机的CPU核数。
举个关于RTT的例子:
测试环境的网络RTT为1ms,应用程序经测试达到QPS要求后,M被确定到代码中,然后上线到生产环境,而生产环境的RTT为10ms,那么生产环境的QPS就会比预期要低10倍。或者在生产环境里,由于目标Redis server发生故障而被切到了备机,此时备机和应用程序极有可能会跨机房,这也会带来同样的问题。
## <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#%E5%BC%82%E6%AD%A5%E6%A8%A1%E5%BC%8Fc)异步模式:C</span>
在GoRedis-Async里,C只和应用程序的routine数量有关,上边所述的RTT问题在异步模式下并不存在。
当然,在特定范围内都可以被应用程序接受的话,同步和异步模式选择哪种都是适合的。
# <span style="font-family: Microsoft YaHei">[](https://github.com/gistao/RedisGo-Async/wiki/async-or-sync-%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89#mmmin-cost-max-payload)MM(Min cost Max payload)</span>
基础库好坏的一个重要衡量标准就是MM。
同步模式从理论上来说,相比较异步模式需要更多的线程和连接资源。下边是RedisGo-Async、[redigo](https://github.com/garyburd/redigo)、官方redisclient的对比[基准测试报告](https://github.com/gistao/RedisGo-Async/blob/master/bench/benchresult.txt)。Y轴是耗时ms,X轴为各对比库,测试数据为1千万条。
![](https://github.com/gistao/RedisGo-Async/raw/master/bench/bench.png)
有疑问加站长微信联系(非本文作者))