<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
	<channel>
		<title>meisw's blog</title>
		<link>http://meisw.wdlinux.cn//</link>
		<description>工作,学习,生活,这里将会有一些记录.     备用域名:http://meisw.wdlinux.cn</description>
		<copyright>Copyright (C) 2004 Security Angel Team [S4T] All Rights Reserved.</copyright>
		<generator>SaBlog-X Version 1.6 Build 20080806</generator>
		<lastBuildDate>Sun, 02 Aug 2026 19:01:55 +0000</lastBuildDate>
		<ttl>30</ttl>
		<item>
			<guid>http://meisw.wdlinux.cn//show-1079-1.html</guid>
			<title>redis从db0迁移数据至db1</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;</p>
<h2 style="box-sizing: border-box; outline: 0px; margin: 8px 0px 16px; padding: 0px; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 24px; color: rgb(79, 79, 79); line-height: 32px; overflow-wrap: break-word; font-variant-ligatures: common-ligatures;">从redis db0中迁移&rsquo;employeeInfo_'为前缀的key到db1中，db0删除该key</h2>
<pre class="prettyprint" style="box-sizing: border-box; outline: 0px; margin-top: 0px; margin-bottom: 24px; padding: 8px 16px 6px 56px; position: relative; font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; overflow: auto hidden; border-top: none; border-right: none; border-bottom: 1px solid rgb(245, 246, 247); border-left: none; border-image: initial; line-height: 22px; overflow-wrap: break-word; background-color: rgb(29, 31, 33); z-index: 9; font-variant-ligatures: common-ligatures;"><code class="has-numbering" style="box-sizing: border-box; outline: 0px; font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; line-height: 22px; color: rgb(197, 200, 198); border-radius: 4px; padding: 0.5em; display: block; overflow-x: auto; overflow-wrap: normal; min-width: 94%; text-size-adjust: none; word-break: break-all; position: unset;">redis-cli -a redis123 -n 0 keys 'employeeInfo_*' | xargs -I '{}' redis-cli -a redis123 -n 0 move '{}' 1 </code><ul class="pre-numbering" style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 8px; padding-bottom: 8px; list-style: none; font-size: 16px; overflow-wrap: normal; position: absolute; width: 48px; top: 0px; left: 0px; text-align: right; word-break: break-all;"><li style="box-sizing: border-box; outline: 0px; margin: 0px; padding: 0px 8px; list-style: none; font-size: inherit; overflow-wrap: normal; border-right: 1px solid rgb(197, 197, 197); color: rgb(153, 153, 153); word-break: break-all;">1</li></ul></pre>
<p style="box-sizing: border-box; outline: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(77, 77, 77); line-height: 26px; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: common-ligatures;">redis-cli -n 0 keys &lsquo;*&rsquo; 表示获取db0中所有的keys<br style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;" />
-a redis123 表示密码redis123<br style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;" />
xargs -I &lsquo;{}&rsquo; 表示将上步操作的结果作为参数,保存在&rsquo;{}'中, 在执行移动db1命令: redis-cli -a redis123 -n 0 move &lsquo;{}&rsquo; 1</p>
<h4 style="box-sizing: border-box; outline: 0px; margin: 8px 0px 16px; padding: 0px; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 20px; color: rgb(79, 79, 79); line-height: 28px; overflow-wrap: break-word; font-variant-ligatures: common-ligatures;">ps:若是Redis带密码，前后都要带上-a 密码</h4>
<p style="box-sizing: border-box; outline: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(77, 77, 77); line-height: 26px; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: common-ligatures;">具体参考<a href="https://www.cnblogs.com/zhoubaojian/articles/7866595.html" style="box-sizing: border-box; outline: none; margin: 0px; padding: 0px; text-decoration-line: none; cursor: pointer; background-color: transparent; color: rgb(103, 149, 181); overflow-wrap: break-word;">redis之间数据迁移 - 开始的第一步 - 博客园</a></p>]]></description>
			<link>http://meisw.wdlinux.cn//show-1079-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2021-01-23 09:24</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-1060-1.html</guid>
			<title>redis-monitor</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;</p>
<ol style="box-sizing: border-box; margin-bottom: 16px; padding-left: 2em; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; font-size: 16px;">
    <li style="box-sizing: border-box;">
    <p style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;">首先安装python库</p>
    <blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 0.25em solid rgb(223, 226, 229); color: rgb(106, 115, 125); padding: 0px 1em;">
    <p style="box-sizing: border-box; margin-bottom: 0px;"><span style="box-sizing: border-box; font-weight: 600;">pip install redis-monitor</span></p>
    </blockquote></li>
    <li style="box-sizing: border-box; margin-top: 0.25em;">
    <p style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;">初始化配置和数据库</p>
    <blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 0.25em solid rgb(223, 226, 229); color: rgb(106, 115, 125); padding: 0px 1em;">
    <p style="box-sizing: border-box; margin-bottom: 0px;"><span style="box-sizing: border-box; font-weight: 600;">redis-monitor init</span></p>
    </blockquote></li>
    <li style="box-sizing: border-box; margin-top: 0.25em;">
    <p style="box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;">启动 webserver</p>
    <blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 0.25em solid rgb(223, 226, 229); color: rgb(106, 115, 125); padding: 0px 1em;">
    <p style="box-sizing: border-box; margin-bottom: 0px;"><span style="box-sizing: border-box; font-weight: 600;">redis-monitor start</span></p>
    </blockquote></li>
</ol>
<p style="box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; font-size: 16px;">然后访问&nbsp;<a href="http://127.0.0.1:9527/" rel="nofollow" style="box-sizing: border-box; background-color: initial; color: rgb(3, 102, 214); text-decoration-line: none;">127.0.0.1:9527</a></p>
<p style="box-sizing: border-box; margin-bottom: 16px;"><font color="#24292e" face="-apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol"><span style="font-size: 16px;">https://github.com/NetEaseGame/redis-monitor</span></font></p>]]></description>
			<link>http://meisw.wdlinux.cn//show-1060-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2018-11-07 16:51</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-1039-1.html</guid>
			<title>redigo的redis.Pool 配置参数调优</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;</p>
<h1 id="配置场景" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 16px; font-size: 28px; color: rgb(79, 79, 79); line-height: 36px; word-break: break-all; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;">配置场景</h1>
<p style="box-sizing: border-box; outline: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(79, 79, 79); line-height: 26px; text-align: justify; word-break: break-all; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;">再来看下主要参数</p>
<ul style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all; color: rgb(51, 51, 51); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;">
    <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">MaxIdle&nbsp;<br style="box-sizing: border-box; outline: 0px; word-break: break-all;" />
    <ul style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">表示连接池空闲连接列表的长度限制</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">空闲列表是一个栈式的结构，先进后出</li>
    </ul>
    </li>
    <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">MaxActive&nbsp;<br style="box-sizing: border-box; outline: 0px; word-break: break-all;" />
    <ul style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">表示连接池中最大连接数限制</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">主要考虑到服务端支持的连接数上限，以及应用之间&rdquo;瓜分&rdquo;连接数</li>
    </ul>
    </li>
    <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">IdleTimeout&nbsp;<br style="box-sizing: border-box; outline: 0px; word-break: break-all;" />
    <ul style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">空闲连接的超时设置，一旦超时，将会从空闲列表中摘除</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 32px; list-style-type: disc; word-break: break-all;">该超时时间时间应该小于服务端的连接超时设置</li>
    </ul>
    </li>
</ul>
<p style="box-sizing: border-box; outline: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(79, 79, 79); line-height: 26px; text-align: justify; word-break: break-all; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;">区分两种使用场景：</p>
<ol style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
    <li style="color: rgb(51, 51, 51); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun; box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">高频调用的场景，需要尽量压榨redis的性能：&nbsp;<br style="box-sizing: border-box; outline: 0px; word-break: break-all;" />
    <ul style="box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">调高MaxIdle的大小，该数目小于maxActive，由于作为一个缓冲区一样的存在，扩大缓冲区自然没有问题</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">调高MaxActive，考虑到服务端的支持上限，尽量调高</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">IdleTimeout由于是高频使用场景，设置短一点也无所谓，需要注意的一点是MaxIdle设置的长了，队列中的过期连接可能会增多，这个时候IdleTimeout也要相应变化</li>
    </ul>
    </li>
    <li style="color: rgb(51, 51, 51); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun; box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">低频调用的场景，调用量远未达到redis的负载，稳定性为重：&nbsp;
    <ul style="color: rgb(51, 51, 51); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun; box-sizing: border-box; outline: 0px; margin-right: 0px; margin-bottom: 24px; margin-left: 0px; list-style: none; word-break: break-all;">
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">MaxIdle可以设置的小一些</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">IdleTimeout相应地设置小一些</li>
        <li style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 8px 0px 0px 40px; list-style-type: decimal; word-break: break-all;">MaxActive随意，够用就好，容易检测到异常</li>
    </ul>
    </li>
    <li style=""><font color="#333333" face="-apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei, SimSun">https://blog.csdn.net/xiaohu50/article/details/51606349</font></li>
</ol>]]></description>
			<link>http://meisw.wdlinux.cn//show-1039-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2018-06-30 15:49</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-1036-1.html</guid>
			<title>Redis 5种主要数据类型和命令</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;https://www.cnblogs.com/mingtianct/p/6291593.html</p>
<p>https://www.cnblogs.com/youxin/p/3833817.html</p>]]></description>
			<link>http://meisw.wdlinux.cn//show-1036-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2018-06-30 10:23</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-997-1.html</guid>
			<title>Redis基础、高级特性与性能调优</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">本文将从Redis的基本特性入手，通过讲述Redis的数据结构和主要命令对Redis的基本能力进行直观介绍。之后概览Redis提供的高级能力，并在部署、维护、性能调优等多个方面进行更深入的介绍和指导。</span></p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">本文适合使用Redis的普通开发人员，以及对Redis进行选型、架构设计和性能调优的架构设计人员。</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">目录</h2>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">概述</li>
    <li style="list-style-type: disc;">Redis的数据结构和相关常用命令</li>
    <li style="list-style-type: disc;">数据持久化</li>
    <li style="list-style-type: disc;">内存管理与数据淘汰机制</li>
    <li style="list-style-type: disc;">Pipelining</li>
    <li style="list-style-type: disc;">事务与Scripting</li>
    <li style="list-style-type: disc;">Redis性能调优</li>
    <li style="list-style-type: disc;">主从复制与集群分片</li>
    <li style="list-style-type: disc;">Redis Java客户端的选择</li>
</ul>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">概述</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis是一个开源的，基于内存的结构化数据存储媒介，可以作为数据库、缓存服务或消息服务使用。<br />
Redis支持多种数据结构，包括字符串、哈希表、链表、集合、有序集合、位图、Hyperloglogs等。<br />
Redis具备LRU淘汰、事务实现、以及不同级别的硬盘持久化等能力，并且支持副本集和通过Redis Sentinel实现的高可用方案，同时还支持通过Redis Cluster实现的数据自动分片能力。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的主要功能都基于单线程模型实现，也就是说Redis使用一个线程来服务所有的客户端请求，同时Redis采用了非阻塞式IO，并精细地优化各种命令的算法时间复杂度，这些信息意味着：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">Redis是线程安全的（因为只有一个线程），其所有操作都是原子的，不会因并发产生数据异常</li>
    <li style="list-style-type: disc;">Redis的速度非常快（因为使用非阻塞式IO，且大部分命令的算法时间复杂度都是O(1))</li>
    <li style="list-style-type: disc;">使用高耗时的Redis命令是很危险的，会占用唯一的一个线程的大量处理时间，导致所有的请求都被拖慢。（例如时间复杂度为O(N)的KEYS命令，严格禁止在生产环境中使用）</li>
</ul>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Redis的数据结构和相关常用命令</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">本节中将介绍Redis支持的主要数据结构，以及相关的常用Redis命令。本节只对Redis命令进行扼要的介绍，且只列出了较常用的命令。如果想要了解完整的Redis命令集，或了解某个命令的详细使用方法，请参考官方文档：<a href="https://redis.io/commands" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands</a></p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Key</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis采用Key-Value型的基本数据结构，任何二进制序列都可以作为Redis的Key使用（例如普通的字符串或一张JPEG图片）<br />
关于Key的一些注意事项：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">不要使用过长的Key。例如使用一个1024字节的key就不是一个好主意，不仅会消耗更多的内存，还会导致查找的效率降低</li>
    <li style="list-style-type: disc;">Key短到缺失了可读性也是不好的，例如&quot;u1000flw&quot;比起&quot;user:1000:followers&quot;来说，节省了寥寥的存储空间，却引发了可读性和可维护性上的麻烦</li>
    <li style="list-style-type: disc;">最好使用统一的规范来设计Key，比如&quot;object-type:id:attr&quot;，以这一规范设计出的Key可能是&quot;user:1000&quot;或&quot;comment:1234:reply-to&quot;</li>
    <li style="list-style-type: disc;">Redis允许的最大Key长度是512MB（对Value的长度限制也是512MB）</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">String</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">String是Redis的基础数据类型，Redis没有Int、Float、Boolean等数据类型的概念，所有的基本类型在Redis中都以String体现。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">与String相关的常用命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>SET</strong>：为一个key设置value，可以配合EX/PX参数指定key的有效期，通过NX/XX参数针对key是否存在的情况进行区别操作，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>GET</strong>：获取某个key对应的value，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>GETSET</strong>：为一个key设置value，并返回该key的原value，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>MSET</strong>：为多个key设置value，时间复杂度O(N)</li>
    <li style="list-style-type: disc;"><strong>MSETNX</strong>：同MSET，如果指定的key中有任意一个已存在，则不进行任何操作，时间复杂度O(N)</li>
    <li style="list-style-type: disc;"><strong>MGET</strong>：获取多个key对应的value，时间复杂度O(N)</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">上文提到过，Redis的基本数据类型只有String，但Redis可以把String作为整型或浮点型数字来使用，主要体现在INCR、DECR类的命令上：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>INCR</strong>：将key对应的value值自增1，并返回自增后的值。只对可以转换为整型的String数据起作用。时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>INCRBY</strong>：将key对应的value值自增指定的整型数值，并返回自增后的值。只对可以转换为整型的String数据起作用。时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>DECR/DECRBY</strong>：同INCR/INCRBY，自增改为自减。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">INCR/DECR系列命令要求操作的value类型为String，并可以转换为64位带符号的整型数字，否则会返回错误。<br />
也就是说，进行INCR/DECR系列命令的value，必须在[-2^63 ~ 2^63 - 1]范围内。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">前文提到过，Redis采用单线程模型，天然是线程安全的，这使得INCR/DECR命令可以非常便利的实现高并发场景下的精确控制。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">例1：库存控制</h4>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在高并发场景下实现库存余量的精准校验，确保不出现超卖的情况。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">设置库存总量：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">SET inv:remain <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;100&quot;</span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">库存扣减+余量校验：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">DECR inv:remain</code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当DECR命令返回值大于等于0时，说明库存余量校验通过，如果返回小于0的值，则说明库存已耗尽。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">假设同时有300个并发请求进行库存扣减，Redis能够确保这300个请求分别得到99到-200的返回值，每个请求得到的返回值都是唯一的，绝对不会找出现两个请求得到一样的返回值的情况。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">例2：自增序列生成</h4>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">实现类似于RDBMS的Sequence功能，生成一系列唯一的序列号</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">设置序列起始值：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">SET sequence <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;10000&quot;</span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">获取一个序列值：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">INCR sequence</code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">直接将返回值作为序列使用即可。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">获取一批（如100个）序列值：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">INCRBY sequence 100</code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">假设返回值为N，那么[N - 99 ~ N]的数值都是可用的序列值。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当多个客户端同时向Redis申请自增序列时，Redis能够确保每个客户端得到的序列值或序列范围都是全局唯一的，绝对不会出现不同客户端得到了重复的序列值的情况。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">List</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的List是链表型的数据结构，可以使用LPUSH/RPUSH/LPOP/RPOP等命令在List的两端执行插入元素和弹出元素的操作。虽然List也支持在特定index上插入和读取元素的功能，但其时间复杂度较高（O(N)），应小心使用。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">与List相关的常用命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>LPUSH</strong>：向指定List的左侧（即头部）插入1个或多个元素，返回插入后的List长度。时间复杂度O(N)，N为插入元素的数量</li>
    <li style="list-style-type: disc;"><strong>RPUSH</strong>：同LPUSH，向指定List的右侧（即尾部）插入1或多个元素</li>
    <li style="list-style-type: disc;"><strong>LPOP</strong>：从指定List的左侧（即头部）移除一个元素并返回，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>RPOP</strong>：同LPOP，从指定List的右侧（即尾部）移除1个元素并返回</li>
    <li style="list-style-type: disc;"><strong>LPUSHX/RPUSHX</strong>：与LPUSH/RPUSH类似，区别在于，LPUSHX/RPUSHX操作的key如果不存在，则不会进行任何操作</li>
    <li style="list-style-type: disc;"><strong>LLEN</strong>：返回指定List的长度，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>LRANGE</strong>：返回指定List中指定范围的元素（双端包含，即LRANGE key 0 10会返回11个元素），时间复杂度O(N)。应尽可能控制一次获取的元素数量，一次获取过大范围的List元素会导致延迟，同时对长度不可预知的List，避免使用LRANGE key 0 -1这样的完整遍历操作。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">应谨慎使用的List相关命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>LINDEX</strong>：返回指定List指定index上的元素，如果index越界，返回nil。index数值是回环的，即-1代表List最后一个位置，-2代表List倒数第二个位置。时间复杂度O(N)</li>
    <li style="list-style-type: disc;"><strong>LSET</strong>：将指定List指定index上的元素设置为value，如果index越界则返回错误，时间复杂度O(N)，如果操作的是头/尾部的元素，则时间复杂度为O(1)</li>
    <li style="list-style-type: disc;"><strong>LINSERT</strong>：向指定List中指定元素之前/之后插入一个新元素，并返回操作后的List长度。如果指定的元素不存在，返回-1。如果指定key不存在，不会进行任何操作，时间复杂度O(N)</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">由于Redis的List是链表结构的，上述的三个命令的算法效率较低，需要对List进行遍历，命令的耗时无法预估，在List长度大的情况下耗时会明显增加，应谨慎使用。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">换句话说，Redis的List实际是设计来用于实现队列，而不是用于实现类似ArrayList这样的列表的。如果你不是想要实现一个双端出入的队列，那么请尽量不要使用Redis的List数据结构。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">为了更好支持队列的特性，Redis还提供了一系列阻塞式的操作命令，如BLPOP/BRPOP等，能够实现类似于BlockingQueue的能力，即在List为空时，阻塞该连接，直到List中有对象可以出队时再返回。针对阻塞类的命令，此处不做详细探讨，请参考官方文档（<a href="https://redis.io/topics/data-types-intro%EF%BC%89" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/topics/data-types-intro）</a>&nbsp;中&quot;Blocking operations on lists&quot;一节。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Hash</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Hash即哈希表，Redis的Hash和传统的哈希表一样，是一种field-value型的数据结构，可以理解成将HashMap搬入Redis。<br />
Hash非常适合用于表现对象类型的数据，用Hash中的field对应对象的field即可。<br />
Hash的优点包括：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">可以实现二元查找，如&quot;查找ID为1000的用户的年龄&quot;</li>
    <li style="list-style-type: disc;">比起将整个对象序列化后作为String存储的方法，Hash能够有效地减少网络传输的消耗</li>
    <li style="list-style-type: disc;">当使用Hash维护一个集合时，提供了比List效率高得多的随机访问命令</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">与Hash相关的常用命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>HSET</strong>：将key对应的Hash中的field设置为value。如果该Hash不存在，会自动创建一个。时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>HGET</strong>：返回指定Hash中field字段的值，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>HMSET/HMGET</strong>：同HSET和HGET，可以批量操作同一个key下的多个field，时间复杂度：O(N)，N为一次操作的field数量</li>
    <li style="list-style-type: disc;"><strong>HSETNX</strong>：同HSET，但如field已经存在，HSETNX不会进行任何操作，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>HEXISTS</strong>：判断指定Hash中field是否存在，存在返回1，不存在返回0，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>HDEL</strong>：删除指定Hash中的field（1个或多个），时间复杂度：O(N)，N为操作的field数量</li>
    <li style="list-style-type: disc;"><strong>HINCRBY</strong>：同INCRBY命令，对指定Hash中的一个field进行INCRBY，时间复杂度O(1)</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">应谨慎使用的Hash相关命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>HGETALL</strong>：返回指定Hash中所有的field-value对。返回结果为数组，数组中field和value交替出现。时间复杂度O(N)</li>
    <li style="list-style-type: disc;"><strong>HKEYS/HVALS</strong>：返回指定Hash中所有的field/value，时间复杂度O(N)</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">上述三个命令都会对Hash进行完整遍历，Hash中的field数量与命令的耗时线性相关，对于尺寸不可预知的Hash，应严格避免使用上面三个命令，而改为使用HSCAN命令进行游标式的遍历，具体请见&nbsp;<a href="https://redis.io/commands/scan" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands/scan</a></p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Set</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis Set是无序的，不可重复的String集合。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">与Set相关的常用命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>SADD</strong>：向指定Set中添加1个或多个member，如果指定Set不存在，会自动创建一个。时间复杂度O(N)，N为添加的member个数</li>
    <li style="list-style-type: disc;"><strong>SREM</strong>：从指定Set中移除1个或多个member，时间复杂度O(N)，N为移除的member个数</li>
    <li style="list-style-type: disc;"><strong>SRANDMEMBER</strong>：从指定Set中随机返回1个或多个member，时间复杂度O(N)，N为返回的member个数</li>
    <li style="list-style-type: disc;"><strong>SPOP</strong>：从指定Set中随机移除并返回count个member，时间复杂度O(N)，N为移除的member个数</li>
    <li style="list-style-type: disc;"><strong>SCARD</strong>：返回指定Set中的member个数，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>SISMEMBER</strong>：判断指定的value是否存在于指定Set中，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>SMOVE</strong>：将指定member从一个Set移至另一个Set</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">慎用的Set相关命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>SMEMBERS</strong>：返回指定Hash中所有的member，时间复杂度O(N)</li>
    <li style="list-style-type: disc;"><strong>SUNION/SUNIONSTORE</strong>：计算多个Set的并集并返回/存储至另一个Set中，时间复杂度O(N)，N为参与计算的所有集合的总member数</li>
    <li style="list-style-type: disc;"><strong>SINTER/SINTERSTORE</strong>：计算多个Set的交集并返回/存储至另一个Set中，时间复杂度O(N)，N为参与计算的所有集合的总member数</li>
    <li style="list-style-type: disc;"><strong>SDIFF/SDIFFSTORE</strong>：计算1个Set与1或多个Set的差集并返回/存储至另一个Set中，时间复杂度O(N)，N为参与计算的所有集合的总member数</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">上述几个命令涉及的计算量大，应谨慎使用，特别是在参与计算的Set尺寸不可知的情况下，应严格避免使用。可以考虑通过SSCAN命令遍历获取相关Set的全部member（具体请见&nbsp;<a href="https://redis.io/commands/scan" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands/scan</a>&nbsp;），如果需要做并集/交集/差集计算，可以在客户端进行，或在不服务实时查询请求的Slave上进行。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Sorted Set</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis Sorted Set是有序的、不可重复的String集合。Sorted Set中的每个元素都需要指派一个分数(score)，Sorted Set会根据score对元素进行升序排序。如果多个member拥有相同的score，则以字典序进行升序排序。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Sorted Set非常适合用于实现排名。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Sorted Set的主要命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>ZADD</strong>：向指定Sorted Set中添加1个或多个member，时间复杂度O(Mlog(N))，M为添加的member数量，N为Sorted Set中的member数量</li>
    <li style="list-style-type: disc;"><strong>ZREM</strong>：从指定Sorted Set中删除1个或多个member，时间复杂度O(Mlog(N))，M为删除的member数量，N为Sorted Set中的member数量</li>
    <li style="list-style-type: disc;"><strong>ZCOUNT</strong>：返回指定Sorted Set中指定score范围内的member数量，时间复杂度：O(log(N))</li>
    <li style="list-style-type: disc;"><strong>ZCARD</strong>：返回指定Sorted Set中的member数量，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>ZSCORE</strong>：返回指定Sorted Set中指定member的score，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>ZRANK/ZREVRANK</strong>：返回指定member在Sorted Set中的排名，ZRANK返回按升序排序的排名，ZREVRANK则返回按降序排序的排名。时间复杂度O(log(N))</li>
    <li style="list-style-type: disc;"><strong>ZINCRBY</strong>：同INCRBY，对指定Sorted Set中的指定member的score进行自增，时间复杂度O(log(N))</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">慎用的Sorted Set相关命令：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>ZRANGE/ZREVRANGE</strong>：返回指定Sorted Set中指定排名范围内的所有member，ZRANGE为按score升序排序，ZREVRANGE为按score降序排序，时间复杂度O(log(N)+M)，M为本次返回的member数</li>
    <li style="list-style-type: disc;"><strong>ZRANGEBYSCORE/ZREVRANGEBYSCORE</strong>：返回指定Sorted Set中指定score范围内的所有member，返回结果以升序/降序排序，min和max可以指定为-inf和+inf，代表返回所有的member。时间复杂度O(log(N)+M)</li>
    <li style="list-style-type: disc;"><strong>ZREMRANGEBYRANK/ZREMRANGEBYSCORE</strong>：移除Sorted Set中指定排名范围/指定score范围内的所有member。时间复杂度O(log(N)+M)</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">上述几个命令，应尽量避免传递[0 -1]或[-inf +inf]这样的参数，来对Sorted Set做一次性的完整遍历，特别是在Sorted Set的尺寸不可预知的情况下。可以通过ZSCAN命令来进行游标式的遍历（具体请见&nbsp;<a href="https://redis.io/commands/scan" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands/scan</a>&nbsp;），或通过LIMIT参数来限制返回member的数量（适用于ZRANGEBYSCORE和ZREVRANGEBYSCORE命令），以实现游标式的遍历。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Bitmap和HyperLogLog</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的这两种数据结构相较之前的并不常用，在本文中只做简要介绍，如想要详细了解这两种数据结构与其相关的命令，请参考官方文档<a href="https://redis.io/topics/data-types-intro" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/topics/data-types-intro</a>&nbsp;中的相关章节</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Bitmap在Redis中不是一种实际的数据类型，而是一种将String作为Bitmap使用的方法。可以理解为将String转换为bit数组。使用Bitmap来存储true/false类型的简单数据极为节省空间。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">HyperLogLogs是一种主要用于数量统计的数据结构，它和Set类似，维护一个不可重复的String集合，但是HyperLogLogs并不维护具体的member内容，只维护member的个数。也就是说，HyperLogLogs只能用于计算一个集合中不重复的元素数量，所以它比Set要节省很多内存空间。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">其他常用命令</h3>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;"><strong>EXISTS</strong>：判断指定的key是否存在，返回1代表存在，0代表不存在，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>DEL</strong>：删除指定的key及其对应的value，时间复杂度O(N)，N为删除的key数量</li>
    <li style="list-style-type: disc;"><strong>EXPIRE/PEXPIRE</strong>：为一个key设置有效期，单位为秒或毫秒，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>TTL/PTTL</strong>：返回一个key剩余的有效时间，单位为秒或毫秒，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>RENAME/RENAMENX</strong>：将key重命名为newkey。使用RENAME时，如果newkey已经存在，其值会被覆盖；使用RENAMENX时，如果newkey已经存在，则不会进行任何操作，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>TYPE</strong>：返回指定key的类型，string, list, set, zset, hash。时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>CONFIG GET</strong>：获得Redis某配置项的当前值，可以使用*通配符，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>CONFIG SET</strong>：为Redis某个配置项设置新值，时间复杂度O(1)</li>
    <li style="list-style-type: disc;"><strong>CONFIG REWRITE</strong>：让Redis重新加载redis.conf中的配置</li>
</ul>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">数据持久化</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供了将数据定期自动持久化至硬盘的能力，包括RDB和AOF两种方案，两种方案分别有其长处和短板，可以配合起来同时运行，确保数据的稳定性。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">必须使用数据持久化吗？</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的数据持久化机制是可以关闭的。如果你只把Redis作为缓存服务使用，Redis中存储的所有数据都不是该数据的主体而仅仅是同步过来的备份，那么可以关闭Redis的数据持久化机制。<br />
但通常来说，仍然建议至少开启RDB方式的数据持久化，因为：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">RDB方式的持久化几乎不损耗Redis本身的性能，在进行RDB持久化时，Redis主进程唯一需要做的事情就是fork出一个子进程，所有持久化工作都由子进程完成</li>
    <li style="list-style-type: disc;">Redis无论因为什么原因crash掉之后，重启时能够自动恢复到上一次RDB快照中记录的数据。这省去了手工从其他数据源（如DB）同步数据的过程，而且要比其他任何的数据恢复方式都要快</li>
    <li style="list-style-type: disc;">现在硬盘那么大，真的不缺那一点地方</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">RDB</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">采用RDB持久方式，Redis会定期保存数据快照至一个rbd文件中，并在启动时自动加载rdb文件，恢复之前保存的数据。可以在配置文件中配置Redis进行快照保存的时机：</p>
<pre class="hljs accesslog" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="accesslog">save <span class="hljs-string" style="color: rgb(163, 21, 21);">[seconds] <span class="hljs-string">[changes]</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">意为在[seconds]秒内如果发生了[changes]次数据修改，则进行一次RDB快照保存，例如</p>
<pre class="hljs lsl" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="lsl">save <span class="hljs-number">60 <span class="hljs-number">100</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">会让Redis每60秒检查一次数据变更情况，如果发生了100次或以上的数据变更，则进行RDB快照保存。<br />
可以配置多条save指令，让Redis执行多级的快照保存策略。<br />
Redis默认开启RDB快照，默认的RDB策略如下：</p>
<pre class="hljs lsl" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="lsl">save <span class="hljs-number">900 <span class="hljs-number">1 save <span class="hljs-number">300 <span class="hljs-number">10 save <span class="hljs-number">60 <span class="hljs-number">10000</span></span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">也可以通过<strong>BGSAVE</strong>命令手工触发RDB快照保存。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;"><strong>RDB的优点：</strong></p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">对性能影响最小。如前文所述，Redis在保存RDB快照时会fork出子进程进行，几乎不影响Redis处理客户端请求的效率。</li>
    <li style="list-style-type: disc;">每次快照会生成一个完整的数据快照文件，所以可以辅以其他手段保存多个时间点的快照（例如把每天0点的快照备份至其他存储媒介中），作为非常可靠的灾难恢复手段。</li>
    <li style="list-style-type: disc;">使用RDB文件进行数据恢复比使用AOF要快很多。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;"><strong>RDB的缺点：</strong></p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">快照是定期生成的，所以在Redis crash时或多或少会丢失一部分数据。</li>
    <li style="list-style-type: disc;">如果数据集非常大且CPU不够强（比如单核CPU），Redis在fork子进程时可能会消耗相对较长的时间（长至1秒），影响这期间的客户端请求。</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">AOF</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">采用AOF持久方式时，Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时，会把AOF文件中记录的所有写操作顺序执行一遍，确保数据恢复到最新。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">AOF默认是关闭的，如要开启，进行如下配置：</p>
<pre class="hljs nginx" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="nginx"><span class="hljs-attribute" style="color: rgb(163, 21, 21);">appendonly <span class="hljs-literal">yes</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">AOF提供了三种fsync配置，always/everysec/no，通过配置项[appendfsync]指定：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">appendfsync no：不进行fsync，将flush文件的时机交给OS决定，速度最快</li>
    <li style="list-style-type: disc;">appendfsync always：每写入一条日志就进行一次fsync操作，数据安全性最高，但速度最慢</li>
    <li style="list-style-type: disc;">appendfsync everysec：折中的做法，交由后台线程每秒fsync一次</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">随着AOF不断地记录写操作日志，必定会出现一些无用的日志，例如某个时间点执行了命令<strong>SET key1 &quot;abc&quot;</strong>，在之后某个时间点又执行了<strong>SET key1 &quot;bcd&quot;</strong>，那么第一条命令很显然是没有用的。大量的无用日志会让AOF文件过大，也会让数据恢复的时间过长。<br />
所以Redis提供了AOF rewrite功能，可以重写AOF文件，只保留能够把数据恢复到最新状态的最小写操作集。<br />
AOF rewrite可以通过<strong>BGREWRITEAOF</strong>命令触发，也可以配置Redis定期自动进行：</p>
<pre class="hljs arduino" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="arduino"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">auto-aof-rewrite-percentage <span class="hljs-number">100 <span class="hljs-keyword">auto-aof-rewrite-<span class="hljs-built_in">min-<span class="hljs-built_in">size <span class="hljs-number">64mb</span></span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">上面两行配置的含义是，Redis在每次AOF rewrite时，会记录完成rewrite后的AOF日志大小，当AOF日志大小在该基础上增长了100%后，自动进行AOF rewrite。同时如果增长的大小没有达到64mb，则不会进行rewrite。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;"><strong>AOF的优点：</strong></p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">最安全，在启用appendfsync always时，任何已写入的数据都不会丢失，使用在启用appendfsync everysec也至多只会丢失1秒的数据。</li>
    <li style="list-style-type: disc;">AOF文件在发生断电等问题时也不会损坏，即使出现了某条日志只写入了一半的情况，也可以使用redis-check-aof工具轻松修复。</li>
    <li style="list-style-type: disc;">AOF文件易读，可修改，在进行了某些错误的数据清除操作后，只要AOF文件没有rewrite，就可以把AOF文件备份出来，把错误的命令删除，然后恢复数据。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;"><strong>AOF的缺点：</strong></p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">AOF文件通常比RDB文件更大</li>
    <li style="list-style-type: disc;">性能消耗比RDB高</li>
    <li style="list-style-type: disc;">数据恢复速度比RDB慢</li>
</ul>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">内存管理与数据淘汰机制</h2>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">最大内存设置</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">默认情况下，在32位OS中，Redis最大使用3GB的内存，在64位OS中则没有限制。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在使用Redis时，应该对数据占用的最大空间有一个基本准确的预估，并为Redis设定最大使用的内存。否则在64位OS中Redis会无限制地占用内存（当物理内存被占满后会使用swap空间），容易引发各种各样的问题。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">通过如下配置控制Redis使用的最大内存：</p>
<pre class="hljs lsl" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="lsl">maxmemory <span class="hljs-number">100mb</span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在内存占用达到了maxmemory后，再向Redis写入数据时，Redis会：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">根据配置的数据淘汰策略尝试淘汰数据，释放空间</li>
    <li style="list-style-type: disc;">如果没有数据可以淘汰，或者没有配置数据淘汰策略，那么Redis会对所有写请求返回错误，但读请求仍然可以正常执行</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在为Redis设置maxmemory时，需要注意：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">如果采用了Redis的主从同步，主节点向从节点同步数据时，会占用掉一部分内存空间，如果maxmemory过于接近主机的可用内存，导致数据同步时内存不足。所以设置的maxmemory不要过于接近主机可用的内存，留出一部分预留用作主从同步。</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">数据淘汰机制</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供了5种数据淘汰策略：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">volatile-lru：使用LRU算法进行数据淘汰（淘汰上次使用时间最早的，且使用次数最少的key），只淘汰设定了有效期的key</li>
    <li style="list-style-type: disc;">allkeys-lru：使用LRU算法进行数据淘汰，所有的key都可以被淘汰</li>
    <li style="list-style-type: disc;">volatile-random：随机淘汰数据，只淘汰设定了有效期的key</li>
    <li style="list-style-type: disc;">allkeys-random：随机淘汰数据，所有的key都可以被淘汰</li>
    <li style="list-style-type: disc;">volatile-ttl：淘汰剩余有效期最短的key</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">最好为Redis指定一种有效的数据淘汰策略以配合maxmemory设置，避免在内存使用满后发生写入失败的情况。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">一般来说，推荐使用的策略是volatile-lru，并辨识Redis中保存的数据的重要性。对于那些重要的，绝对不能丢弃的数据（如配置类数据等），应不设置有效期，这样Redis就永远不会淘汰这些数据。对于那些相对不是那么重要的，并且能够热加载的数据（比如缓存最近登录的用户信息，当在Redis中找不到时，程序会去DB中读取），可以设置上有效期，这样在内存不够时Redis就会淘汰这部分数据。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">配置方法：</p>
<pre class="hljs autoit" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="autoit">maxmemory-policy <span class="hljs-keyword" style="color: rgb(0, 0, 255);">volatile-lru   <span class="hljs-meta" style="color: rgb(43, 145, 175);">#默认是noeviction，即不进行数据淘汰</span></span></code></pre>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Pipelining</h2>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Pipelining</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供许多批量操作的命令，如MSET/MGET/HMSET/HMGET等等，这些命令存在的意义是减少维护网络连接和传输数据所消耗的资源和时间。<br />
例如连续使用5次SET命令设置5个不同的key，比起使用一次MSET命令设置5个不同的key，效果是一样的，但前者会消耗更多的RTT(Round Trip Time)时长，永远应优先使用后者。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">然而，如果客户端要连续执行的多次操作无法通过Redis命令组合在一起，例如：</p>
<pre class="hljs gams" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="gams"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">SET a <span class="hljs-comment" style="color: green;">&quot;abc&quot; INCR <span class="hljs-comment">b HSET <span class="hljs-comment">c name <span class="hljs-comment">&quot;hi&quot;</span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">此时便可以使用Redis提供的pipelining功能来实现在一次交互中执行多条命令。<br />
使用pipelining时，只需要从客户端一次向Redis发送多条命令（以\r\n）分隔，Redis就会依次执行这些命令，并且把每个命令的返回按顺序组装在一起一次返回，比如：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">$ (<span class="hljs-built_in" style="color: rgb(0, 0, 255);">printf <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;PING\r\nPING\r\nPING\r\n&quot;; sleep 1) | nc localhost 6379 +PONG +PONG +PONG</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">大部分的Redis客户端都对Pipelining提供支持，所以开发者通常并不需要自己手工拼装命令列表。</p>
<h5 style="margin: 10px 0px; padding: 0px; font-size: 12px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Pipelining的局限性</h5>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Pipelining只能用于执行<strong>连续且无相关性</strong>的命令，当某个命令的生成需要依赖于前一个命令的返回时，就无法使用Pipelining了。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">通过Scripting功能，可以规避这一局限性</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">事务与Scripting</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Pipelining能够让Redis在一次交互中处理多条命令，然而在一些场景下，我们可能需要在此基础上确保这一组命令是连续执行的。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">比如获取当前累计的PV数并将其清0</p>
<pre class="hljs routeros" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="routeros">&gt; <span class="hljs-builtin-name">GET vCount 12384 &gt; <span class="hljs-builtin-name">SET vCount 0 OK</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">如果在GET和SET命令之间插进来一个INCR vCount，就会使客户端拿到的vCount不准确。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的事务可以确保复数命令执行时的原子性。也就是说Redis能够保证：一个事务中的一组命令是绝对连续执行的，在这些命令执行完成之前，绝对不会有来自于其他连接的其他命令插进去执行。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">通过MULTI和EXEC命令来把这两个命令加入一个事务中：</p>
<pre class="hljs shell" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="shell"><span class="hljs-meta" style="color: rgb(43, 145, 175);">&gt;<span class="bash"> MULTI OK <span class="hljs-meta">&gt;<span class="bash"> GET vCount QUEUED <span class="hljs-meta">&gt;<span class="bash"> SET vCount 0 QUEUED <span class="hljs-meta">&gt;<span class="bash"> EXEC 1) 12384 2) OK</span></span></span></span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis在接收到MULTI命令后便会开启一个事务，这之后的所有读写命令都会保存在队列中但并不执行，直到接收到EXEC命令后，Redis会把队列中的所有命令连续顺序执行，并以数组形式返回每个命令的返回结果。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">可以使用DISCARD命令放弃当前的事务，将保存的命令队列清空。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">需要注意的是，<strong>Redis事务不支持回滚</strong>：<br />
如果一个事务中的命令出现了语法错误，大部分客户端驱动会返回错误，2.6.5版本以上的Redis也会在执行EXEC时检查队列中的命令是否存在语法错误，如果存在，则会自动放弃事务并返回错误。<br />
但如果一个事务中的命令有非语法类的错误（比如对String执行HSET操作），无论客户端驱动还是Redis都无法在真正执行这条命令之前发现，所以事务中的所有命令仍然会被依次执行。在这种情况下，会出现一个事务中部分命令成功部分命令失败的情况，然而与RDBMS不同，Redis不提供事务回滚的功能，所以只能通过其他方法进行数据的回滚。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">通过事务实现CAS</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供了WATCH命令与事务搭配使用，实现CAS乐观锁的机制。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">假设要实现将某个商品的状态改为已售：</p>
<pre class="hljs pf" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="pf">if(exec(HGET stock:<span class="hljs-number">1001 <span class="hljs-keyword" style="color: rgb(0, 0, 255);">state) == <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;in stock&quot;)     exec(HSET stock:<span class="hljs-number">1001 <span class="hljs-keyword" style="color: rgb(0, 0, 255);">state <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;sold&quot;);</span></span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">这一伪代码执行时，无法确保并发安全性，有可能多个客户端都获取到了&quot;in stock&quot;的状态，导致一个库存被售卖多次。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">使用WATCH命令和事务可以解决这一问题：</p>
<pre class="hljs pf" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="pf">exec(WATCH stock:<span class="hljs-number">1001); if(exec(HGET stock:<span class="hljs-number">1001 <span class="hljs-keyword" style="color: rgb(0, 0, 255);">state) == <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;in stock&quot;) {     exec(MULTI);     exec(HSET stock:<span class="hljs-number">1001 <span class="hljs-keyword" style="color: rgb(0, 0, 255);">state <span class="hljs-string" style="color: rgb(163, 21, 21);">&quot;sold&quot;);     exec(EXEC); }</span></span></span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">WATCH的机制是：在事务EXEC命令执行时，Redis会检查被WATCH的key，只有被WATCH的key从WATCH起始时至今没有发生过变更，EXEC才会被执行。如果WATCH的key在WATCH命令到EXEC命令之间发生过变化，则EXEC命令会返回失败。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Scripting</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">通过EVAL与EVALSHA命令，可以让Redis执行LUA脚本。这就类似于RDBMS的存储过程一样，可以把客户端与Redis之间密集的读/写交互放在服务端进行，避免过多的数据交互，提升性能。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Scripting功能是作为事务功能的替代者诞生的，事务提供的所有能力Scripting都可以做到。Redis官方推荐使用LUA Script来代替事务，前者的效率和便利性都超过了事务。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">关于Scripting的具体使用，本文不做详细介绍，请参考官方文档&nbsp;<a href="https://redis.io/commands/eval" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands/eval</a></p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Redis性能调优</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">尽管Redis是一个非常快速的内存数据存储媒介，也并不代表Redis不会产生性能问题。<br />
前文中提到过，Redis采用单线程模型，所有的命令都是由一个线程串行执行的，所以当某个命令执行耗时较长时，会拖慢其后的所有命令，这使得Redis对每个任务的执行效率更加敏感。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">针对Redis的性能优化，主要从下面几个层面入手：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">最初的也是最重要的，确保没有让Redis执行耗时长的命令</li>
    <li style="list-style-type: disc;">使用pipelining将连续执行的命令组合执行</li>
    <li style="list-style-type: disc;">操作系统的Transparent huge pages功能必须关闭：
    <pre class="hljs awk" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word;"><code class="awk">echo never &gt; <span class="hljs-regexp">/sys/kernel<span class="hljs-regexp">/mm/transparent_hugepage<span class="hljs-regexp">/enabled</span></span></span></code></pre>
    </li>
    <li style="list-style-type: disc;">如果在虚拟机中运行Redis，可能天然就有虚拟机环境带来的固有延迟。可以通过./redis-cli --intrinsic-latency 100命令查看固有延迟。同时如果对Redis的性能有较高要求的话，应尽可能在物理机上直接部署Redis。</li>
    <li style="list-style-type: disc;">检查数据持久化策略</li>
    <li style="list-style-type: disc;">考虑引入读写分离机制</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">长耗时命令</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis绝大多数读写命令的时间复杂度都在O(1)到O(N)之间，在文本和官方文档中均对每个命令的时间复杂度有说明。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">通常来说，O(1)的命令是安全的，O(N)命令在使用时需要注意，如果N的数量级不可预知，则应避免使用。例如对一个field数未知的Hash数据执行HGETALL/HKEYS/HVALS命令，通常来说这些命令执行的很快，但如果这个Hash中的field数量极多，耗时就会成倍增长。<br />
又如使用SUNION对两个Set执行Union操作，或使用SORT对List/Set执行排序操作等时，都应该严加注意。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">避免在使用这些O(N)命令时发生问题主要有几个办法：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">不要把List当做列表使用，仅当做队列来使用</li>
    <li style="list-style-type: disc;">通过机制严格控制Hash、Set、Sorted Set的大小</li>
    <li style="list-style-type: disc;">可能的话，将排序、并集、交集等操作放在客户端执行</li>
    <li style="list-style-type: disc;">绝对禁止使用KEYS命令</li>
    <li style="list-style-type: disc;">避免一次性遍历集合类型的所有成员，而应使用SCAN类的命令进行分批的，游标式的遍历</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供了SCAN命令，可以对Redis中存储的所有key进行游标式的遍历，避免使用KEYS命令带来的性能问题。同时还有SSCAN/HSCAN/ZSCAN等命令，分别用于对Set/Hash/Sorted Set中的元素进行游标式遍历。SCAN类命令的使用请参考官方文档：<a href="https://redis.io/commands/scan" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/commands/scan</a></p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis提供了Slow Log功能，可以自动记录耗时较长的命令。相关的配置参数有两个：</p>
<pre class="hljs bash" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="bash">slowlog-log-slower-than xxxms  <span class="hljs-comment" style="color: green;">#执行时间慢于xxx毫秒的命令计入Slow Log slowlog-max-len xxx  <span class="hljs-comment">#Slow Log的长度，即最大纪录多少条Slow Log</span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">使用<strong>SLOWLOG GET [number]</strong>命令，可以输出最近进入Slow Log的number条命令。<br />
使用<strong>SLOWLOG RESET</strong>命令，可以重置Slow Log</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">网络引发的延迟</h3>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">尽可能使用长连接或连接池，避免频繁创建销毁连接</li>
    <li style="list-style-type: disc;">客户端进行的批量数据操作，应使用Pipeline特性在一次交互中完成。具体请参照本文的Pipelining章节</li>
</ul>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">数据持久化引发的延迟</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的数据持久化工作本身就会带来延迟，需要根据数据的安全级别和性能要求制定合理的持久化策略：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">AOF + fsync always的设置虽然能够绝对确保数据安全，但每个操作都会触发一次fsync，会对Redis的性能有比较明显的影响</li>
    <li style="list-style-type: disc;">AOF + fsync every second是比较好的折中方案，每秒fsync一次</li>
    <li style="list-style-type: disc;">AOF + fsync never会提供AOF持久化方案下的最优性能</li>
    <li style="list-style-type: disc;">使用RDB持久化通常会提供比使用AOF更高的性能，但需要注意RDB的策略配置</li>
    <li style="list-style-type: disc;">每一次RDB快照和AOF Rewrite都需要Redis主进程进行fork操作。fork操作本身可能会产生较高的耗时，与CPU和Redis占用的内存大小有关。根据具体的情况合理配置RDB快照和AOF Rewrite时机，避免过于频繁的fork带来的延迟</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 5px 10px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
<p style="margin: 10px auto;">Redis在fork子进程时需要将内存分页表拷贝至子进程，以占用了24GB内存的Redis实例为例，共需要拷贝24GB / 4kB * 8 = 48MB的数据。在使用单Xeon 2.27Ghz的物理机上，这一fork操作耗时216ms。</p>
<p style="margin: 10px auto;">可以通过<strong>INFO</strong>命令返回的latest_fork_usec字段查看上一次fork操作的耗时（微秒）</p>
</blockquote>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Swap引发的延迟</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当Linux将Redis所用的内存分页移至swap空间时，将会阻塞Redis进程，导致Redis出现不正常的延迟。Swap通常在物理内存不足或一些进程在进行大量I/O操作时发生，应尽可能避免上述两种情况的出现。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">/proc/&lt;pid&gt;/smaps文件中会保存进程的swap记录，通过查看这个文件，能够判断Redis的延迟是否由Swap产生。如果这个文件中记录了较大的Swap size，则说明延迟很有可能是Swap造成的。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">数据淘汰引发的延迟</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当同一秒内有大量key过期时，也会引发Redis的延迟。在使用时应尽量将key的失效时间错开。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">引入读写分离机制</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的主从复制能力可以实现一主多从的多节点架构，在这一架构下，主节点接收所有写请求，并将数据同步给多个从节点。<br />
在这一基础上，我们可以让从节点提供对实时性要求不高的读请求服务，以减小主节点的压力。<br />
尤其是针对一些使用了长耗时命令的统计类任务，完全可以指定在一个或多个从节点上执行，避免这些长耗时命令影响其他请求的响应。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">关于读写分离的具体说明，请参见后续章节</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">主从复制与集群分片</h2>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">主从复制</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis支持一主多从的主从复制架构。一个Master实例负责处理所有的写请求，Master将写操作同步至所有Slave。<br />
借助Redis的主从复制，可以实现读写分离和高可用：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">实时性要求不是特别高的读请求，可以在Slave上完成，提升效率。特别是一些周期性执行的统计任务，这些任务可能需要执行一些长耗时的Redis命令，可以专门规划出1个或几个Slave用于服务这些统计任务</li>
    <li style="list-style-type: disc;">借助Redis Sentinel可以实现高可用，当Master crash后，Redis Sentinel能够自动将一个Slave晋升为Master，继续提供服务</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">启用主从复制非常简单，只需要配置多个Redis实例，在作为Slave的Redis实例中配置：</p>
<pre class="hljs lsl" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="lsl">slaveof <span class="hljs-number">192.168<span class="hljs-number">.1<span class="hljs-number">.1 <span class="hljs-number">6379  #指定Master的IP和端口</span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当Slave启动后，会从Master进行一次冷启动数据同步，由Master触发BGSAVE生成RDB文件推送给Slave进行导入，导入完成后Master再将增量数据通过Redis Protocol同步给Slave。之后主从之间的数据便一直以Redis Protocol进行同步</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">使用Sentinel做自动failover</h4>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的主从复制功能本身只是做数据同步，并不提供监控和自动failover能力，要通过主从复制功能来实现Redis的高可用，还需要引入一个组件：Redis Sentinel</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis Sentinel是Redis官方开发的监控组件，可以监控Redis实例的状态，通过Master节点自动发现Slave节点，并在监测到Master节点失效时选举出一个新的Master，并向所有Redis实例推送新的主从配置。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis Sentinel需要至少部署3个实例才能形成选举关系。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">关键配置：</p>
<pre class="hljs smali" style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 13.3333px;"><code class="smali">sentinel<span class="hljs-built_in" style="color: rgb(0, 0, 255);"> monitor mymaster 127.0.0.1 6379 2  <span class="hljs-comment" style="color: green;">#Master实例的IP、端口，以及选举需要的赞成票数 sentinel down-after-milliseconds mymaster 60000  <span class="hljs-comment">#多长时间没有响应视为Master失效 sentinel failover-timeout mymaster 180000  <span class="hljs-comment">#两次failover尝试间的间隔时长 sentinel parallel-syncs mymaster 1  <span class="hljs-comment">#如果有多个Slave，可以通过此配置指定同时从新Master进行数据同步的Slave数，避免所有Slave同时进行数据同步导致查询服务也不可用</span></span></span></span></span></code></pre>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">另外需要注意的是，Redis Sentinel实现的自动failover不是在同一个IP和端口上完成的，也就是说自动failover产生的新Master提供服务的IP和端口与之前的Master是不一样的，所以要实现HA，还要求客户端必须支持Sentinel，能够与Sentinel交互获得新Master的信息才行。</p>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">集群分片</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">为何要做集群分片：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">Redis中存储的数据量大，一台主机的物理内存已经无法容纳</li>
    <li style="list-style-type: disc;">Redis的写请求并发量大，一个Redis实例以无法承载</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">当上述两个问题出现时，就必须要对Redis进行分片了。<br />
Redis的分片方案有很多种，例如很多Redis的客户端都自行实现了分片功能，也有向Twemproxy这样的以代理方式实现的Redis分片方案。然而首选的方案还应该是Redis官方在3.0版本中推出的Redis Cluster分片方案。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">本文不会对Redis Cluster的具体安装和部署细节进行介绍，重点介绍Redis Cluster带来的好处与弊端。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Redis Cluster的能力</h4>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">能够自动将数据分散在多个节点上</li>
    <li style="list-style-type: disc;">当访问的key不在当前分片上时，能够自动将请求转发至正确的分片</li>
    <li style="list-style-type: disc;">当集群中部分节点失效时仍能提供服务</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">其中第三点是基于主从复制来实现的，Redis Cluster的每个数据分片都采用了主从复制的结构，原理和前文所述的主从复制完全一致，唯一的区别是省去了Redis Sentinel这一额外的组件，由Redis Cluster负责进行一个分片内部的节点监控和自动failover。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Redis Cluster分片原理</h4>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis Cluster中共有16384个hash slot，Redis会计算每个key的CRC16，将结果与16384取模，来决定该key存储在哪一个hash slot中，同时需要指定Redis Cluster中每个数据分片负责的Slot数。Slot的分配在任何时间点都可以进行重新分配。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">客户端在对key进行读写操作时，可以连接Cluster中的任意一个分片，如果操作的key不在此分片负责的Slot范围内，Redis Cluster会自动将请求重定向到正确的分片上。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">hash tags</h4>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在基础的分片原则上，Redis还支持hash tags功能，以hash tags要求的格式明明的key，将会确保进入同一个Slot中。例如：{uiv}user:1000和{uiv}user:1001拥有同样的hash tag {uiv}，会保存在同一个Slot中。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">使用Redis Cluster时，pipelining、事务和LUA Script功能涉及的key必须在同一个数据分片上，否则将会返回错误。如要在Redis Cluster中使用上述功能，就必须通过hash tags来确保一个pipeline或一个事务中操作的所有key都位于同一个Slot中。</p>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 5px 10px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
<p style="margin: 10px auto;">有一些客户端（如Redisson）实现了集群化的pipelining操作，可以自动将一个pipeline里的命令按key所在的分片进行分组，分别发到不同的分片上执行。但是Redis不支持跨分片的事务，事务和LUA Script还是必须遵循所有key在一个分片上的规则要求。</p>
</blockquote>
<h3 style="font-size: 16px; border-bottom: 1px dotted rgb(214, 214, 214); line-height: 1.5; margin: 10px 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">主从复制 vs 集群分片</h3>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在设计软件架构时，要如何在主从复制和集群分片两种部署方案中取舍呢？</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">从各个方面看，Redis Cluster都是优于主从复制的方案</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">Redis Cluster能够解决单节点上数据量过大的问题</li>
    <li style="list-style-type: disc;">Redis Cluster能够解决单节点访问压力过大的问题</li>
    <li style="list-style-type: disc;">Redis Cluster包含了主从复制的能力</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">那是不是代表Redis Cluster永远是优于主从复制的选择呢？</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">并不是。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">软件架构永远不是越复杂越好，复杂的架构在带来显著好处的同时，一定也会带来相应的弊端。采用Redis Cluster的弊端包括：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">维护难度增加。在使用Redis Cluster时，需要维护的Redis实例数倍增，需要监控的主机数量也相应增加，数据备份/持久化的复杂度也会增加。同时在进行分片的增减操作时，还需要进行reshard操作，远比主从模式下增加一个Slave的复杂度要高。</li>
    <li style="list-style-type: disc;">客户端资源消耗增加。当客户端使用连接池时，需要为每一个数据分片维护一个连接池，客户端同时需要保持的连接数成倍增多，加大了客户端本身和操作系统资源的消耗。</li>
    <li style="list-style-type: disc;">性能优化难度增加。你可能需要在多个分片上查看Slow Log和Swap日志才能定位性能问题。</li>
    <li style="list-style-type: disc;">事务和LUA Script的使用成本增加。在Redis Cluster中使用事务和LUA Script特性有严格的限制条件，事务和Script中操作的key必须位于同一个分片上，这就使得在开发时必须对相应场景下涉及的key进行额外的规划和规范要求。如果应用的场景中大量涉及事务和Script的使用，如何在保证这两个功能的正常运作前提下把数据平均分到多个数据分片中就会成为难点。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">所以说，在主从复制和集群分片两个方案中做出选择时，应该从应用软件的功能特性、数据和访问量级、未来发展规划等方面综合考虑，只在<strong>确实有必要</strong>引入数据分片时再使用Redis Cluster。<br />
下面是一些建议：</p>
<ol style="padding-left: 40px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: decimal;">需要在Redis中存储的数据有多大？未来2年内可能发展为多大？这些数据是否都需要长期保存？是否可以使用LRU算法进行非热点数据的淘汰？综合考虑前面几个因素，评估出Redis需要使用的物理内存。</li>
    <li style="list-style-type: decimal;">用于部署Redis的主机物理内存有多大？有多少可以分配给Redis使用？对比(1)中的内存需求评估，是否足够用？</li>
    <li style="list-style-type: decimal;">Redis面临的并发写压力会有多大？在不使用pipelining时，Redis的写性能可以超过10万次/秒（更多的benchmark可以参考&nbsp;<a href="https://redis.io/topics/benchmarks" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://redis.io/topics/benchmarks</a>&nbsp;）</li>
    <li style="list-style-type: decimal;">在使用Redis时，是否会使用到pipelining和事务功能？使用的场景多不多？</li>
</ol>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">综合上面几点考虑，如果单台主机的可用物理内存完全足以支撑对Redis的容量需求，且Redis面临的并发写压力距离Benchmark值还尚有距离，建议采用主从复制的架构，可以省去很多不必要的麻烦。同时，如果应用中大量使用pipelining和事务，也建议尽可能选择主从复制架构，可以减少设计和开发时的复杂度。</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">Redis Java客户端的选择</h2>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redis的Java客户端很多，官方推荐的有三种：Jedis、Redisson和lettuce。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">在这里对Jedis和Redisson进行对比介绍</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Jedis：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">轻量，简洁，便于集成和改造</li>
    <li style="list-style-type: disc;">支持连接池</li>
    <li style="list-style-type: disc;">支持pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster</li>
    <li style="list-style-type: disc;">不支持读写分离，需要自己实现</li>
    <li style="list-style-type: disc;">文档差（真的很差，几乎没有&hellip;&hellip;）</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redisson：</p>
<ul style="margin-left: 30px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">
    <li style="list-style-type: disc;">基于Netty实现，采用非阻塞IO，性能高</li>
    <li style="list-style-type: disc;">支持异步请求</li>
    <li style="list-style-type: disc;">支持连接池</li>
    <li style="list-style-type: disc;">支持pipelining、LUA Scripting、Redis Sentinel、Redis Cluster</li>
    <li style="list-style-type: disc;">不支持事务，官方建议以LUA Scripting代替事务</li>
    <li style="list-style-type: disc;">支持在Redis Cluster架构下使用pipelining</li>
    <li style="list-style-type: disc;">支持读写分离，支持读负载均衡，在主从复制和Redis Cluster架构下都可以使用</li>
    <li style="list-style-type: disc;">内建Tomcat Session Manager，为Tomcat 6/7/8提供了会话共享功能</li>
    <li style="list-style-type: disc;">可以与Spring Session集成，实现基于Redis的会话共享</li>
    <li style="list-style-type: disc;">文档较丰富，有中文文档</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">对于Jedis和Redisson的选择，同样应遵循前述的原理，尽管Jedis比起Redisson有各种各样的不足，但也应该在需要使用Redisson的高级特性时再选用Redisson，避免造成不必要的程序复杂度提升。</p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Jedis：<br />
github：<a href="https://github.com/xetorthio/jedis" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://github.com/xetorthio/jedis</a><br />
文档：<a href="https://github.com/xetorthio/jedis/wiki" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://github.com/xetorthio/jedis/wiki</a></p>
<p style="margin: 10px auto; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px;">Redisson：<br />
github：<a href="https://github.com/redisson/redisson" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://github.com/redisson/redisson</a><br />
文档：<a href="https://github.com/redisson/redisson/wiki" target="_blank" style="color: rgb(0, 102, 170); text-decoration-line: none;">https://github.com/redisson/redisson/wiki</a></p>]]></description>
			<link>http://meisw.wdlinux.cn//show-997-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-04 19:58</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-995-1.html</guid>
			<title>Redis应用场景-转载</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">1. &nbsp;MySql+Memcached架构的问题</span></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　实际MySQL是适合进行海量数据存储的，通过Memcached将热点数据加载到cache，加速访问，很多公司都曾经使用过这样的架构，但随着业务数据量的不断增加，和访问量的持续增长，我们遇到了很多问题：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　1.MySQL需要不断进行拆库拆表，Memcached也需不断跟着扩容，扩容和维护工作占据大量开发时间。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　2.Memcached与MySQL数据库数据一致性问题。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　3.Memcached数据命中率低或down机，大量访问直接穿透到DB，MySQL无法支撑。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　4.跨机房cache同步问题。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　众多NoSQL百花齐放，如何选择</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　最近几年，业界不断涌现出很多各种各样的NoSQL产品，那么如何才能正确地使用好这些产品，最大化地发挥其长处，是我们需要深入研究和思考的问题，实际归根结底最重要的是了解这些产品的定位，并且了解到每款产品的tradeoffs，在实际应用中做到扬长避短，总体上这些NoSQL主要用于解决以下几种问题</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　1.少量数据存储，高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速访问，同时提供数据落地的功能，实际这正是Redis最主要的适用场景。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　2.海量数据存储，分布式系统支持，数据一致性保证，方便的集群节点添加/删除。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　3.这方面最具代表性的是dynamo和bigtable 2篇论文所阐述的思路。前者是一个完全无中心的设计，节点之间通过gossip方式传递集群信息，数据保证最终一致性，后者是一个中心化的方案设计，通过类似一个分布式锁服务来保证强一致性,数据写入先写<a class="nounderline" title="内存" href="http://product.it168.com/list/b/0205_1.shtml" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">内存</a>和redo log，然后定期compat归并到磁盘上，将随机写优化为顺序写，提高写入性能。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　4.Schema free，auto-sharding等。比如目前常见的一些文档数据库都是支持schema-free的，直接存储json格式数据，并且支持auto-sharding等功能，比如mongodb。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">　　面对这些不同类型的NoSQL产品,我们需要根据我们的业务场景选择最合适的产品。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;Redis最适合所有数据in-momory的场景，虽然Redis也提供持久化功能，但实际更多的是一个disk-backed的功能，跟传统意义上的持久化有比较大的差别，那么可能大家就会有疑问，似乎Redis更像一个加强版的Memcached，那么何时使用Memcached,何时使用Redis呢?</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;如果简单地比较Redis与Memcached的区别，大多数都会得到以下观点：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp;1 、Redis不仅仅支持简单的k/v类型的数据，同时还提供list，set，zset，hash等数据结构的存储。<br />
&nbsp; &nbsp; &nbsp;2 、Redis支持数据的备份，即master-slave模式的数据备份。<br />
&nbsp; &nbsp; &nbsp;3 、Redis支持数据的持久化，可以将内存中的数据保持在磁盘中，重启的时候可以再次加载进行使用。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t2" style="color: rgb(29, 88, 209);"></a><a name="t4" target="_blank" style="color: rgb(29, 88, 209);"></a></h2>
<p class="headline-1 bk-sidecatalog-title" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">2. &nbsp;Redis常用数据类型</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Redis最为常用的数据类型主要有以下：</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">String</li>
    <li style="list-style-type: disc;">Hash</li>
    <li style="list-style-type: disc;">List</li>
    <li style="list-style-type: disc;">Set</li>
    <li style="list-style-type: disc;">Sorted set</li>
    <li style="list-style-type: disc;">pub/sub</li>
    <li style="list-style-type: disc;">Transactions</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">在具体描述这几种数据类型之前，我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的：</p>
<p class="image-wide" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><img src="http://www.infoq.com/resource/articles/tq-redis-memory-usage-optimization-storage/zh/resources/image1.jpg;jsessionid=D59D91777C9EC47839B11001B07CAAC9" alt="" border="0" style="border: 0px; max-width: 900px;" /></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;type代表一个value对象具体是何种数据类型，</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;encoding是不同数据类型在redis内部的存储方式，</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;比如：type=string代表value存储的是一个普通字符串，那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的，当然前提是这个字符串本身可以用数值表示，比如:&quot;123&quot; &quot;456&quot;这样的字符串。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;这里需要特殊说明一下vm字段，只有打开了Redis的虚拟内存功能，此字段才会真正的分配内存，该功能默认是关闭状态的，该功能会在后面具体描述。通过上图我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的，当然这些内存管理成本的付出主要也是为了给Redis不同数据类型提供一个统一的管理接口，实际作者也提供了多种方法帮助我们尽量节省内存使用，我们随后会具体讨论。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t3" style="color: rgb(29, 88, 209);"></a><a name="t4" target="_blank" style="color: rgb(29, 88, 209);"></a></h2>
<p class="headline-1 bk-sidecatalog-title" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">3. &nbsp;各种数据类型应用和实现方式</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">下面我们先来逐一的分析下这7种数据类型的使用和内部实现方式:</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t4" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">String:</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<div>Strings 数据结构是简单的key-value类型，value其实不仅是String，也可以是数字.</div>
<p style="margin: 10px auto;">常用命令: &nbsp;set,get,decr,incr,mget 等。</p>
<p style="margin: 10px auto;">&nbsp;</p>
<p style="margin: 10px auto;"><strong>应用场景：</strong>String是最常用的一种数据类型，普通的key/ value 存储都可以归为此类.即可以完全实现目前 Memcached 的功能，并且效率更高。还可以享受Redis的定时持久化，操作日志及 Replication等功能。除了提供与 Memcached 一样的get、set、incr、decr 等操作外，Redis还提供了下面一些操作：</p>
</blockquote>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <ul style="margin-left: 30px;">
        <li style="list-style-type: disc;">获取字符串长度</li>
        <li style="list-style-type: disc;">往字符串append内容</li>
        <li style="list-style-type: disc;">设置和获取字符串的某一段内容</li>
        <li style="list-style-type: disc;">设置及获取字符串的某一位（bit）</li>
        <li style="list-style-type: disc;">批量设置一系列字符串的内容</li>
    </ul>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;">&nbsp;</p>
<p style="margin: 10px auto;"><strong>实现方式：</strong>String在redis内部存储默认就是一个字符串，被redisObject所引用，当遇到incr,decr等操作时会转成数值型进行计算，此时redisObject的encoding字段为int。</p>
<blockquote style="background: none; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px;">
<p style="margin: 10px auto;">&nbsp;</p>
</blockquote></blockquote>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t5" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">Hash</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;"><strong>常用命令：</strong>hget,hset,hgetall 等。</p>
<p style="margin: 10px auto;"><strong>应用场景：</strong>在Memcached中，我们经常将一些结构化的信息打包成HashMap，在客户端序列化后存储为一个字符串的值，比如用户的昵称、年龄、性别、积分等，这时候在需要修改其中某一项时，通常需要将所有值取出反序列化后，修改某一项的值，再序列化存储回去。<strong>这样不仅增大了开销，也不适用于一些可能并发操作的场合</strong>（比如两个并发的操作都需要修改积分）。而Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。</p>
<p style="margin: 10px auto;">&nbsp; &nbsp; &nbsp; &nbsp; 我们简单举个实例来描述下Hash的应用场景，比如我们要存储一个用户信息对象数据，包含以下信息：</p>
<p style="margin: 10px auto;">用户ID为查找的key，存储的value用户对象包含姓名，年龄，生日等信息，如果用普通的key/value结构来存储，主要有以下2种存储方式：</p>
<p style="margin: 10px auto;">&nbsp;</p>
<p class="image-wide" style="margin: 10px auto;"><img src="http://img.blog.csdn.net/20130506195958936" alt="" style="border: 0px; max-width: 900px;" /></p>
<p style="margin: 10px auto;">第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储，这种方式的缺点是，增加了序列化/反序列化的开销，并且在需要修改其中一项信息时，需要把整个对象取回，并且修改操作需要对并发进行保护，引入CAS等复杂问题。</p>
<p class="image-wide" style="margin: 10px auto;"><img src="http://img.blog.csdn.net/20130506200011015" alt="" style="border: 0px; max-width: 900px;" /></p>
<p style="margin: 10px auto;">第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿，用用户ID+对应属性的名称作为唯一标识来取得对应属性的值，虽然省去了序列化开销和并发问题，但是用户ID为重复存储，如果存在大量这样的数据，内存浪费还是非常可观的。</p>
<p style="margin: 10px auto;">那么Redis提供的Hash很好的解决了这个问题，Redis的Hash实际是内部存储的Value为一个HashMap，并提供了直接存取这个Map成员的接口，如下图：</p>
<p class="image-wide" style="margin: 10px auto;"><img src="http://img.blog.csdn.net/20130506200040811" alt="" style="border: 0px; max-width: 900px;" /></p>
<p style="margin: 10px auto;">也就是说，Key仍然是用户ID, value是一个Map，这个Map的key是成员的属性名，value是属性值，这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了，既不需要重复存储数据，也不会带来序列化和并发修改控制的问题。很好的解决了问题。</p>
<p style="margin: 10px auto;">这里同时需要注意，Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多，那么涉及到遍历整个内部Map的操作，由于Redis单线程模型的缘故，这个遍历操作可能会比较耗时，而另其它客户端的请求完全不响应，这点需要格外注意。</p>
<p style="margin: 10px auto;"><strong>实现方式：</strong></p>
<p style="margin: 10px auto;">上面已经说到Redis Hash对应Value内部实际就是一个HashMap，实际这里会有2种不同实现，这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储，而不会采用真正的HashMap结构，对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。</p>
</blockquote>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t6" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">List</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;"><strong>常用命令：</strong>lpush,rpush,lpop,rpop,lrange等。</p>
<p style="margin: 10px auto;"><strong>应用场景：</strong></p>
<p style="margin: 10px auto;">Redis list的应用场景非常多，也是Redis最重要的数据结构之一，比如twitter的关注列表，粉丝列表等都可以用Redis的list结构来实现。</p>
<p style="margin: 10px auto;">Lists 就是链表，相信略有数据结构知识的人都应该能理解其结构。使用Lists结构，我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列，<br />
可以利用Lists的PUSH操作，将任务存在Lists中，然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api，你可以直接查询，删除Lists中某一段的元素。</p>
<p style="margin: 10px auto;"><strong>实现方式：</strong></p>
<p style="margin: 10px auto;">Redis list的实现为一个双向链表，即可以支持反向查找和遍历，更方便操作，不过带来了部分额外的内存开销，Redis内部的很多实现，包括发送缓冲队列等也都是用的这个数据结构。</p>
</blockquote>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t7" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">Set</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;"><strong>常用命令：</strong></p>
<p style="margin: 10px auto;">sadd,spop,smembers,sunion 等。</p>
<p style="margin: 10px auto;"><strong>应用场景：</strong></p>
<p style="margin: 10px auto;">Redis set对外提供的功能与list类似是一个列表的功能，特殊之处在于set是可以自动排重的，当你需要存储一个列表数据，又不希望出现重复数据时，set是一个很好的选择，并且set提供了判断某个成员是否在一个set集合内的重要接口，这个也是list所不能提供的。</p>
<p style="margin: 10px auto;">Sets 集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构，可以存储一些集合性的数据，比如在微博应用中，可以将一个用户所有的关注人存在一个集合中，将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作，可以非常方便的实现如共同关注、共同喜好、二度好友等功能，对上面的所有集合操作，你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。</p>
<p style="margin: 10px auto;"><strong>实现方式：</strong></p>
<p style="margin: 10px auto;">set 的内部实现是一个 value永远为null的HashMap，实际就是通过计算hash的方式来快速排重的，这也是set能提供判断一个成员是否在集合内的原因。</p>
</blockquote>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t8" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">Sorted Set</li>
</ul>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;"><strong>常用命令：</strong></p>
<p style="margin: 10px auto;">zadd,zrange,zrem,zcard等</p>
<p style="margin: 10px auto;"><strong>使用场景：</strong></p>
<p style="margin: 10px auto;">Redis sorted set的使用场景与set类似，区别是set不是自动有序的，而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序，并且是插入有序的，即自动排序。当你需要一个有序的并且不重复的集合列表，那么可以选择sorted set数据结构，比如twitter 的public timeline可以以发表时间作为score来存储，这样获取时就是自动按时间排好序的。</p>
<p style="margin: 10px auto;">另外还可以用Sorted Sets来做带权重的队列，比如普通消息的score为1，重要消息的score为2，然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。</p>
<p style="margin: 10px auto;"><strong>实现方式：</strong></p>
<p style="margin: 10px auto;">Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序，HashMap里放的是成员到score的映射，而跳跃表里存放的是所有的成员，排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率，并且在实现上比较简单。</p>
</blockquote>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t9" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">Pub/Sub</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;">Pub/Sub 从字面上理解就是发布（Publish）与订阅（Subscribe），在Redis中，你可以设定对某一个key值进行消息发布及消息订阅，当一个key值上进行了消息发布后，所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统，比如普通的即时聊天，群聊等功能。</p>
</blockquote>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t10" style="color: rgb(29, 88, 209);"></a></h3>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">Transactions</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<blockquote style="background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; border: 2px solid rgb(239, 239, 239); padding: 4px; margin: 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
<p style="margin: 10px auto;">谁说NoSQL都不支持事务，虽然Redis的Transactions提供的并不是严格的ACID的事务（比如一串用EXEC提交执行的命令，在执行中服务器宕机，那么会有一部分命令执行了，剩下的没执行），但是这个Transactions还是提供了基本的命令打包执行的功能（在服务器不出问题的情况下，可以保证一连串的命令是顺序在一起执行的，中间有会有其它客户端命令插进来执行）。Redis还提供了一个Watch功能，你可以对一个key进行Watch，然后再执行Transactions，在这过程中，如果这个Watched的值进行了修改，那么这个Transactions会发现并拒绝执行。</p>
</blockquote>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t11" style="color: rgb(29, 88, 209);"></a><a name="t4" target="_blank" style="color: rgb(29, 88, 209);"></a></h2>
<p class="headline-1 bk-sidecatalog-title" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">4. &nbsp;Redis实际应用场景</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; Redis在很多方面与其他数据库解决方案不同：它使用内存提供主存储支持，而仅使用硬盘做持久性的存储；它的数据模型非常独特，用的是单线程。另一个大区别在于，你可以在开发环境中使用Redis的功能，但却不需要转到Redis。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">转向Redis当然也是可取的，许多开发者从一开始就把Redis作为首选数据库；但设想如果你的开发环境已经搭建好，应用已经在上面运行了，那么更换数据库框架显然不那么容易。另外在一些需要大容量数据集的应用，Redis也并不适合，因为它的数据集不会超过系统可用的内存。所以如果你有大数据应用，而且主要是读取访问模式，那么Redis并不是正确的选择。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 然而我喜欢Redis的一点就是你可以把它融入到你的系统中来，这就能够解决很多问题，比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化，或者为应用创建些新的功能。在本文中，我就想探讨一些怎样将Redis加入到现有的环境中，并利用它的原语命令等功能来解决 传统环境中碰到的一些常见问题。在这些例子中，Redis都不是作为首选数据库。</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t12" style="color: rgb(29, 88, 209);"></a><strong>1、显示最新的项目列表</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">下面这个语句常用来显示最新项目，随着数据多了，查询毫无疑问会越来越慢。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<div class="dp-highlighter bg_sql" style="font-family: Consolas, &quot;Courier New&quot;, Courier, mono, serif; font-size: 12px; overflow: auto; word-break: break-word; margin: 18px 0px !important;">
<ol class="dp-sql" start="1" style="padding-left: 40px; border: none; list-style-position: initial; list-style-image: initial; color: rgb(92, 92, 92); margin-right: 0px !important; margin-bottom: 1px !important; margin-left: 45px !important;">
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;"><span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit; font-weight: bold;">SELECT&nbsp;*&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">FROM&nbsp;foo&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">WHERE&nbsp;...&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">ORDER&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">BY&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">time&nbsp;<span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit;">DESC&nbsp;LIMIT&nbsp;10&nbsp;&nbsp;&nbsp;</span></span></span></span></span></span></span></li>
</ol>
</div>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 在Web应用中，&ldquo;列出最新的回复&rdquo;之类的查询非常普遍，这通常会带来可扩展性问题。这令人沮丧，因为项目本来就是按这个顺序被创建的，但要输出这个顺序却不得不进行排序操作。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 类似的问题就可以用Redis来解决。比如说，我们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上我们有一个&ldquo;显示全部&rdquo;的链接，点击后就可以获得更多的评论。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 我们假设数据库中的每条评论都有一个唯一的递增的ID字段。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 我们可以使用分页来制作主页和评论页，使用Redis的模板，每次新评论发表时，我们会将它的ID添加到一个Redis列表：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<div class="dp-highlighter bg_plain" style="font-family: Consolas, &quot;Courier New&quot;, Courier, mono, serif; font-size: 12px; overflow: auto; word-break: break-word; margin: 18px 0px !important;">
<ol start="1" style="padding-left: 40px; border: none; list-style-position: initial; list-style-image: initial; color: rgb(92, 92, 92); margin-right: 0px !important; margin-bottom: 1px !important; margin-left: 45px !important;">
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">LPUSH&nbsp;latest.comments&nbsp;&lt;ID&gt;&nbsp;&nbsp;&nbsp;</li>
</ol>
</div>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;我们将列表裁剪为指定长度，因此Redis只需要保存最新的5000条评论：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;LTRIM&nbsp;latest.comments&nbsp;0&nbsp;5000&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 每次我们需要获取最新评论的项目范围时，我们调用一个函数来完成（使用伪代码）：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<div class="dp-highlighter bg_plain" style="font-family: Consolas, &quot;Courier New&quot;, Courier, mono, serif; font-size: 12px; overflow: auto; word-break: break-word; margin: 18px 0px !important;">
<ol start="1" style="padding-left: 40px; border: none; list-style-position: initial; list-style-image: initial; color: rgb(92, 92, 92); margin-right: 0px !important; margin-bottom: 1px !important; margin-left: 45px !important;">
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">FUNCTION&nbsp;get_latest_comments(start,&nbsp;num_items):&nbsp;&nbsp;</li>
    <li style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; background-color: rgb(248, 248, 248); line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">&nbsp;&nbsp;&nbsp;&nbsp;id_list&nbsp;=&nbsp;redis.lrange(&quot;latest.comments&quot;,start,start+num_items&nbsp;-&nbsp;1)&nbsp;&nbsp;</li>
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">&nbsp;&nbsp;&nbsp;&nbsp;IF&nbsp;id_list.length&nbsp;&lt;&nbsp;num_items&nbsp;&nbsp;</li>
    <li style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; background-color: rgb(248, 248, 248); line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id_list&nbsp;=&nbsp;SQL_DB(&quot;SELECT&nbsp;...&nbsp;ORDER&nbsp;BY&nbsp;time&nbsp;LIMIT&nbsp;...&quot;)&nbsp;&nbsp;</li>
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">&nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;&nbsp;</li>
    <li style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; background-color: rgb(248, 248, 248); line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">&nbsp;&nbsp;&nbsp;&nbsp;RETURN&nbsp;id_list&nbsp;&nbsp;</li>
    <li class="alt" style="border-top: none; border-right: none; border-bottom: none; border-left: 3px solid rgb(108, 226, 108); border-image: initial; list-style-type: decimal; list-style-image: initial; color: inherit; line-height: 1.6; margin: 0px !important; padding: 0px 3px 0px 10px !important; list-style-position: outside !important;">END&nbsp;&nbsp;</li>
</ol>
</div>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 这里我们做的很简单。在Redis中我们的最新ID使用了常驻缓存，这是一直更新的。但是我们做了限制不能超过5000个ID，因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候，才需要去访问数据库。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 我们的系统不会像传统方式那样&ldquo;刷新&rdquo;缓存，Redis实例中的信息永远是一致的。SQL数据库（或是硬盘上的其他类型数据库）只是在用户需要获取&ldquo;很远&rdquo;的数据时才会被触发，而主页或第一个评论页是不会麻烦到硬盘上的数据库了。</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t13" style="color: rgb(29, 88, 209);"></a><strong>2、删除与过滤</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 我们可以使用LREM来删除评论。如果删除操作非常少，另一个选择是直接跳过评论条目的入口，报告说该评论已经不存在。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;有些时候你想要给不同的列表附加上不同的过滤器。如果过滤器的数量受到限制，你可以简单的为每个不同的过滤器使用不同的Redis列表。毕竟每个列表只有5000条项目，但Redis却能够使用非常少的内存来处理几百万条项目。</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t14" style="color: rgb(29, 88, 209);"></a><strong>3、排行榜相关</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 另一个很普遍的需求是各种数据库的数据并非存储在内存中，因此在按得分排序以及实时更新这些几乎每秒钟都需要更新的功能上数据库的性能不够理想。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 典型的比如那些在线游戏的排行榜，比如一个Facebook的游戏，根据得分你通常想要：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- 列出前100名高分选手</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- 列出某用户当前的全球排名</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 这些操作对于Redis来说小菜一碟，即使你有几百万个用户，每分钟都会有几百万个新的得分。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 模式是这样的，每次获得新得分时，我们用这样的代码：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; ZADD&nbsp;leaderboard &nbsp;&lt;score&gt; &nbsp;&lt;username&gt;&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp;你可能用userID来取代username，这取决于你是怎么设计的。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 得到前100名高分用户很简单：ZREVRANGE leaderboard 0 99。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 用户的全球排名也相似，只需要：ZRANK leaderboard &lt;username&gt;。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t15" style="color: rgb(29, 88, 209);"></a><strong>4、按照用户投票和时间排序</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 排行榜的一种常见变体模式就像Reddit或Hacker News用的那样，新闻按照类似下面的公式根据得分来排序：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;score&nbsp;=&nbsp;points&nbsp;/&nbsp;time^alpha&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 因此用户的投票会相应的把新闻挖出来，但时间会按照一定的指数将新闻埋下去。下面是我们的模式，当然算法由你决定。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 模式是这样的，开始时先观察那些可能是最新的项目，例如首页上的1000条新闻都是候选者，因此我们先忽视掉其他的，这实现起来很简单。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 每次新的新闻贴上来后，我们将ID添加到列表中，使用LPUSH + LTRIM，确保只取出最新的1000条项目。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 有一项后台任务获取这个列表，并且持续的计算这1000条新闻中每条新闻的最终得分。计算结果由ZADD命令按照新的顺序填充生成列表，老新闻则被清除。这里的关键思路是排序工作是由后台任务来完成的。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t16" style="color: rgb(29, 88, 209);"></a><strong>5、处理过期项目</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 另一种常用的项目排序是按照时间排序。我们使用unix时间作为得分即可。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 模式如下：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;- 每次有新项目添加到我们的非Redis数据库时，我们把它加入到排序集合中。这时我们用的是时间属性，current_time和time_to_live。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;- 另一项后台任务使用ZRANGE&hellip;SCORES查询排序集合，取出最新的10个项目。如果发现unix时间已经过期，则在数据库中删除条目。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t17" style="color: rgb(29, 88, 209);"></a><strong>6、计数</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;Redis是一个很好的计数器，这要感谢INCRBY和其他相似命令。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;我相信你曾许多次想要给数据库加上新的计数器，用来获取统计或显示新信息，但是最后却由于写入敏感而不得不放弃它们。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;好了，现在使用Redis就不需要再担心了。有了原子递增（atomic increment），你可以放心的加上各种计数，用GETSET重置，或者是让它们过期。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;例如这样操作：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;INCR&nbsp;user:&lt;id&gt;&nbsp;EXPIRE&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user:&lt;id&gt;&nbsp;60&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;你可以计算出最近用户在页面间停顿不超过60秒的页面浏览量，当计数达到比如20时，就可以显示出某些条幅提示，或是其它你想显示的东西。</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t18" style="color: rgb(29, 88, 209);"></a><strong>7、特定时间内的特定项目</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 另一项对于其他数据库很难，但Redis做起来却轻而易举的事就是统计在某段特点时间里有多少特定用户访问了某个特定资源。比如我想要知道某些特定的注册用户或IP地址，他们到底有多少访问了某篇文章。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 每次我获得一次新的页面浏览时我只需要这样做：</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;SADD&nbsp;page:day1:&lt;page_id&gt;&nbsp;&lt;user_id&gt;&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 当然你可能想用unix时间替换day1，比如time()-(time()%3600*24)等等。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; 想知道特定用户的数量吗？只需要使用SCARD page:day1:&lt;page_id&gt;。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;需要测试某个特定用户是否访问了这个页面？SISMEMBER page:day1:&lt;page_id&gt;。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>&nbsp;</strong></p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t19" style="color: rgb(29, 88, 209);"></a><strong>8、实时分析正在发生的情况，用于数据统计与防止垃圾邮件等</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 我们只做了几个例子，但如果你研究Redis的命令集，并且组合一下，就能获得大量的实时分析方法，有效而且非常省力。使用Redis原语命令，更容易实施垃圾邮件过滤系统或其他实时跟踪系统。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t20" style="color: rgb(29, 88, 209);"></a><strong>9、Pub/Sub</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;Redis的Pub/Sub非常非常简单，运行稳定并且快速。支持模式匹配，能够实时订阅与取消频道。</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t21" style="color: rgb(29, 88, 209);"></a><strong>10、队列</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 你应该已经注意到像list push和list pop这样的Redis命令能够很方便的执行队列操作了，但能做的可不止这些：比如Redis还有list pop的变体命令，能够在列表为空时阻塞队列。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;现代的互联网应用大量地使用了消息队列（Messaging）。消息队列不仅被用于系统内部组件之间的通信，同时也被用于系统跟其它服务之间的交互。消息队列的使用可以增加系统的可扩展性、灵活性和用户体验。非基于消息队列的系统，其运行速度取决于系统中最慢的组件的速度（注：短板效应）。而基于消息队列可以将系统中各组件解除耦合，这样系统就不再受最慢组件的束缚，各组件可以异步运行从而得以更快的速度完成各自的工作。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; 此外，当服务器处在高并发操作的时候，比如频繁地写入日志文件。可以利用消息队列实现异步处理。从而实现高性能的并发操作。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t22" style="color: rgb(29, 88, 209);"></a><strong>11、缓存</strong></h3>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; Redis的缓存部分值得写一篇新文章，我这里只是简单的说一下。Redis能够替代memcached，让你的缓存从只能存储数据变得能够更新数据，因此你不再需要每次都重新生成数据了。</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">此部分内容的原文地址：http://antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h2 style="margin: 10px 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t23" style="color: rgb(29, 88, 209);"></a></h2>
<p class="headline-1 bk-sidecatalog-title" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">5. &nbsp;国内外三个不同领域巨头分享的Redis实战经验及使用场景</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p align="left" style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp;随着应用对高性能需求的增加，NoSQL逐渐在各大名企的系统架构中生根发芽。这里我们将为大家分享<strong>社交巨头新浪微博、传媒巨头Viacom及图片分享领域佼佼者Pinterest</strong>带来的Redis实践，首先我们看新浪微博&nbsp;<a href="http://weibo.com/1319158547/AcmcMuPM5" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">@启盼cobain</a>的Redis实战经验分享：</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t24" style="color: rgb(29, 88, 209);"></a><strong>一、新浪微博：史上最大的Redis集群</strong></h3>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Tape is Dead，Disk is Tape，Flash is Disk，RAM Locality is King. &mdash; Jim Gray</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Redis不是比较成熟的memcache或者Mysql的替代品，是对于大型互联网类应用在架构上很好的补充。现在有越来越多的应用也在纷纷基于Redis做架构的改造。首先简单公布一下Redis平台实际情况：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;"><strong>2200+亿 commands/day 5000亿Read/day 500亿Write/day</strong></li>
    <li style="list-style-type: disc;"><strong>18TB+ Memory</strong></li>
    <li style="list-style-type: disc;"><strong>500+ Servers in 6 IDC 2000+instances</strong></li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">应该是国内外比较大的Redis使用平台，今天主要从应用角度谈谈Redis服务平台。</p>
<h4 style="margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t25" style="color: rgb(29, 88, 209);"></a>Redis使用场景</h4>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>1.Counting（计数）</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">计数的应用在另外一篇文章里较详细的描述，计数场景的优化&nbsp;<a href="http://www.xdata.me/?p=262" shape="rect" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">http://www.xdata.me/?p=262</a>这里就不多加描述了。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">可以预见的是，有很多同学认为把计数全部存在内存中成本非常高，我在这里用个图表来表达下我的观点：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/Mem.png" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;"><img class="size-full wp-image-324 aligncenter" title="Mem" src="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/Mem.png" alt="" style="border: 0px; max-width: 900px;" /></a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">很多情况大家都会设想纯使用内存的方案会很有很高成本，但实际情况往往会有一些不一样：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">COST，对于有一定吞吐需求的应用来说，肯定会单独申请DB、Cache资源，很多担心DB写入性能的同学还会主动将DB更新记入异步队列，而这三块的资源的利用率一般都不会太高。资源算下来，你惊异的发现：反而纯内存的方案会更精简！</li>
    <li style="list-style-type: disc;">KISS原则，这对于开发是非常友好的，我只需要建立一套连接池，不用担心数据一致性的维护，不用维护异步队列。</li>
    <li style="list-style-type: disc;">Cache穿透风险，如果后端使用DB，肯定不会提供很高的吞吐能力，cache宕机如果没有妥善处理，那就悲剧了。</li>
    <li style="list-style-type: disc;">大多数的起始存储需求，容量较小。</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>2.Reverse cache（反向cache）</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">面对微博常常出现的热点，如最近出现了较为火爆的短链，短时间有数以万计的人点击、跳转，而这里会常常涌现一些需求，比如我们向快速在跳转时判定用户等级，是否有一些账号绑定，性别爱好什么的，已给其展示不同的内容或者信息。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">普通采用memcache+Mysql的解决方案，当调用id合法的情况下，可支撑较大的吞吐。但当调用id不可控，有较多垃圾用户调用时，由于memcache未有命中，会大量的穿透至Mysql服务器，瞬间造成连接数疯长，整体吞吐量降低，响应时间变慢。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">这里我们可以用redis记录全量的用户判定信息，如string key:uid int:type，做一次反向的cache，当用户在redis快速获取自己等级等信息后，再去Mc+Mysql层去获取全量信息。如图：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/Concept2.jpeg" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;"><img class="size-full wp-image-311 aligncenter" title="Concept2" src="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/Concept2.jpeg" alt="" style="border: 0px; max-width: 900px;" /></a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">当然这也不是最优化的场景，如用Redis做bloomfilter，可能更加省用内存。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>3.Top 10 list</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">产品运营总会让你展示最近、最热、点击率最高、活跃度最高等等条件的top list。很多更新较频繁的列表如果使用MC+MySQL维护的话缓存失效的可能性会比较大，鉴于占用内存较小的情况，使用Redis做存储也是相当不错的。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>4.Last Index</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">用户最近访问记录也是redis list的很好应用场景，lpush lpop自动过期老的登陆记录，对于开发来说还是非常友好的。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>5.Relation List/Message Queue</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">这里把两个功能放在最后，因为这两个功能在现实问题当中遇到了一些困难，但在一定阶段也确实解决了我们很多的问题，故在这里只做说明。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Message Queue就是通过list的lpop及lpush接口进行队列的写入和消费，由于本身性能较好也能解决大部分问题。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>6.Fast transaction with Lua</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Redis 的Lua的功能扩展实际给Redis带来了更多的应用场景，你可以编写若干command组合作为一个小型的非阻塞事务或者更新逻辑，如：在收到message推送时，同时1.给自己的增加一个未读的对话 2.给自己的私信增加一个未读消息 3.最后给发送人回执一个完成推送消息，这一层逻辑完全可以在Redis Server端实现。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">但是，需要注意的是Redis会将lua script的全部内容记录在aof和传送给slave，这也将是对磁盘，网卡一个不小的开销。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>7.Instead of Memcache</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ol style="padding-left: 40px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: decimal;">很多测试和应用均已证明，</li>
    <li style="list-style-type: decimal;">在性能方面Redis并没有落后memcache多少，而单线程的模型给Redis反而带来了很强的扩展性。</li>
    <li style="list-style-type: decimal;">在很多场景下，Redis对同一份数据的内存开销是小于memcache的slab分配的。</li>
    <li style="list-style-type: decimal;">Redis提供的数据同步功能，其实是对cache的一个强有力功能扩展。</li>
</ol>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<h4 style="margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t26" style="color: rgb(29, 88, 209);"></a>Redis使用的重要点</h4>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>1.rdb/aof Backup!</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">我们线上的Redis 95%以上是承担后端存储功能的，我们不仅用作cache，而更为一种k-v存储，他完全替代了后端的存储服务（MySQL），故其数据是非常重要的，如果出现数据污染和丢失，误操作等情况，将是难以恢复的。所以备份是非常必要的！为此，我们有共享的hdfs资源作为我们的备份池，希望能随时可以还原业务所需数据。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>2.Small item &amp; Small instance!</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">由于Redis单线程（严格意义上不是单线程，但认为对request的处理是单线程的）的模型，大的数据结构list,sorted set,hash set的批量处理就意味着其他请求的等待，故使用Redis的复杂数据结构一定要控制其单key-struct的大小。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">另外，Redis单实例的内存容量也应该有严格的限制。单实例内存容量较大后，直接带来的问题就是故障恢复或者Rebuild从库的时候时间较长，而更糟糕的是，Redis rewrite aof和save rdb时，将会带来非常大且长的系统压力，并占用额外内存，很可能导致系统内存不足等严重影响性能的线上故障。我们线上96G/128G内存服务器不建议单实例容量大于20/30G。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>3.Been Available!</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">业界资料和使用比较多的是Redis sentinel（哨兵）</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://www.huangz.me/en/latest/storage/redis_code_analysis/sentinel.html" shape="rect" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">http://www.huangz.me/en/latest/storage/redis_code_analysis/sentinel.html</a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://qiita.com/wellflat/items/8935016fdee25d4866d9" shape="rect" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">http://qiita.com/wellflat/items/8935016fdee25d4866d9</a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">2000行C实现了服务器状态检测，自动故障转移等功能。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">但由于自身实际架构往往会复杂，或者考虑的角度比较多，为此&nbsp;<a href="http://weibo.com/eryk86" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">@许琦eryk</a>和我一同做了hypnos项目。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">hypnos是神话中的睡神，字面意思也是希望我们工程师无需在休息时间处理任何故障。:-)</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">其工作原理示意如下：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/hypnos1.png" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;"><img class="aligncenter size-full wp-image-309" title="hypnos" src="http://minidb-wordpress.stor.sinaapp.com/uploads/2013/09/hypnos1.png" alt="" style="border: 0px; max-width: 900px;" /></a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Talk is cheap, show me your code! 稍后将单独写篇博客细致讲下Hypnos的实现。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>4.In Memory or not?</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">发现一种情况，开发在沟通后端资源设计的时候，常常因为习惯使用和错误了解产品定位等原因，而忽视了对真实使用用户的评估。也许这是一份历史数据，只有最近一天的数据才有人进行访问，而把历史数据的容量和最近一天请求量都抛给内存类的存储现实是非常不合理的。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">所以当你在究竟使用什么样的数据结构存储的时候，请务必先进行成本衡量，有多少数据是需要存储在内存中的？有多少数据是对用户真正有意义的。因为这其实对后端资源的设计是至关重要的，1G的数据容量和1T的数据容量对于设计思路是完全不一样的</p>
<h4 style="margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t27" style="color: rgb(29, 88, 209);"></a>Plans in future?</h4>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>1.slave sync改造</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">全部改造线上master-slave数据同步机制，这一点我们借鉴了MySQL Replication的思路，使用rdb+aof+pos作为数据同步的依据，这里简要说明为什么官方提供的psync没有很好的满足我们的需求：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">假设A有两个从库B及C，及 A `&mdash; B&amp;C，这时我们发现master A服务器有宕机隐患需要重启或者A节点直接宕机，需要切换B为新的主库，如果A、B、C不共享rdb及aof信息，C在作为B的从库时，仍会清除自身数据，因为C节点只记录了和A节点的同步状况。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">故我们需要有一种将A`&ndash;B&amp;C 结构切换切换为A`&ndash;B`&ndash;C结构的同步机制，psync虽然支持断点续传，但仍无法支持master故障的平滑切换。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">实际上我们已经在我们定制的Redis计数服务上使用了如上功能的同步，效果非常好，解决了运维负担，但仍需向所有Redis服务推广，如果可能我们也会向官方Redis提出相关sync slave的改进。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>2.更适合redis的name-system Or proxy</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">细心的同学发现我们除了使用DNS作为命名系统，也在zookeeper中有一份记录，为什么不让用户直接访问一个系统，zk或者DNS选择其一呢？</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">其实还是很简单，命名系统是个非常重要的组件，而dns是一套比较完善的命名系统，我们为此做了很多改进和试错，zk的实现还是相对复杂，我们还没有较强的把控粒度。我们也在思考用什么做命名系统更符合我们需求。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>3.后端数据存储</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">大内存的使用肯定是一个重要的成本优化方向，flash盘及分布式的存储也在我们未来计划之中。（原文链接：&nbsp;<a href="http://www.xdata.me/?p=301" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">Largest Redis Clusters Ever</a>）</p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t28" style="color: rgb(29, 88, 209);"></a>二、Pinterest：Reids维护上百亿的相关性</h3>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp; &nbsp; &nbsp; Pinterest已经成为硅谷最疯故事之一，在2012年，他们基于PC的业务增加1047%，移动端采用增加1698%，&nbsp;<a href="http://www.forbes.com/sites/jjcolao/2013/05/08/why-is-pinterest-a-2-5-billion-company-an-early-investor-explains/" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">该年3月其独立访问数量更飙升至533亿</a>。在Pinterest，人们关注的事物以百亿记&mdash;&mdash;每个用户界面都会查询某个board或者是用户是否关注的行为促成了异常复杂的工程问题。这也让Redis获得了用武之地。经过数年的发展，Pinterest已经成为媒体、社交等多个领域的佼佼者，其辉煌战绩如下：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">获得的推荐流量高于Google+、YouTube及LinkedIn三者的总和</li>
    <li style="list-style-type: disc;">与Facebook及Twitter一起成为最流行的三大社交网络</li>
    <li style="list-style-type: disc;">参考Pinterest进行购买的用户比其它网站更高（&nbsp;<a href="http://corp.wishpond.com/pinterest-marketing-resources-for-business/15-facts-you-need-to-know-about-pinterest/" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">更多详情</a>）</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">如您所想，基于其独立访问数，Pinterest的高规模促成了一个非常高的IT基础设施需求。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://cms.csdnimg.cn/article/201310/07/525206fd19192.jpg" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;"><img src="http://cms.csdnimg.cn/article/201310/07/525206fd19192.jpg" alt="" border="0" style="border: 0px; max-width: 900px;" />&nbsp;</a></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>通过缓存来优化用户体验</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">近日，Pinterest工程经理Abhi&nbsp;Khune对其公司的用户体验需求及Redis的使用经验&nbsp;<a href="http://engineering.pinterest.com/post/55272557617/building-a-follower-model-from-scratch" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">进行了分享</a>。即使是滋生的应用程序打造者，在分析网站的细节之前也不会理解这些特性，因此先大致的理解一下使用场景：首先，为每个粉丝进行提及到的预检查；其次，UI将准确的显示用户的粉丝及关注列表分页。高效的执行这些操作，每次点击都需要非常高的性能架构。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">不能免俗，Pinterest的软件工程师及架构师已经使用了MySQL及memcache，但是缓存解决方案仍然达到了他们的瓶颈；因此为了拥有更好的用户体验，缓存必须被扩充。而在实际操作过程中，工程团队已然发现缓存只有当用户sub-graph已经在缓存中时才会起到作用。因此。任何使用这个系统的人都需要被缓存，这就导致了整个图的缓存。同时，最常见的查询&ldquo;用户A是否关注了用户B&rdquo;的答案经常是否定的，然而这却被作为了缓存丢失，从而促成一个数据库查询，因此他们需要一个新的方法来扩展缓存。最终，他们团队决定使用Redis来存储整个图，用以服务众多的列表。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>使用Redis存储大量的Pinterest列表</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Pinterest使用了Redis作为解决方案，并将性能推至了内存数据库等级，为用户保存多种类型列表：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<ul style="margin-left: 30px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">
    <li style="list-style-type: disc;">关注者列表</li>
    <li style="list-style-type: disc;">你所关注的board列表</li>
    <li style="list-style-type: disc;">粉丝列表</li>
    <li style="list-style-type: disc;">关注你board的用户列表</li>
    <li style="list-style-type: disc;">某个用户中board中你没有关注的列表</li>
    <li style="list-style-type: disc;">每个board的关注者及非关注者</li>
</ul>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">&nbsp;</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Redis为其7000万用户存储了以上的所有列表，本质上讲可以说是储存了所有粉丝图，通过用户ID分片。鉴于你可以通过类型来查看以上列表的数据，分析概要信息被用看起来更像事务的系统储存及访问。Pinterest当下的用户like被限制为10万，初略进行统计：如果每个用户关注25个board，将会在用户及board间产生17.5亿的关系。同时更加重要的是，这些关系随着系统的使用每天都会增加。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Pinterest的Reids架构及运营</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">通过Pinterest的一个创始人了解到，Pinterest开始使用Python及订制的Django编写应用程序，并一直持续到其拥有1800万用户级日410TB用户数据的时候。虽然使用了多个存储对数据进行储存，工程师根据用户id使用了8192个虚拟分片，每个分片都运行在一个Redis&nbsp;DB之上，同时1个Redis实例将运行多个Redis&nbsp;DB。为了对CPU核心的充分使用，同一台主机上同时使用多线程和单线程Redis实例。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">鉴于整个数据集运行在内存当中，Redis在Amazon&nbsp;EBS上对每秒传输进来的写入都会进行持久化。扩展主要通过两个方面进行：第一，保持50%的利用率，通过主从转换，机器上运行的Redis实例一半会转译到一个新机器上；第二，扩展节点和分片。整个Redis集群都会使用一个主从配置，从部分将被当做一个热备份。一旦主节点失败，从部分会立刻完成主的转换，同时一个新的从部分将会被添加，ZooKeeper将完成整个过程。同时他们每个小时都会在Amazon&nbsp;S3上运行BGsave做更持久的储存&mdash;&mdash;这项Reids操作会在后端进行，之后Pinterest会使用这些数据做MapReduce和分析作业。（更多内容见原文）</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><a href="http://cms.csdnimg.cn/article/201310/07/52520832c73e7.jpg" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;"><img src="http://cms.csdnimg.cn/article/201310/07/52520832c73e7.jpg" alt="" border="0" style="border: 0px; max-width: 900px;" /></a></p>
<h3 style="font-size: 16px; line-height: 1.5; margin: 10px 0px; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif;"><a name="t29" style="color: rgb(29, 88, 209);"></a>三、Viacom：Redis在系统中的用例盘点</h3>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Viacom是全球最大的传媒集体之一，同时也遭遇了当下最大的数据难题之一：如何处理日益剧增的动态视频内容。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">着眼这一挑战的上升趋势，我们会发现：<a href="http://blogs.vmware.com/vfabric/2013/03/why-every-database-must-be-broken-soon.html" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">2010年世界上所有数据体积达到ZB级</a>，而单单2012这一年，互联网产生的数据就增加了2.8个ZB，其中大部分的数据都是非结构化的，包括了视频和图片。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">覆盖MVN（以前称为MTV&nbsp;Networks、Paramount及BET），Viacom是个名副其实的传媒巨头，支持众多人气站点，其中包括The&nbsp;Daily&nbsp;Show、osh.0、South&nbsp;Park&nbsp;Studios、GameTrailers.com等。作为媒体公司，这些网站上的文档、图片、视频短片都在无时无刻的更新。长话短说，下面就进入Viacom高级架构师Michael&nbsp;Venezia&nbsp;分享的Redis实践：</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Viacom的网站架构背景</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">对于Viacom，横跨多个站点传播内容让必须专注于规模的需求，同时为了将内容竟可能快的传播到相应用户，他们还必须聚焦内容之间的关系。然而即使The&nbsp;Daily&nbsp;Show、Nickelodeon、Spike或者是VH1&nbsp;这些单独的网站上，日平均PV都可以达到千万，峰值时流量更会达到平均值的20-30倍。同时基于对实时的需求，动态的规模及速度已成为架构的基础之一。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">除去动态规模之外，服务还必须基于用户正在浏览的视频或者是地理位置来推测用户的喜好。比如说，某个页面可能会将一个独立的视频片段与本地的促销，视频系列的额外部分，甚至是相关视频联系起来。为了能让用户能在网站上停留更长的时间，他们建立了一个能基于详细元数据自动建立页面的软件引擎，这个引擎可以根据用户当下兴趣推荐额外的内容。鉴于用于兴趣的随时改变，数据的类型非常广泛&mdash;&mdash;类似graph-like，实际上做的是大量的join。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">这样做有利于减少类似视频的大体积文件副本数，比如数据存储中一个独立的记录是Southpark片段&ldquo;Cartman&nbsp;gets&nbsp;an&nbsp;Anal&nbsp;Probe&rdquo;，这个片段可能也会出现在德语的网站上。虽然视频是一样的，但是英语用户搜索的可能就是另一个不同的词语。元数据的副本转换成搜索结果，并指向相同的视频。因此在美国用户搜索真实标题的情况下，德国浏览者可能会使用转译的标题&mdash;&mdash;德国网站上的&ldquo;Cartman&nbsp;und&nbsp;die&nbsp;Analsonde&rdquo;。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">这些元数据覆盖了其它记录或者是对象，同时还可以根据使用环境来改变内容，通过不同的规则集来限制不同地理位置或者是设备请求的内容。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Viacom的实现方法</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">尽管许多机构通过使用ORM及传统关系型数据库来解决这个问题，Viacom却使用了一个迥然不同的方法。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">本质上，他们完全承担不了对数据库的直接访问。首先，他们处理的大部分都是流数据，他们偏向于使用Akamai从地理上来分配内容。其次，基于页面的复杂性可能会取上万个对象。取如此多的数据显然会影响到性能，因此JSON在1个数据服务中投入了使用。当然，这些JSON对象的缓存将直接影响到网站性能。同时，当内容或者是内容之间的关系发生改变时，缓存还需要动态的进行更新。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Viacom依靠对象基元和超类解决这个问题，继续以South&nbsp;Park为例：一个私有的&ldquo;episode&rdquo;类包含了所有该片段相关信息，一个&ldquo;super&nbsp;object&rdquo;将有助于发现实际的视频对象。超类这个思想确实非常有益于建设低延迟页面的自动建设，这些超类可以帮助到基元对象到缓存的映射及保存。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Viacom为什么要使用Redis</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">每当Viacom上传一个视频片段，系统将建立一个私有的对象，并于1个超类关联。每一次修改，他们都需要重估私有对象的每个改变，并更新所有复合对象。同时，系统还需要无效Akamail中的URL请求。系统现有架构的组合及更敏捷的管理方法需求将Viacom推向了Redis。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">基于Viacom主要基于PHP，所以这个解决方案必须支持PHP。他们首先选择了memcached做对象存储，但是它并不能很好的支持hashmap；同时他们还需要一个更有效的进行无效步骤的重估，即更好的理解内容的依赖性。本质上说，他们需要时刻跟进无效步骤中的依赖性改变。因此他们选择了Redis及Predis的组合来解决这个问题。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">他们团队使用Redis给southparkstudios.com和thedailyshow.com两个网站建设依赖性图，在取得了很大的成功后他们开始着眼Redis其它适合场景。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;"><strong>Redis的其它使用场景</strong></p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">显而易见，如果有人使用Redis来建设依赖性图，那么使用它来做对象处理也是说得通的。同样，这也成了架构团队为Redis选择的第二使用场景。Redis的复制及持久化特性同时也征服了Viacom的运营团队，因此在几个开发周期后，Redis成为他们网站的主要数据及依赖性储存。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">后两个用例则是行为追踪及浏览计数的缓冲，改变后的架构是Redis每几分钟向MySQL中储存一次，而浏览计数则通过Redis进行存储及计数。同时Redis还被用来做人气的计算，一个基于访问数及访问时间的得分系统&mdash;&mdash;如果某个视频最近被访问的次数越多，它的人气就越高。在如此多内容上每隔10-15分钟做一次计算绝对不是类似MySQL这样传统关系型数据库的强项，Viacom使用Redis的理由也非常简单&mdash;&mdash;在1个存储浏览信息的Redis实例上运行Lua批处理作业，计算出所有的得分表。信息被拷贝到另一个Redis实例上，用以支持相关的产品查询。同时还在MySQL上做了另一个备份，用以以后的分析，这种组合会将这个过程耗费的时间降低60倍。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">Viacom还使用Redis存储一步作业信息，这些信息被插入一个列表中，工作人员则使用<a href="http://redis.io/commands/blpop" target="_blank" style="color: rgb(29, 88, 209); text-decoration-line: none;">BLPOP</a>命令行在队列中抓取顶端的任务。同时zsets被用于从众多社交网络（比如Twitter及Tumblr）上综合内容，Viacom通过Brightcove视频播放器来同步多个内容管理系统。</p>
<p style="margin: 10px auto; font-family: Verdana, &quot;Lucida Grande&quot;, Arial, Helvetica, sans-serif; font-size: 12px;">横跨这些用例，几乎所有的Redis命令都被使用&mdash;&mdash;sets、lists、zlists、hashmaps、scripts、counters等。同时，Redis也成为Viacom可扩展架构中不可或缺的一环。</p>]]></description>
			<link>http://meisw.wdlinux.cn//show-995-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 17:11</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-994-1.html</guid>
			<title>redis 五种数据结构详解（string，list，set，zset，hash）</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="background-color: rgb(254, 254, 242); font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px;">Redis不仅仅支持简单的key-value类型的数据，同时还提供list，set，zset，hash等数据结构的存储。</span></p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">String&mdash;&mdash;字符串<br style="margin: 0px; padding: 0px;" />
Hash&mdash;&mdash;字典<br style="margin: 0px; padding: 0px;" />
List&mdash;&mdash;列表<br style="margin: 0px; padding: 0px;" />
Set&mdash;&mdash;集合<br style="margin: 0px; padding: 0px;" />
Sorted Set&mdash;&mdash;有序集合</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">下面我们就来简单说明一下它们各自的使用场景：</p>
<h2 style="margin: 10px 0px; padding: 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">一、Redis&nbsp;String类型</h2>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">string类型的数据存储是最简单的key-value存储；</p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.string字符串读写实现方式：</h3>
<div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); overflow: auto; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">function</span><span style="margin: 0px; padding: 0px; line-height: 1.5;"> testRedis(){         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">string类型的数据结构</span>         app()-&gt;redis-&gt;set('1', 'aa'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);<br style="margin: 0px; padding: 0px;" />　　　　<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(51, 153, 102);">//根据key取出value值</span><br style="margin: 0px; padding: 0px;" /></span></pre>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;">　　　　$string = app()-&gt;redis-&gt;get('1');</pre>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5;">    }</span></pre>
</div>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">2.redis客户端查看结果：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);"><img src="http://images2015.cnblogs.com/blog/728981/201701/728981-20170103115027862-1957541760.png" alt="" style="margin: 0px; padding: 0px; border: 0px; max-width: 900px;" /></p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">3.string字符串的其他redis操作方法：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//普通set/get操作<br style="margin: 0px; padding: 0px;" />
$redis-&gt;set('library', 'predis');<br style="margin: 0px; padding: 0px;" />
$retval = $redis-&gt;get('library');<br style="margin: 0px; padding: 0px;" />
echo $retval; //显示 'predis'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//setex set一个存储时效<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setex('str', 10, 'bar'); //表示存储有效期为10秒</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//setnx/msetnx相当于add操作,不会覆盖已有值<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setnx('foo',12); //true<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setnx('foo',34); //false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//getset操作,set的变种,结果返回替换前的值<br style="margin: 0px; padding: 0px;" />
$redis-&gt;getset('foo',56);//返回34</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">// incrby/incr/decrby/decr 对值的递增和递减<br style="margin: 0px; padding: 0px;" />
$redis-&gt;incr('foo'); //foo为57<br style="margin: 0px; padding: 0px;" />
$redis-&gt;incrby('foo',2); //foo为59</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//exists检测是否存在某值<br style="margin: 0px; padding: 0px;" />
$redis-&gt;exists('foo');//true</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//del 删除<br style="margin: 0px; padding: 0px;" />
$redis-&gt;del('foo');//true</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//type 类型检测,字符串返回string,列表返回 list,set表返回set/zset,hash表返回hash<br style="margin: 0px; padding: 0px;" />
$redis-&gt;type('foo');//不存在,返回none<br style="margin: 0px; padding: 0px;" />
$redis-&gt;set('str','test');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;type('str'); //字符串，返回string</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//append 连接到已存在字符串<br style="margin: 0px; padding: 0px;" />
$redis-&gt;append('str','_123'); //返回累加后的字符串长度8,此进str为 'test_123'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//setrange 部分替换操作<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setrange('str',0,'abc'); //返回3,参数2为0时等同于set操作<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setrange('str',2,'cd');//返回4,表示从第2个字符后替换,这时'str'为'abcd'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//substr 部分获取操作<br style="margin: 0px; padding: 0px;" />
$redis-&gt;substr('str',0,2);//表示从第0个起，取到第2个字符，共3个，返回'abc'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//strlen 获取字符串长度<br style="margin: 0px; padding: 0px;" />
$redis-&gt;strlen('str'); //返回4</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//setbit/getbit 位存储和获取<br style="margin: 0px; padding: 0px;" />
$redis-&gt;setbit('binary',31,1);&amp;nbsp; //表示在第31位存入1,这边可能会有大小端问题?不过没关系,getbit 应该不会有问题<br style="margin: 0px; padding: 0px;" />
$redis-&gt;getbit('binary',31);&amp;nbsp;&amp;nbsp;&amp;nbsp; //返回1</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//keys 模糊查找功能,支持*号以及?号(匹配一个字符)<br style="margin: 0px; padding: 0px;" />
$redis-&gt;set('foo1',123);<br style="margin: 0px; padding: 0px;" />
$redis-&gt;set('foo2',456);<br style="margin: 0px; padding: 0px;" />
$redis-&gt;keys('foo*'); //返回foo1和foo2的array<br style="margin: 0px; padding: 0px;" />
$redis-&gt;keys('f?o?');&amp;nbsp; //同上</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//randomkey 随机返回一个key<br style="margin: 0px; padding: 0px;" />
$redis-&gt;randomkey(); //可能是返回 'foo1'或者是'foo2'及其它任何一存在redis的key</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//rename/renamenx 对key进行改名,所不同的是renamenx不允许改成已存在的key<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rename('str','str2'); //把原先命名为'str'的key改成了'str2'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//expire 设置key-value的时效性,ttl 获取剩余有效期,persist 重新设置为永久存储<br style="margin: 0px; padding: 0px;" />
$redis-&gt;expire('foo', 1); //设置有效期为1秒<br style="margin: 0px; padding: 0px;" />
$redis-&gt;ttl('foo'); //返回有效期值1s<br style="margin: 0px; padding: 0px;" />
$redis-&gt;expire('foo'); //取消expire行为</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//dbsize 返回redis当前数据库的记录总数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;dbsize();</p>
<h2 style="margin: 10px 0px; padding: 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">二、Redis&nbsp;Hash表</h2>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">&nbsp;redis中hash表存储数据，比较类似数据库中表的一条记录；</p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.hash读写实现方式：</h3>
<div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); overflow: auto; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">function</span><span style="margin: 0px; padding: 0px; line-height: 1.5;"> testRedis()     {</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">存储 hash类型 数据结构</span>         app()-&gt;redis-&gt;hset('goods', 'apple', '苹果'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);          </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">取出 hash表中的数据</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$hash</span> = app()-&gt;redis-&gt;hget('goods', 'apple'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$hash</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">echo</span> &quot;\n&quot;<span style="margin: 0px; padding: 0px; line-height: 1.5;">;                  </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">die</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">();     }</span></pre>
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
</div>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">2.redis客户端查看结果：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">&nbsp;<img src="http://images2015.cnblogs.com/blog/728981/201701/728981-20170103120418206-1518023364.png" alt="" style="margin: 0px; padding: 0px; border: 0px; max-width: 900px;" /></p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">&nbsp;3.关于hash表其他redis操作方法：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hset/hget 存取hash表的数据<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hset('hash1','key1','v1'); //将key为'key1' value为'v1'的元素存入hash1表<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hset('hash1','key2','v2');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hget('hash1','key1');&amp;nbsp; //取出表'hash1'中的key 'key1'的值,返回'v1'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hexists 返回hash表中的指定key是否存在<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hexists ('hash1','key1'); //true or false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hdel 删除hash表中指定key的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hdel('hash1','key2'); //true or false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hlen 返回hash表元素个数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hlen('hash1'); //1</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hsetnx 增加一个元素,但不能重复<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hsetnx('hash1','key1','v2'); //false<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hsetnx('hash1','key2','v2'); //true</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hmset/hmget 存取多个元素到hash表<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hmset('hash1',array('key3'=&gt;'v3','key4'=&gt;'v4'));<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hmget('hash1',array('key3','key4')); //返回相应的值 array('v3','v4')</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hincrby 对指定key进行累加<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hincrby('hash1','key5',3); //返回3<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hincrby('hash1','key5',10); //返回13</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hkeys 返回hash表中的所有key<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hkeys('hash1'); //返回array('key1','key2','key3','key4','key5')</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hvals 返回hash表中的所有value<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hvals('hash1'); //返回array('v1','v2','v3','v4',13)</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//hgetall 返回整个hash表元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;hgetall('hash1'); //返回array('key1'=&gt;'v1','key2'=&gt;'v2','key3'=&gt;'v3','key4'=&gt;'v4','key5'=&gt;13)</p>
<h2 style="margin: 10px 0px; padding: 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">三、Redis&nbsp;list列表</h2>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">List数据结构是链表结构，<strong style="margin: 0px; padding: 0px;">是双向的，可以在链表左，右两边分别操作；</strong></p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">也可以把list看成一种队列，所以在很多时候可以用redis用作消息队列，这个时候它的作用就类似于activeMq啦；</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">应用案例有时间轴数据，评论列表，消息传递等等，它可以提供简便的分页，读写操作。</p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.list 读写实现方式：</h3>
<div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); overflow: auto; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">function</span><span style="margin: 0px; padding: 0px; line-height: 1.5;"> testRedis()     {</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">存储 list</span>         app()-&gt;redis-&gt;lpush('news', 'cc'); <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">从队列前面插入元素</span>         app()-&gt;redis-&gt;lpush('news', 'ee'); <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">从队列前面插入元素</span>         app()-&gt;redis-&gt;rpush('news', 'dd');<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">从队列后面插入元素</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$list</span> = app()-&gt;redis-&gt;lrange('news', 0, -1);<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">取出list所有元素</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$list</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">echo</span> &quot;\n&quot;<span style="margin: 0px; padding: 0px; line-height: 1.5;">;          </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">die</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">();     }</span></pre>
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
</div>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">2.在redis客户端中直观查看list的存储结果：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);"><strong style="margin: 0px; padding: 0px;"><img src="http://images2015.cnblogs.com/blog/728981/201701/728981-20170103135936269-432609426.png" alt="" style="margin: 0px; padding: 0px; border: 0px; max-width: 900px;" /></strong></p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">3.list列表的其他redis操作方法：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//rpush/rpushx 有序列表操作,从队列后插入元素<br style="margin: 0px; padding: 0px;" />
//lpush/lpushx 和rpush/rpushx的区别是插入到队列的头部,同上,'x'含义是只对已存在的key进行操作<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpush('fooList', 'bar1'); //返回一个列表的长度1<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lpush('fooList', 'bar0'); //返回一个列表的长度2<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpushx('fooList', 'bar2'); //返回3,rpushx只对已存在的队列做添加,否则返回0<br style="margin: 0px; padding: 0px;" />
//llen返回当前列表长度<br style="margin: 0px; padding: 0px;" />
$redis-&gt;llen('fooList');//3</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//lrange 返回队列中一个区间的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lrange('fooList',0,1); //返回数组包含第0个至第1个共2个元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lrange('fooList',0,-1);//返回第0个至倒数第一个,相当于返回所有元素,注意redis中很多时候会用到负数,下同</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//lindex 返回指定顺序位置的list元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lindex('fooList',1); //返回'bar1'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//lset 修改队列中指定位置的value<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lset('fooList',1,'123');//修改位置1的元素,返回true</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//lrem 删除队列中左起指定数量的字符<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lrem('fooList',1,'_'); //删除队列中左起(右起使用-1)1个字符'_'(若有)</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//lpop/rpop 类似栈结构地弹出(并删除)最左或最右的一个元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;lpop('fooList'); //'bar0'<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpop('fooList'); //'bar2'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//ltrim 队列修改，保留左边起若干元素，其余删除<br style="margin: 0px; padding: 0px;" />
$redis-&gt;ltrim('fooList', 0,1); //保留左边起第0个至第1个元素</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//rpoplpush 从一个队列中pop出元素并push到另一个队列<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpush('list1','ab0');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpush('list1','ab1');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpush('list2','ab2');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpush('list2','ab3');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpoplpush('list1','list2');//结果list1 =&gt;array('ab0'),list2 =&gt;array('ab1','ab2','ab3')<br style="margin: 0px; padding: 0px;" />
$redis-&gt;rpoplpush('list2','list2');//也适用于同一个队列,把最后一个元素移到头部list2 =&gt;array('ab3','ab1','ab2')</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//linsert 在队列的中间指定元素前或后插入元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;linsert('list2', 'before','ab1','123'); //表示在元素'ab1'之前插入'123'<br style="margin: 0px; padding: 0px;" />
$redis-&gt;linsert('list2', 'after','ab1','456');&amp;nbsp;&amp;nbsp; //表示在元素'ab1'之后插入'456'</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//blpop/brpop 阻塞并等待一个列队不为空时，再pop出最左或最右的一个元素（这个功能在php以外可以说非常好用）<br style="margin: 0px; padding: 0px;" />
//brpoplpush 同样是阻塞并等待操作，结果同rpoplpush一样<br style="margin: 0px; padding: 0px;" />
$redis-&gt;blpop('list3',10); //如果list3为空则一直等待,直到不为空时将第一元素弹出,10秒后超时；</p>
<h2 style="margin: 10px 0px; padding: 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">四、Redis&nbsp;Set集合</h2>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">Set 就是一个集合，集合的概念就是一堆<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(255, 0, 0);">不重复值</span>的组合。利用 Redis 提供的 Set 数据结构，可以存储一些集合性的数据。</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">比如在微博应用中，可以将一个用户所有的关注人存在一个集合中，将其所有粉丝存在一个集合。</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">因为 Redis 非常人性化的为集合提供了求交集、并集、差集等操作，那么就可以非常方便的实现如共同关注、共同喜好、二度好友等功能，对上面的所有集合操作，你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.共同好友、二度好友<br style="margin: 0px; padding: 0px;" />
2.利用唯一性，可以统计访问网站的所有独立 IP<br style="margin: 0px; padding: 0px;" />
3.好友推荐的时候，根据 tag 求交集，大于某个 threshold 就可以推荐</p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.set 读写实现方式：</h3>
<div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); overflow: auto; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">function</span><span style="margin: 0px; padding: 0px; line-height: 1.5;"> testRedis()     {</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">存储 set</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span> = app()-&gt;redis-&gt;sadd('fans', 'ff'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">if</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">){             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add ff success'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">else</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">{             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add ff fail'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span> = app()-&gt;redis-&gt;sadd('fans', 'gg'); <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">不存在返回true</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">if</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">){             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add gg success'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">else</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">{             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add gg fail'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span> = app()-&gt;redis-&gt;sadd('fans', 'gg'); <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">不存在返回false</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">if</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">){             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add gg success'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">else</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">{             </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>('set add gg fail'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         }         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">取出set</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span> = app()-&gt;redis-&gt;smembers('fans'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$fans</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">echo</span> &quot;\n&quot;<span style="margin: 0px; padding: 0px; line-height: 1.5;">;     }</span></pre>
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
</div>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">2.在redis客户端中直观查看set集合的存储结果：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);"><img src="http://images2015.cnblogs.com/blog/728981/201701/728981-20170103143121159-1358020966.png" alt="" style="margin: 0px; padding: 0px; border: 0px; max-width: 900px;" /></p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">3.set集合的其他redis操作方法：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//sadd 增加元素,返回true,重复返回false<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sadd('set1','ab');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sadd('set1','cd');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sadd('set1','ef');</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//srem 移除指定元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;srem('set1','cd'); //删除'cd'元素</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//spop 弹出首元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;spop('set1');</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//smove 移动当前set表的指定元素到另一个set表<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sadd('set2','123');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;smove('set1','set2','ab');//移动'set1'中的'ab'到'set2',返回true or false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//scard 返回当前set表元素个数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;scard('set2');//2</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//sismember 判断元素是否属于当前表<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sismember('set2','123'); //true or false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//smembers 返回当前表的所有元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;smembers('set2'); //array('123','ab');</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//sinter/sunion/sdiff&amp;nbsp; 返回两个表中元素的交集/并集/补集<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sadd('set1','ab');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sinter('set2','set1'); //返回array('ab')</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//sinterstore/sunionstore/sdiffstore 将两个表交集/并集/补集元素copy到第三个表中<br style="margin: 0px; padding: 0px;" />
$redis-&gt;set('foo',0);<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sinterstore('foo','set1'); //这边等同于将'set1'的内容copy到'foo'中，并将'foo'转为set表<br style="margin: 0px; padding: 0px;" />
$redis-&gt;sinterstore('foo',array('set1','set2')); //将'set1'和'set2'中相同的元素copy到'foo'表中,覆盖'foo'原有内容</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//srandmember 返回表中一个随机元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;srandmember('set1');</p>
<h2 style="margin: 10px 0px; padding: 0px; font-size: 21px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">五、Redis Zset集合（Sorted Sets）</h2>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">zset是set的一个升级版本，他在set的基础上增加了一个<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(255, 0, 0);">顺序属性</span>，这一属性在添加修改元素的时候可以指定，每次指定后，zset会自动重新按新的值调整顺序。 可以对指定键的值进行排序权重的设定，它应用排名模块比较多。</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">比如一个存储全班同学成绩的 Sorted Sets，其集合 value 可以是同学的学号，而 score 就可以是其考试得分，这样在数据插入集合的时候，就已经进行了天然的排序。另外还可以用 Sorted Sets 来做带权重的队列，比如普通消息的 score 为1，重要消息的 score 为2，然后工作线程可以选择按 score 的倒序来获取工作任务，让重要的任务优先执行。</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">zset集合可以完成有序执行、按照优先级执行的情况；</p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">1.zset 读写实现方式：</h3>
<div class="cnblogs_code" style="margin: 5px 0px; padding: 5px; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); overflow: auto; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important;"><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">public</span> <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">function</span><span style="margin: 0px; padding: 0px; line-height: 1.5;"> testRedis()     {</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">zset 添加元素</span>         app()-&gt;redis-&gt;zadd('students', '1', '90'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         app()</span>-&gt;redis-&gt;zadd('students', '2', '80'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         app()</span>-&gt;redis-&gt;zadd('students', '3', '95'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         app()</span>-&gt;redis-&gt;zadd('students', '7', '75'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         app()</span>-&gt;redis-&gt;zadd('students', '5', '55'<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">//</span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 0);">取出 zset</span>         <span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$zset</span> = app()-&gt;redis-&gt;zrange('students', 0, -1<span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 128, 128);">print_r</span>(<span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(128, 0, 128);">$zset</span><span style="margin: 0px; padding: 0px; line-height: 1.5;">);         </span><span style="margin: 0px; padding: 0px; line-height: 1.5; color: rgb(0, 0, 255);">echo</span> &quot;\n&quot;<span style="margin: 0px; padding: 0px; line-height: 1.5;">;     }</span></pre>
<div class="cnblogs_code_toolbar" style="margin: 5px 0px 0px; padding: 0px;"><span class="cnblogs_code_copy" style="margin: 0px; padding: 0px 5px 0px 0px; line-height: 1.5;"><a title="复制代码" style="margin: 0px; padding: 0px; color: rgb(7, 93, 179); text-decoration-line: underline; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="margin: 0px; padding: 0px; max-width: 900px; border: none !important;" /></a></span></div>
</div>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">2.在redis客户端中直观查看zset集合的存储结果：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);"><img src="http://images2015.cnblogs.com/blog/728981/201701/728981-20170103144958691-45050737.png" alt="" style="margin: 0px; padding: 0px; border: 0px; max-width: 900px;" /></p>
<h3 style="margin: 10px 0px; padding: 0px; font-size: 16px; line-height: 1.5; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">3.zset集合的其他redis操作方法：</h3>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//sadd 增加元素,并设置序号,返回true,重复返回false<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zadd('zset1',1,'ab');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zadd('zset1',2,'cd');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zadd('zset1',3,'ef');</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zincrby 对指定元素索引值的增减,改变元素排列次序<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zincrby('zset1',10,'ab');//返回11</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zrem 移除指定元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrem('zset1','ef'); //true or false</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zrange 按位置次序返回表中指定区间的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrange('zset1',0,1); //返回位置0和1之间(两个)的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrange('zset1',0,-1);//返回位置0和倒数第一个元素之间的元素(相当于所有元素)</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zrevrange 同上,返回表中指定区间的元素,按次序倒排<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrevrange('zset1',0,-1); //元素顺序和zrange相反</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zrangebyscore/zrevrangebyscore 按顺序/降序返回表中指定索引区间的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zadd('zset1',3,'ef');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zadd('zset1',5,'gh');<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrangebyscore('zset1',2,9); //返回索引值2-9之间的元素 array('ef','gh')<br style="margin: 0px; padding: 0px;" />
//参数形式<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrangebyscore('zset1',2,9,'withscores'); //返回索引值2-9之间的元素并包含索引值 array(array('ef',3),array('gh',5))<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrangebyscore('zset1',2,9,array('withscores' =&gt;true,'limit'=&gt;array(1, 2))); //返回索引值2-9之间的元素,'withscores' =&gt;true表示包含索引值; 'limit'=&gt;array(1, 2),表示最多返回2条,结果为array(array('ef',3),array('gh',5))</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zunionstore/zinterstore 将多个表的并集/交集存入另一个表中<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zunionstore('zset3',array('zset1','zset2','zset0')); //将'zset1','zset2','zset0'的并集存入'zset3'<br style="margin: 0px; padding: 0px;" />
//其它参数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zunionstore('zset3',array('zset1','zset2'),array('weights' =&gt; array(5,0)));//weights参数表示权重，其中表示并集后值大于5的元素排在前，大于0的排在后<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zunionstore('zset3',array('zset1','zset2'),array('aggregate' =&gt; 'max'));//'aggregate' =&gt; 'max'或'min'表示并集后相同的元素是取大值或是取小值</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zcount 统计一个索引区间的元素个数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zcount('zset1',3,5);//2<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zcount('zset1','(3',5)); //'(3'表示索引值在3-5之间但不含3,同理也可以使用'(5'表示上限为5但不含5</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zcard 统计元素个数<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zcard('zset1');//4</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zscore 查询元素的索引<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zscore('zset1','ef');//3</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zremrangebyscore 删除一个索引区间的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zremrangebyscore('zset1',0,2); //删除索引在0-2之间的元素('ab','cd'),返回删除元素个数2</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zrank/zrevrank 返回元素所在表顺序/降序的位置(不是索引)<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zrank('zset1','ef');//返回0,因为它是第一个元素;zrevrank则返回1(最后一个)</p>
<p style="margin: 10px auto; line-height: 1.5; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(254, 254, 242);">//zremrangebyrank 删除表中指定位置区间的元素<br style="margin: 0px; padding: 0px;" />
$redis-&gt;zremrangebyrank('zset1',0,10); //删除位置为0-10的元素,返回删除的元素个数2</p>]]></description>
			<link>http://meisw.wdlinux.cn//show-994-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 17:10</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-993-1.html</guid>
			<title>Redis作者谈Redis应用场景（转）</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;https://www.cnblogs.com/ajianbeyourself/p/4395146.html</p>]]></description>
			<link>http://meisw.wdlinux.cn//show-993-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:33</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-992-1.html</guid>
			<title>Redis sort 排序命令详解</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<strong style="color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px;">1、命令描述</strong></p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">返回或保存给定列表、集合、有序集合key中经过排序的元素。<br />
排序默认以数字作为对象，值被解释为双精度浮点数，然后进行比较。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>2、一般sort用法</strong><br />
最简单的sort使用方法是sort key和sort key desc。<br />
sort key：返回键值从小到大排序的结果。<br />
sort key desc：返回键值从大到小排序的结果。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">假设price列表保存了今日的物品价格， 那么可以用sort命令对它进行排序：<br />
# 开销金额列表<br />
redis&gt; lpush price 30 1.5 10 8<br />
(integer) 4</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 排序<br />
redis&gt; sort price<br />
1) &quot;1.5&quot;<br />
2) &quot;8&quot;<br />
3) &quot;10&quot;<br />
4) &quot;30&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 逆序排序<br />
redis 127.0.0.1:6379&gt; sort price desc<br />
1) &quot;30&quot;<br />
2) &quot;10&quot;<br />
3) &quot;8&quot;<br />
4) &quot;1.5&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>3、使用alpha修饰符对字符串进行排序</strong><br />
因为sort命令默认排序对象为数字，当需要对字符串进行排序时，需要显式地在sort命令之后添加alpha修饰符。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 网址<br />
redis&gt; lpush website &quot;www.ceddit.com&quot;<br />
(integer) 1</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis&gt; lpush website &quot;www.hlashdot.com&quot;<br />
(integer) 2</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis&gt; lpush website &quot;www.bnfoq.com&quot;<br />
(integer) 3</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 默认(按数字)排序<br />
redis 127.0.0.1:8888&gt; sort website<br />
1) &quot;www.bnfoq.com&quot;<br />
2) &quot;www.hlashdot.com&quot;<br />
3) &quot;www.ceddit.com&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 按字符排序<br />
redis 127.0.0.1:8888&gt; sort website alpha<br />
1) &quot;www.bnfoq.com&quot;<br />
2) &quot;www.ceddit.com&quot;<br />
3) &quot;www.hlashdot.com&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:8888&gt; sort website alpha desc<br />
1) &quot;www.hlashdot.com&quot;<br />
2) &quot;www.ceddit.com&quot;<br />
3) &quot;www.bnfoq.com&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>4、使用limit修饰符限制返回结果</strong><br />
排序之后返回元素的数量可以通过limit修饰符进行限制，修饰符接受offset和count两个参数。<br />
offset：指定要跳过的元素数量，即起始位置。<br />
count：指定跳过offset个指定的元素之后，要返回多少个对象。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">以下例子返回排序结果的前5个对象(offset为0表示没有元素被跳过)。<br />
# 添加测试数据，列表值为1~10<br />
redis 127.0.0.1:6379&gt; rpush age 1 3 5 7 9<br />
(integer) 5</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; rpush age 2 4 6 8 10<br />
(integer) 10</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 返回列表中最小的5个值<br />
redis 127.0.0.1:6379&gt; sort age limit 0 5<br />
1) &quot;1&quot;<br />
2) &quot;2&quot;<br />
3) &quot;3&quot;<br />
4) &quot;4&quot;<br />
5) &quot;5&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>5、使用外部key进行排序</strong><br />
可以使用外部 key 的数据作为权重，代替默认的直接对比键值的方式来进行排序。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">假设现在有用户数据如下：<br />
<img src="http://images.cnitblog.com/blog/270324/201306/14170533-b5acf18dc1904c46ba4aafc61b0e77de.png" alt="" style="border: 0px; max-width: 900px; max-height: 100%; height: auto;" /></p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">以下代码将数据输入到redis中：<br />
# admin<br />
redis 127.0.0.1:6379&gt; lpush uid 1<br />
(integer) 1</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_name_1 admin<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_level_1 9999<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># jack<br />
redis 127.0.0.1:6379&gt; lpush uid 2<br />
(integer) 2</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_name_2 jack<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_level_2 10<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># peter<br />
redis 127.0.0.1:6379&gt; lpush uid 3<br />
(integer) 3</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_name_3 peter<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_level_3 25<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># mary<br />
redis 127.0.0.1:6379&gt; lpush uid 4<br />
(integer) 4</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_name_4 mary<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; set user_level_4 70<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>6、by选项</strong><br />
默认情况下， sort uid直接按uid中的值排序：</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; sort uid<br />
1) &quot;1&quot; # admin<br />
2) &quot;2&quot; # jack<br />
3) &quot;3&quot; # peter<br />
4) &quot;4&quot; # mary<br />
通过使用by选项，可以让uid按其他键的元素来排序。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">比如说， 以下代码让uid键按照user_level_{uid}的大小来排序：<br />
redis 127.0.0.1:6379&gt; sort uid by user_level_*<br />
1) &quot;2&quot; # jack , level = 10<br />
2) &quot;3&quot; # peter, level = 25<br />
3) &quot;4&quot; # mary, level = 70<br />
4) &quot;1&quot; # admin, level = 9999<br />
user_level_*是一个占位符，它先取出uid中的值，然后再用这个值来查找相应的键。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">比如在对uid列表进行排序时，程序就会先取出uid的值1、2、3、4，然后使用user_level_1、user_level_2、user_level_3和 user_level_4的值作为排序uid的权重。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>7、get选项</strong><br />
使用get选项，可以根据排序的结果来取出相应的键值。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">比如说，以下代码先排序uid，再取出键user_name_{uid}的值：</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; sort uid get user_name_*<br />
1) &quot;admin&quot;<br />
2) &quot;jack&quot;<br />
3) &quot;peter&quot;<br />
4) &quot;mary&quot;<br />
现在的排序结果要比只使用 sort uid by user_level_* 要直观得多。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>8、获取多个外部键</strong><br />
可以同时使用多个get选项，获取多个外部键的值。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">以下代码就按 uid 分别获取 user_level_{uid} 和 user_name_{uid} ：<br />
redis 127.0.0.1:6379&gt; sort uid get user_level_* get user_name_*<br />
1) &quot;9999&quot; # level<br />
2) &quot;admin&quot; # name<br />
3) &quot;10&quot;<br />
4) &quot;jack&quot;<br />
5) &quot;25&quot;<br />
6) &quot;peter&quot;<br />
7) &quot;70&quot;<br />
8) &quot;mary&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">get有一个额外的参数规则，那就是可以用#获取被排序键的值。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">以下代码就将 uid 的值、及其相应的 user_level_* 和 user_name_* 都返回为结果：<br />
redis 127.0.0.1:6379&gt; sort uid get # get user_level_* get user_name_*<br />
1) &quot;1&quot; # uid<br />
2) &quot;9999&quot; # level<br />
3) &quot;admin&quot; # name<br />
4) &quot;2&quot;<br />
5) &quot;10&quot;<br />
6) &quot;jack&quot;<br />
7) &quot;3&quot;<br />
8) &quot;25&quot;<br />
9) &quot;peter&quot;<br />
10) &quot;4&quot;<br />
11) &quot;70&quot;<br />
12) &quot;mary&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>9、获取外部键，但不进行排序</strong><br />
通过将一个不存在的键作为参数传给 by 选项， 可以让 sort 跳过排序操作，直接返回结果：<br />
redis 127.0.0.1:6379&gt; sort uid by not-exists-key<br />
1) &quot;4&quot;<br />
2) &quot;3&quot;<br />
3) &quot;2&quot;<br />
4) &quot;1&quot;<br />
这种用法在单独使用时，没什么实际用处。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">不过，通过将这种用法和get选项配合，就可以在不排序的情况下，获取多个外部键，相当于执行一个整合的获取操作（类似于 sql数据库的join关键字）。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">以下代码演示了，如何在不引起排序的情况下，使用sort、by和get获取多个外部键：<br />
redis 127.0.0.1:6379&gt; sort uid by not-exists-key get # get user_level_* get user_name_*<br />
1) &quot;4&quot; # id<br />
2) &quot;70&quot; # level<br />
3) &quot;mary&quot; # name<br />
4) &quot;3&quot;<br />
5) &quot;25&quot;<br />
6) &quot;peter&quot;<br />
7) &quot;2&quot;<br />
8) &quot;10&quot;<br />
9) &quot;jack&quot;<br />
10) &quot;1&quot;<br />
11) &quot;9999&quot;<br />
12) &quot;admin&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>10、将哈希表作为get或by的参数</strong></p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">除了可以将字符串键之外， 哈希表也可以作为 get 或 by 选项的参数来使用。<br />
比如说，对于前面给出的用户信息表：<br />
<img src="http://images.cnitblog.com/blog/270324/201306/14170547-a6b12eaf960b4bb6816198881a1ad1ed.png" alt="" style="border: 0px; max-width: 900px; max-height: 100%; height: auto;" /></p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">我们可以不将用户的名字和级别保存在 user_name_{uid} 和 user_level_{uid} 两个字符串键中， 而是用一个带有 name 域和 level 域的哈希表 user_info_{uid} 来保存用户的名字和级别信息：<br />
redis 127.0.0.1:6379&gt; hmset user_info_1 name admin level 9999<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; hmset user_info_2 name jack level 10<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; hmset user_info_3 name peter level 25<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; hmset user_info_4 name mary level 70<br />
ok</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">之后， by 和 get 选项都可以用 key-&gt;field 的格式来获取哈希表中的域的值， 其中 key 表示哈希表键， 而 field 则表示哈希表的域：</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; sort uid by user_info_*-&gt;level<br />
1) &quot;2&quot;<br />
2) &quot;3&quot;<br />
3) &quot;4&quot;<br />
4) &quot;1&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; sort uid by user_info_*-&gt;level get user_info_*-&gt;name<br />
1) &quot;jack&quot;<br />
2) &quot;peter&quot;<br />
3) &quot;mary&quot;<br />
4) &quot;admin&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"><strong>11、保存排序结果</strong><br />
默认情况下， sort 操作只是简单地返回排序结果，并不进行任何保存操作。<br />
通过给 store 选项指定一个 key 参数，可以将排序结果保存到给定的键上。<br />
如果被指定的 key 已存在，那么原有的值将被排序结果覆盖。</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 测试数据<br />
redis 127.0.0.1:6379&gt; rpush numbers 1 3 5 7 9<br />
(integer) 5</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; rpush numbers 2 4 6 8 10<br />
(integer) 10</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; lrange numbers 0 -1<br />
1) &quot;1&quot;<br />
2) &quot;3&quot;<br />
3) &quot;5&quot;<br />
4) &quot;7&quot;<br />
5) &quot;9&quot;<br />
6) &quot;2&quot;<br />
7) &quot;4&quot;<br />
8) &quot;6&quot;<br />
9) &quot;8&quot;<br />
10) &quot;10&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">redis 127.0.0.1:6379&gt; sort numbers store sorted-numbers<br />
(integer) 10</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;"># 排序后的结果<br />
redis 127.0.0.1:6379&gt; lrange sorted-numbers 0 -1<br />
1) &quot;1&quot;<br />
2) &quot;2&quot;<br />
3) &quot;3&quot;<br />
4) &quot;4&quot;<br />
5) &quot;5&quot;<br />
6) &quot;6&quot;<br />
7) &quot;7&quot;<br />
8) &quot;8&quot;<br />
9) &quot;9&quot;<br />
10) &quot;10&quot;</p>
<p style="margin: 10px auto; color: rgb(75, 75, 75); font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 1.5;">13、返回值<br />
没有使用 store 参数，返回列表形式的排序结果。<br />
使用 store 参数，返回排序结果的元素数量</p>]]></description>
			<link>http://meisw.wdlinux.cn//show-992-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:32</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-991-1.html</guid>
			<title>redis实现简单的条件查询功能</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;今天在学习redis的时候，遇到了一个让我很纠结的问题。在sql语句中，条件查询是很简单实现的，比如：</p>
<div>select * from books where id = 1</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>这条SQL语句就能够很简单的挑选出来表books里面id等于1的书本的全部信息。但是，redis是非关系型数据库，并不支持这种通过&ldquo;键值=value&rdquo;查询数据的方式，那我们究竟该怎样实现类似的条件查询呢？</div>
<div>在登陆注册场景中，我们这样实现用户登陆时候的用户名判断。我们先假定用户信息只有用户名和密码。</div>
<div>注册：</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>exports.handle_regist = function(username,password){</div>
<div>&nbsp; client.incr('uid');</div>
<div>&nbsp; client.get('uid',function(err,uid){</div>
<div>&nbsp; //建立索引集合，username--id</div>
<div>&nbsp; &nbsp; client.set('username:'+username,uid);</div>
<div>&nbsp; &nbsp; client.hmset(&quot;user:&quot;+uid,'username',username,'password',password,function(err){</div>
<div>&nbsp; &nbsp; &nbsp; if(err){</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; return 0;</div>
<div>&nbsp; &nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; &nbsp; else{</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; return 1;</div>
<div>&nbsp; &nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; });</div>
<div>&nbsp; });</div>
<div>};</div>
<div>&nbsp;</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>这段代码中，我们实现的是存储用户的用户名和密码的操作。</div>
<div>client.incr('uid');</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>创建 键名为uid的字符串类型键值对，每次有用户注册的数据传入时候，我们都会将uid自增1。这样，其实我们就能够知道下一位用户注册时候我们应该给他分配的uid是多少了。那为什么要分配uid呢?是为了在后面建立hash类型的键值对时候需要用到，一会再说。</div>
<div>client.&lt;b&gt;get&lt;/b&gt;(&lt;font color=&quot;#dd1144&quot;&gt;'uid'&lt;/font&gt;,function(err,uid){...}</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>这行代码是干嘛的呢？很明显，我们用来挑选出字符串类型的并且key=uid的value，得到value之后，实际上我们就能够为注册的用户分配唯一的ID.</div>
<div>client.set('username:'+username,uid);</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>这行代码很关键，我们在这里设置了一个&ldquo;username：zhou=&gt;1&rdquo;类型的键值对索引。（&lsquo;zhou&rsquo;是传过来的用户名，1是刚才得到的uid）。那么这个键值对又是干嘛的？</div>
<div>这个就是实现条件索引的关键了，我们为用户名和用户id建立联系，当需要挑选出用户名为zhou的用户的密码的时候，我们首先通过这个键值对索引，找到该用户的uid，再通过这个uid得到用户名密码。这样，思路就清晰了。</div>
<div>client.hmset(&quot;user:&quot;+uid,'username',username,'password',password,function(err){...}</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>这行代码中，我们才是真正的储存用户名和密码。可以看到，我们建立了&ldquo;user：1=&gt;{username='zhou',password='123'}&rdquo;形式的键值对，其中user:uid是键名，username，password是键值中的字段，用户信息是键值中字段值。这样我们就能实现用户信息的储存了。</div>
<div>登陆功能：</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>exports.handle_login = function(username,password,callback){</div>
<div>&nbsp; client.get('username:'+username,function(err,uid){</div>
<div>&nbsp; &nbsp; if(err){</div>
<div>&nbsp; &nbsp; &nbsp; return callback(err);</div>
<div>&nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; else{</div>
<div>&nbsp; &nbsp; &nbsp; client.hget('user:'+uid,'password',function(err,pass){</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; if(err){</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var msg = 0;</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return callback(msg);</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; if(password == pass){</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var msg = 1;</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return callback(msg);</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; else{</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var msg = 2;</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return callback(msg);</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; }</div>
<div>&nbsp; &nbsp; &nbsp; });</div>
<div>&nbsp; &nbsp; }</div>
<div>&nbsp; });</div>
<div>};</div>
<div>复制代码</div>
<div>client.get('username:'+username,function(err,uid){</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>我们首先通过传过来的username，在键值对&ldquo;username：zhou=&gt;uid&rdquo;中寻找uid，如果没有该uid，说明没有注册，返回一个状态码；</div>
<div>如果找到uid，说明该用户名已经注册过，接着判断password。</div>
<div>&nbsp;</div>
<div>client.hget('user:'+uid,'password',function(err,pass){</div>
<div>复制代码</div>
<div>&nbsp;</div>
<div>通过之前得到的uid查询用户信息键值对，得到password，判断用户输入的密码是否匹配，这样就能完成判断。</div>
<div>总结：通过以上过程不难发现，redis实现条件查询其实就是需要我们自己建立id与其他属性的联系集。比如在关系型数据库里面，建立一个汽车表car：car_id,color,price.location.当我们需要查询color等于white的所有汽车信息的时候，我们首先需要建立一个car_id和color之间的联系集，color：color_value=&gt;uid,通过匹配得到uid再去查找汽车信息。这个方法看起来有点麻烦，但还是不知道有什么方法能替代(lua脚本是啥?)</div>]]></description>
			<link>http://meisw.wdlinux.cn//show-991-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:30</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-990-1.html</guid>
			<title>使用Redis的五个注意事项</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">下面内容来源于Quora上的</span><a href="http://www.quora.com/Redis/What-are-5-mistakes-to-avoid-when-using-Redis" target="_blank" class="gj_safe_a" style="word-wrap: break-word; color: rgb(51, 102, 153); font-family: Tahoma, Helvetica, SimSun, sans-serif;">一个提问</a><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">，问题是使用</span><a href="http://blog.nosqlfan.com/tags/redis" target="_blank" class="gj_safe_a" style="word-wrap: break-word; color: rgb(51, 102, 153); font-family: Tahoma, Helvetica, SimSun, sans-serif;">Redis</a><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">需要避免的五个问题。而回答中超出了五个问题的范畴，描述了五个使用Redis的注意事项。如果你在使用或者考虑使用Redis，可能你可以学习一下下面的一些建议，避免一下提到的问题。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="word-wrap: break-word; font-weight: 700; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">1.使用key值前缀来作命名空间</span><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">虽然说Redis支持多个数据库（默认32个，可以配置更多），但是除了默认的0号库以外，其它的都需要通过一个额外请求才能使用。所以用前缀作为命名空间可能会更明智一点。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">另外，在使用前缀作为命名空间区隔不同key的时候，最好在程序中使用全局配置来实现，直接在代码里写前缀的做法要严格避免，这样可维护性实在太差了。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="word-wrap: break-word; font-weight: 700; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">2.创建一个类似 &rdquo;registry&rdquo; 的key用于标记key使用情况</span><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">为了更好的管理你的key值的使用，比如哪一类key值是属于哪个业务的，你通常会在内部wiki或者什么地方创建一个文档，通过查询这个文档，我们能够知道Redis中的key都是什么作用。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">与之结合，一个推荐的做法是，在Redis里面保存一个registry值，这个值的名字可以类似于 __key_registry__ 这样的，这个key对应的value就是你文档的位置，这样我们在使用Redis的时候，就能通过直接查询这个值获取到当前Redis的使用情况了。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="word-wrap: break-word; font-weight: 700; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">3.注意垃圾回收</span><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">Redis是一个提供持久化功能的内存数据库，如果你不指定上面值的过期时间，并且也不进行定期的清理工作，那么你的Redis内存占用会越来越大，当有一天它超过了系统可用内存，那么swap上场，离性能陡降的时间就不远了。所以在Redis中保存数据时，一定要预先考虑好数据的生命周期，这有很多方法可以实现。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">比如你可以采用Redis自带的过期时间为你的数据设定过期时间。但是自动过期有一个问题，很有可能导致你还有大量内存可用时，就让key过期去释放内存，或者是内存已经不足了key还没有过期。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">如果你想更精准的控制你的数据过期，你可以用一个ZSET来维护你的数据更新程度，你可以用时间戳作为score值，每次更新操作时更新一下score，这样你就得到了一个按更新时间排序序列串，你可以轻松地找到最老的数据，并且从最老的数据开始进行删除，一直删除到你的空间足够为止。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="word-wrap: break-word; font-weight: 700; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">4.设计好你的Sharding机制</span><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">Redis目前并不支持Sharding，但是当你的数据量超过单机内存时，你不得不考虑Sharding的事（注意：Slave不是用来做Sharding操作的，只是数据的一个备份和读写分离而已）。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">所以你可能需要考虑好数据量大了后的分片问题，比如你可以在只有一台机器的时候就在程序上设定一致性hash机制，虽然刚开始所有数据都hash到一台机器，但是当你机器越加越多的时候，你就只需要迁移少量的数据就能完成了。</span><br style="word-wrap: break-word; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;" />
<span style="word-wrap: break-word; font-weight: 700; color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">5.不要有个锤子看哪都是钉子</span><span style="color: rgb(68, 68, 68); font-family: Tahoma, Helvetica, SimSun, sans-serif;">当你使用Redis构建你的服务的时候，一定要记住，你只是找了一个合适的工具来实现你需要的功能。而不是说你在用Redis构建一个服务，这是很不同的，你把Redis当作你很多工具中的一个，只在合适使用的时候再使用它，在不合适的时候选择其它的方法。</span></p>]]></description>
			<link>http://meisw.wdlinux.cn//show-990-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:30</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-989-1.html</guid>
			<title>redis info 命令查看redis使用情况</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">用客户端连接redis服务器：&nbsp; redis-cli &gt;&gt; info&nbsp; :</span></p>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">server</tt>&nbsp;: 一般 Redis 服务器信息，包含以下域：</p>
    <blockquote style="box-sizing: border-box; padding: 10px 20px; margin: 0px 0px 20px; border-left: 5px solid rgb(238, 238, 238);">
    <div style="box-sizing: border-box; margin: 0px; padding: 0px;">
    <ul class="simple" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style: disc;">
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">redis_version</tt>&nbsp;: Redis 服务器版本</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">redis_git_sha1</tt>&nbsp;: Git SHA1</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">redis_git_dirty</tt>&nbsp;: Git dirty flag</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">os</tt>&nbsp;: Redis 服务器的宿主操作系统</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">arch_bits</tt>&nbsp;: 架构（32 或 64 位）</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">multiplexing_api</tt>&nbsp;: Redis 所使用的事件处理机制</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">gcc_version</tt>&nbsp;: 编译 Redis 时所使用的 GCC 版本</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">process_id</tt>&nbsp;: 服务器进程的 PID</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">run_id</tt>&nbsp;: Redis 服务器的随机标识符（用于 Sentinel 和集群）</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">tcp_port</tt>&nbsp;: TCP/IP 监听端口</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">uptime_in_seconds</tt>&nbsp;: 自 Redis 服务器启动以来，经过的秒数</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">uptime_in_days</tt>&nbsp;: 自 Redis 服务器启动以来，经过的天数</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">lru_clock</tt>&nbsp;: 以分钟为单位进行自增的时钟，用于 LRU 管理</li>
    </ul>
    </div>
    </blockquote></li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">clients</tt>&nbsp;: 已连接客户端信息，包含以下域：</p>
    <blockquote style="box-sizing: border-box; padding: 10px 20px; margin: 0px 0px 20px; border-left: 5px solid rgb(238, 238, 238);">
    <div style="box-sizing: border-box; margin: 0px; padding: 0px;">
    <ul class="simple" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style: disc;">
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">connected_clients</tt>&nbsp;: 已连接客户端的数量（不包括通过从属服务器连接的客户端）</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">client_longest_output_list</tt>&nbsp;: 当前连接的客户端当中，最长的输出列表</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">client_longest_input_buf</tt>&nbsp;: 当前连接的客户端当中，最大输入缓存</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">blocked_clients</tt>&nbsp;: 正在等待阻塞命令（BLPOP、BRPOP、BRPOPLPUSH）的客户端的数量</li>
    </ul>
    </div>
    </blockquote></li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">memory</tt>&nbsp;: 内存信息，包含以下域：</p>
    <blockquote style="box-sizing: border-box; padding: 10px 20px; margin: 0px 0px 20px; border-left: 5px solid rgb(238, 238, 238);">
    <div style="box-sizing: border-box; margin: 0px; padding: 0px;">
    <ul class="simple" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style: disc;">
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory</tt>&nbsp;: 由 Redis 分配器分配的内存总量，以字节（byte）为单位</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory_human</tt>&nbsp;: 以人类可读的格式返回 Redis 分配的内存总量</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory_rss</tt>&nbsp;: 从操作系统的角度，返回 Redis 已分配的内存总量（俗称常驻集大小）。这个值和<tt class="docutils literal" style="box-sizing: border-box;">top</tt>&nbsp;、&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">ps</tt>&nbsp;等命令的输出一致。</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory_peak</tt>&nbsp;: Redis 的内存消耗峰值（以字节为单位）</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory_peak_human</tt>&nbsp;: 以人类可读的格式返回 Redis 的内存消耗峰值</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">used_memory_lua</tt>&nbsp;: Lua 引擎所使用的内存大小（以字节为单位）</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">mem_fragmentation_ratio</tt>&nbsp;:<tt class="docutils literal" style="box-sizing: border-box;">used_memory_rss</tt>&nbsp;和&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">used_memory</tt>&nbsp;之间的比率</li>
        <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">mem_allocator</tt>&nbsp;: 在编译时指定的， Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。</li>
    </ul>
    <div class="line-block" style="box-sizing: border-box; margin: 0px; padding: 0px;">
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">在理想情况下，&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">used_memory_rss</tt>&nbsp;的值应该只比<tt class="docutils literal" style="box-sizing: border-box;">used_memory</tt>&nbsp;稍微高一点儿。</div>
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">当&nbsp;<tt class="docutils literal" style="box-sizing: border-box;"><span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">rss</span>&nbsp;<span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">&gt;</span>&nbsp;<span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">used</span></tt>&nbsp;，且两者的值相差较大时，表示存在（内部或外部的）内存碎片。</div>
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">内存碎片的比率可以通过&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">mem_fragmentation_ratio</tt>&nbsp;的值看出。</div>
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">当&nbsp;<tt class="docutils literal" style="box-sizing: border-box;"><span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">used</span>&nbsp;<span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">&gt;</span>&nbsp;<span class="pre" style="box-sizing: border-box; margin: 0px; padding: 0px;">rss</span></tt>&nbsp;时，表示 Redis 的部分内存被操作系统换出到交换空间了，在这种情况下，操作可能会产生明显的延迟。</div>
    </div>
    <p style="box-sizing: border-box; margin-bottom: 0px; font-size: 17.5px; line-height: 1.25; word-wrap: break-word; word-break: normal;">Because Redis does not have control over how its allocations are mapped to memory pages, high<tt class="docutils literal" style="box-sizing: border-box;">used_memory_rss</tt>&nbsp;is often the result of a spike in memory usage.</p>
    <div class="line-block" style="box-sizing: border-box; margin: 0px; padding: 0px;">
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">当 Redis 释放内存时，分配器可能会，也可能不会，将内存返还给操作系统。</div>
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">如果 Redis 释放了内存，却没有将内存返还给操作系统，那么&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">used_memory</tt>&nbsp;的值可能和操作系统显示的 Redis 内存占用并不一致。</div>
    <div class="line" style="box-sizing: border-box; margin: 0px; padding: 0px;">查看&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">used_memory_peak</tt>&nbsp;的值可以验证这种情况是否发生。</div>
    </div>
    </div>
    </blockquote></li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">persistence</tt>&nbsp;:<tt class="docutils literal" style="box-sizing: border-box;">RDB</tt>&nbsp;和&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">AOF</tt>&nbsp;的相关信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">stats</tt>&nbsp;: 一般统计信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">replication</tt>&nbsp;: 主/从复制信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">cpu</tt>&nbsp;: CPU 计算量统计信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">commandstats</tt>&nbsp;: Redis 命令统计信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">cluster</tt>&nbsp;: Redis 集群信息</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;">
    <p class="first" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;"><tt class="docutils literal" style="box-sizing: border-box;">keyspace</tt>&nbsp;: 数据库相关的统计信息</p>
    </li>
</ul>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">除上面给出的这些值以外，参数还可以是下面这两个：</p>
<ul class="simple" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">all</tt>&nbsp;: 返回所有信息</li>
    <li style="box-sizing: border-box; margin: 0px 0px 0px 40px; padding: 0px; list-style: disc;"><tt class="docutils literal" style="box-sizing: border-box;">default</tt>&nbsp;: 返回默认选择的信息</li>
</ul>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">当不带参数直接调用&nbsp;<a target="_blank" class="reference internal" href="http://redis.readthedocs.org/en/latest/server/info.html#info" style="box-sizing: border-box; background: transparent; color: rgb(202, 12, 22); text-decoration-line: none; margin: 0px; padding: 0px; outline: 0px;">INFO</a>&nbsp;命令时，使用&nbsp;<tt class="docutils literal" style="box-sizing: border-box;">default</tt>&nbsp;作为默认参数。</p>
<div class="admonition note" style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;">不同版本的 Redis 可能对返回的一些域进行了增加或删减。</p>
<p class="last" style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal;">因此，一个健壮的客户端程序在对&nbsp;<a target="_blank" class="reference internal" href="http://redis.readthedocs.org/en/latest/server/info.html#info" style="box-sizing: border-box; background: transparent; color: rgb(202, 12, 22); text-decoration-line: none; margin: 0px; padding: 0px; outline: 0px;"><em style="box-sizing: border-box;">INFO</em></a>&nbsp;命令的输出进行分析时，应该能够跳过不认识的域，并且妥善地处理丢失不见的域。</p>
</div>]]></description>
			<link>http://meisw.wdlinux.cn//show-989-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:18</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-988-1.html</guid>
			<title>Redis 数据操作命令</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;</p>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;">1、连接操作相关的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">quit：关闭连接（connection）</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">auth：简单密码认证</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t1" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>2、对value操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">exists(key)：确认一个key是否存在</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">del(key)：删除一个key</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">type(key)：返回值的类型</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">keys(pattern)：返回满足给定pattern的所有key</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">randomkey：随机返回key空间的一个key</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">rename(oldname, newname)：将key由oldname重命名为newname，若newname存在则删除newname表示的key</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">dbsize：返回当前数据库中key的数目</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">expire：设定一个key的活动时间（s）</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">ttl：获得一个key的活动时间</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">select(index)：按索引查询</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">move(key, dbindex)：将当前数据库中的key转移到有dbindex索引的数据库</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">flushdb：删除当前选择数据库中的所有key</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">flushall：删除所有数据库中的所有key</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t2" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>3、对String操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">set(key, value)：给数据库中名称为key的string赋予值value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">get(key)：返回数据库中名称为key的string的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">getset(key, value)：给名称为key的string赋予上一次的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">mget(key1, key2,&hellip;, key N)：返回库中多个string（它们的名称为key1，key2&hellip;）的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">setnx(key, value)：如果不存在名称为key的string，则向库中添加string，名称为key，值为value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">setex(key, time, value)：向库中添加string（名称为key，值为value）同时，设定过期时间time</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">mset(key1, value1, key2, value2,&hellip;key N, value N)：同时给多个string赋值，名称为key i的string赋值value i</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">msetnx(key1, value1, key2, value2,&hellip;key N, value N)：如果所有名称为key i的string都不存在，则向库中添加string，名称key i赋值为value i</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">incr(key)：名称为key的string增1操作</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">incrby(key, integer)：名称为key的string增加integer</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">decr(key)：名称为key的string减1操作</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">decrby(key, integer)：名称为key的string减少integer</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">append(key, value)：名称为key的string的值附加value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">substr(key, start, end)：返回名称为key的string的value的子串</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t3" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>4、对List操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">rpush(key, value)：在名称为key的list尾添加一个值为value的元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lpush(key, value)：在名称为key的list头添加一个值为value的 元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">llen(key)：返回名称为key的list的长度</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lrange(key, start, end)：返回名称为key的list中start至end之间的元素（下标从0开始，下同）</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">ltrim(key, start, end)：截取名称为key的list，保留start至end之间的元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lindex(key, index)：返回名称为key的list中index位置的元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lset(key, index, value)：给名称为key的list中index位置的元素赋值为value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lrem(key, count, value)：删除count个名称为key的list中值为value的元素。count为0，删除所有值为value的元素，count&gt;0从头至尾删除count个值为value的元素，count&lt;0从尾到头删除|count|个值为value的元素。 lpop(key)：返回并删除名称为key的list中的首元素 rpop(key)：返回并删除名称为key的list中的尾元素 blpop(key1, key2,&hellip; key N, timeout)：lpop命令的block版本。即当timeout为0时，若遇到名称为key i的list不存在或该list为空，则命令结束。如果timeout&gt;0，则遇到上述情况时，等待timeout秒，如果问题没有解决，则对keyi+1开始的list执行pop操作。</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">brpop(key1, key2,&hellip; key N, timeout)：rpop的block版本。参考上一命令。</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">rpoplpush(srckey, dstkey)：返回并删除名称为srckey的list的尾元素，并将该元素添加到名称为dstkey的list的头部</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t4" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>5、对Set操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sadd(key, member)：向名称为key的set中添加元素member</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">srem(key, member) ：删除名称为key的set中的元素member</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">spop(key) ：随机返回并删除名称为key的set中一个元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">smove(srckey, dstkey, member) ：将member元素从名称为srckey的集合移到名称为dstkey的集合</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">scard(key) ：返回名称为key的set的基数</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sismember(key, member) ：测试member是否是名称为key的set的元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sinter(key1, key2,&hellip;key N) ：求交集</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sinterstore(dstkey, key1, key2,&hellip;key N) ：求交集并将交集保存到dstkey的集合</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sunion(key1, key2,&hellip;key N) ：求并集</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sunionstore(dstkey, key1, key2,&hellip;key N) ：求并集并将并集保存到dstkey的集合</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sdiff(key1, key2,&hellip;key N) ：求差集</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">sdiffstore(dstkey, key1, key2,&hellip;key N) ：求差集并将差集保存到dstkey的集合</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">smembers(key) ：返回名称为key的set的所有元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">srandmember(key) ：随机返回名称为key的set的一个元素</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t5" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>6、对zset（sorted set）操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zadd(key, score, member)：向名称为key的zset中添加元素member，score用于排序。如果该元素已经存在，则根据score更新该元素的顺序。</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrem(key, member) ：删除名称为key的zset中的元素member</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zincrby(key, increment, member) ：如果在名称为key的zset中已经存在元素member，则该元素的score增加increment；否则向集合中添加该元素，其score的值为increment</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrank(key, member) ：返回名称为key的zset（元素已按score从小到大排序）中member元素的rank（即index，从0开始），若没有member元素，返回&ldquo;nil&rdquo;</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrevrank(key, member) ：返回名称为key的zset（元素已按score从大到小排序）中member元素的rank（即index，从0开始），若没有member元素，返回&ldquo;nil&rdquo;</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrange(key, start, end)：返回名称为key的zset（元素已按score从小到大排序）中的index从start到end的所有元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrevrange(key, start, end)：返回名称为key的zset（元素已按score从大到小排序）中的index从start到end的所有元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zrangebyscore(key, min, max)：返回名称为key的zset中score &gt;= min且score &lt;= max的所有元素 zcard(key)：返回名称为key的zset的基数 zscore(key, element)：返回名称为key的zset中元素element的score zremrangebyrank(key, min, max)：删除名称为key的zset中rank &gt;= min且rank &lt;= max的所有元素 zremrangebyscore(key, min, max) ：删除名称为key的zset中score &gt;= min且score &lt;= max的所有元素</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">zunionstore / zinterstore(dstkeyN, key1,&hellip;,keyN, WEIGHTS w1,&hellip;wN, AGGREGATE SUM|MIN|MAX)：对N个zset求并集和交集，并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score，在进行AGGREGATE运算前，都要乘以对于的WEIGHT参数。如果没有提供WEIGHT，默认为1。默认的AGGREGATE是SUM，即结果集合中元素的score是所有集合对应元素进行SUM运算的值，而MIN和MAX是指，结果集合中元素的score是所有集合对应元素中最小值和最大值。</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t6" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>7、对Hash操作的命令</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hset(key, field, value)：向名称为key的hash中添加元素field&lt;&mdash;&gt;value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hget(key, field)：返回名称为key的hash中field对应的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hmget(key, field1, &hellip;,field N)：返回名称为key的hash中field i对应的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hmset(key, field1, value1,&hellip;,field N, value N)：向名称为key的hash中添加元素field i&lt;&mdash;&gt;value i</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hincrby(key, field, integer)：将名称为key的hash中field的value增加integer</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hexists(key, field)：名称为key的hash中是否存在键为field的域</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hdel(key, field)：删除名称为key的hash中键为field的域</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hlen(key)：返回名称为key的hash中元素个数</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hkeys(key)：返回名称为key的hash中所有键</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hvals(key)：返回名称为key的hash中所有键对应的value</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">hgetall(key)：返回名称为key的hash中所有的键（field）及其对应的value</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t7" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>8、持久化</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">save：将数据同步保存到磁盘</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">bgsave：将数据异步保存到磁盘</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">lastsave：返回上次成功将数据保存到磁盘的Unix时戳</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">shundown：将数据同步保存到磁盘，然后关闭服务</li>
</ul>
<h3 style="box-sizing: border-box; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: 100; line-height: 1.1; color: rgb(69, 69, 69); margin: 0.8em 0px; font-size: 1.7em; padding: 0px;"><a name="t8" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); margin: 0px; padding: 0px; outline: 0px;"></a>9、远程服务控制</h3>
<ul style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; list-style-position: initial; list-style-image: initial; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">info：提供服务器的信息和统计</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">monitor：实时转储收到的请求</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">slaveof：改变复制策略设置</li>
    <li style="box-sizing: border-box; margin: 0px; padding: 2px 0px 2px 30px; list-style: disc; clear: both;">config：在运行时配置Redis服务器</li>
</ul>]]></description>
			<link>http://meisw.wdlinux.cn//show-988-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:15</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-987-1.html</guid>
			<title>从Redis+Lua到Goroutine，日均10亿次的股票行情计算</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="color: rgb(63, 63, 63); font-family: Avenir, sans-serif;">股票行情数据是一种典型的时序数据（Time-series Data），在一般的IT系统中，日志数据其实也是一种时序数据，在大数据的世界里，也有大量应用是基于时序数据处理的，可以说时间序列的数据无处不在。所以，哪怕是不炒股、不熟悉金融世界的工程师，从本文也可以了解一些具有普遍性的技术思考，例如在大规模、高密度的数据处理中，是把数据快照搬到计算节点作运算还是把计算能力放到数据节点中&ldquo;就地计算&rdquo;？协程（co-routine）在这类计算密集型系统中又有何作用？</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">实时行情服务是券商的基础服务，给普通投资者描绘出风云变幻的动态市场画面，也给量化投资者提供最重要的建模基础数据和下单信号，时间就是金钱，行情服务必须要快。证券交易系统行情指标很丰富，最基础常见的包括：行情报价、分笔数据、分时数据、分钟K线、日周月年K线、各类财务技术指标、多维度排序、多维度统计等等，这些指标需要由交易所的行情数据流结合时间流进行统计计算。本文分享广发证券行情服务并行化计算演进的过程，包括五个部分：</p>
<ul class="list-paddingleft-2" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 30px; list-style-position: initial; list-style-image: initial; font-size: 16px; max-width: 100%; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; word-wrap: break-word !important;">
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">股票行情是怎么回事</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">日均10亿次的行情指标计算</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">基于Redis+Lua的方案：&ldquo;就地计算&rdquo;</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">引入Goroutine的方案：&ldquo;海量算子&rdquo;</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">孰优孰劣</p>
    </li>
</ul>
<p><span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">一、不炒股没关系，股票行情科普在这里</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">任何交易在达成之前，通常都有一个讨价还价的僵持过程，或者买方让价，或者卖方让价，两不相让的时候需要第三方介入撮合取个&ldquo;平均价&rdquo;，这个过程就是定价。证券股票交易也不例外，不同的是买卖双方互不可见，双方通过券商渠道把自己的价量报给交易所，交易所通常按照达成最大成交量的原则撮合定价。撮合涉及order book和tick data两个概念。交易所维护两个&ldquo;账本&rdquo;分别记录买方和卖方申报的价量，实时或按照一定频率进行撮合定价成交，申报、成交时对&ldquo;账本&rdquo;进行增、改、删操作。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">这两个&ldquo;账本&rdquo;就称作order book，对order book增改删操作引起数据变化，每个变化的快照就称作tick data。国内股民数超 1.2 亿户，A股上市公司近3000家，可以想见的到order book是一个大&ldquo;账本&rdquo;，tick data瞬息万变，一个交易日产生的tick data量更是惊人。国内交易所目前采用抓取快照的方式，抓取order book的前五/十档价量，剔除&rdquo;无用的&rdquo;其他档价量数据，统计交易当日开市时点到目前时点的最高、最低、成交量、成交额数据，我们将这种数据称为原始行情数据（如图1）。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">交易所将原始行情数据近实时的发送给券商，券商行情系统对这份原始数据进一步处理，比如按时间区间统计出5分钟、10分钟、15分钟、30分钟、1小时、1天、1周、1月、1季度、1年这十个周期时间段K线蜡烛图的高、开、低、收价格及成交量、成交额数据。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">券商将处理好的行情数据揭示给投资者做再报价参考。可见这类数据量大、变化频繁、中间统计计算耗时，一旦延迟，以后就再也跟不上&ldquo;实时&rdquo;的节奏了。又快又准，是股票行情服务的基本要求，任何误差、延迟，都可以引起交易者的经济损失，导致投诉甚至社会事件。系统该如何设计才能高速的处理和展示这类实时行情数据，是个很大的技术挑战。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; text-align: center; word-wrap: break-word !important;">图1</p>
<p><span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">二、你们股炒的爽，我们指标算的酸爽</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">券商行情系统可以分为行情原始数据接收解析、中间指标统计计算处理、行情数据请求响应三个模块。原始数据接收解析模块只需要做好与不同交易所的行情消息格式适配即可，行情数据请求响应模块要达到原始行情报价及各类行情统计指标的快速展现需要减少中间处理步骤，在行情原始数据接收解析、统计指标计算完成后立即推送给终端用户，同时存一份到内存数据库中以便终端用户再次查询读取，推送与查询两路相结合，达到在数据落地之前即已展示给用户的效果。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">剩下要做的就是要尽量减少中间指标统计计算的处理时延。A股上市公司3000多家，基金加债券数更是上万，但它们之间是无关联的，在统计计算时完全可以分片、并行处理，存储上采用内存数据库，redis内置多种数据结构的支持满足多统计指标存储的需求、容易分片部署便于并行计算，如图2。</p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-break: normal; font-size: 16px; max-width: 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; text-align: center; word-wrap: break-word !important;"><span style="color: rgb(63, 63, 63); font-family: Avenir, sans-serif; font-size: 17px;">图 2</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">以最简单的十个周期时间段的K线统计指标，证券数保守算1w只，10*1w=10w，也就是说分分秒秒就有近10w的计算量，国内沪深交易所一个交易日开市4个小时，按照交易所行情数据每3秒更新一次，可得出日计算量就有4.8亿，加上其他指标计算如市盈率、涨跌幅、换手率、委比委差、多板块多指标排序，日计算量已突破10亿。</p>
<p><span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">三、&ldquo;就地计算&rdquo;的方案 &ndash; 把计算能力放在数据里</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">好在不同的证券可以分片并行、同样各周期段的K线指标也可以并行统计计算，实时处理这么大的计算量，我们显然需要高度并行处理。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">我们最早的方案基于Redis，因为Redis是一个非常好的承载时间序列数据的高性能内存存储技术。Redis除了内置多种数据结构，还内置了Lua语言解释器，这意味着Redis除了具备数据存储能力也拥有了数据计算的能力。一个Redis存储集群中，每个节点加载Lua脚本，这基本上就是一个分布式并行计算集群了。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">我们剩下要做的是事情是实现一个行情收集器，接收来自不同交易所的行情原始数据（node.js善于处理io型事务，很适合用来实现收集器，细节不是本文焦点，不在此详述），发送eval lua指令到Redis集群。 Redis收到指令后执行我们用Lua实现的指标计算逻辑完成指标计算，之后通过Redis pub将行情数据推送出去。如图3通过将计算挪到Redis存储节点，我们避免了复杂易出错的多进程管理问题，也大大简化了开发的工作量。</p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-break: normal; font-size: 16px; max-width: 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; text-align: center; word-wrap: break-word !important;"><span style="color: rgb(63, 63, 63); font-family: Avenir, sans-serif; font-size: 17px;">图 3</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">这个方案的一个优点，是技术架构比较简单，从数据存储到运算处理，都在Redis上，我们仅专注于Redis集群的性能优化、高可用方案实现、容灾备份、数据复制。对于运维来说，运维一套相对单一的技术系统，&ldquo;零部件&rdquo;（moving parts）越少越好，出现故障、单点失败的环节也少了很多。</p>
<p><span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">四、&ldquo;海量算子&rdquo;- 把数据快照挪到技术节点</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">上述Redis+Lua的方案，早期也服务了我们的市场与客户，但是当指标计算量不断增大后，其不足也日益显著，主要体现在高度密集的计算导致影响存储集群的性能而产生延迟，并且在交易期间对存储集群作动态扩容是非常困难的。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">有鉴于此，我们很自然的只能把指标计算任务从数据存储中回收，放弃一个数据与计算一体化的相对简单的架构，把计算的职责交给存储之外的专用运算节点。此时Redis变成单纯的内存存储。这种实现将计算与存储分离，计算所需的数据不再能从&rdquo;本地&rdquo;获取到了，对于Redis而言，运算服务算是&ldquo;out of process&rdquo;（进程外），所以计算指标所需的数据，必须以一份数据快照的方式从Redis传递到运算节点，用以计算和更新，计算结果最终回写到Redis，如图4。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">这个对于Redis而言&ldquo;out of process&rdquo;的计算能力，我们称之为运算节点（相对于Redis的数据节点），是一系列非常容易水平扩容的、高度并发的程序，我们采用了Golang来实现。Golang这个语言，天生支持协程(Goroutine) &ndash; 在一个运行的Golang程序中，可轻易启动上万的协程，所消耗的资源远小于线程，天生适合并行计算。</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">当接收到交易所tick数据时， 在一个运算节点中对每只证券解析及每类指标计算启动单独的goroutine，每个goroutine在它的生命周期中只做一件事就结束（存活时间毫秒级），这很像数学上的函数执行过程完全没有副作用，goroutine就是一个闭包算子，相互之间毫无影响。&nbsp;</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">Golang的内存回收是并行的，数万个goroutine启动到销毁对性能的影响很小，另外tick data本身是有间隔的从交易所发过来的，在goroutine销毁那一刻往往是tick data空闲的间隔时间，这个空闲时机点用来做goroutine回收是合适的。当然也有一些常驻goroutine用来将指标结果数据落地到Redis。程序语言本身是有各自不同的设计哲学的，Golang正是这样一种语言，其协程机制让我们能够更细粒度的处理可分而治之的系统，同时免去了复杂易出错的多进程、多线程问题。</p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-break: normal; font-size: 16px; max-width: 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; text-align: center; word-wrap: break-word !important;"><span style="color: rgb(63, 63, 63); font-family: Avenir, sans-serif; font-size: 17px;">图 4</span></p>
<p><span style="color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">五、方案比较 - 孰优孰劣</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">两种方案的对比：</p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">1、Redis既负责存储也负责计算</span></p>
<ul class="list-paddingleft-2" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 30px; list-style: square; font-size: 16px; max-width: 100%; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; word-wrap: break-word !important;">
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">我们通过搭建Redis集群来进行分布式并行计算，Redis集群本身有主备节点，这就涉及到主备同步的问题，虽然Redis自己解决了同步问题并且也支持增量同步，但通过eval lua指令在存储节点上计算时，同步的不是计算结果而是计算本身，也就是说同一个指标计算在主节点和备节点都需要各自计算一次。Redis又是单线程处理，对于复杂的指标计算通过查看SLOWLOG会有上百毫秒的延迟，这会造成阻塞，对于要求快速的行情服务是不可接受的，为了减少阻塞，就需要尽可能多的进行分片，这意味着需要起更多的redis节点。</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">Redis集群一旦搭建，节点缩扩容需要人工干预。对于证券行情服务这种目前9:30-15:00业务高峰，其他时段空闲的系统来说，高峰时无法弹性扩容，低峰时Redis节点进程无法回收造成资源浪费。</p>
    </li>
</ul>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">2、Redis负责存储，海量Goroutine做算子</span></p>
<ul class="list-paddingleft-2" style="box-sizing: border-box; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 30px; list-style: square; font-size: 16px; max-width: 100%; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; word-wrap: break-word !important;">
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">将指标计算从Redis拿出来交给goroutine，Redis仅作存储节点，主备节点同步的是指标计算结果，这样降低了Redis进程的cpu使用率，也不再有SLOWLOG记录，同时仅需要很少的分片，大大减少了Redis节点数。</p>
    </li>
    <li style="box-sizing: border-box; margin: 0px; padding: 0px; list-style: disc; max-width: 100%; word-wrap: break-word !important;">
    <p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">Redis集群规模的大小仅需要根据业务数据量确定。指标计算量的变化可以轻易通过启动更多的goroutine来进行方便的弹性扩容，goroutine数也随投资者活跃程度变化，对交易频繁的股票只需要启动更多的goroutine，不会像方案1那样造成部分Redis节点成为热点。在休市时段goroutine完全回收释放。</p>
    </li>
</ul>
<p style="box-sizing: border-box; margin-bottom: 0px; word-break: normal; font-size: 16px; max-width: 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; text-align: center; word-wrap: break-word !important;"><span style="color: rgb(63, 63, 63); font-family: Avenir, sans-serif; font-size: 17px;">图 5</span></p>
<p style="box-sizing: border-box; margin-bottom: 1em; word-break: normal; max-width: 100%; clear: both; min-height: 1em; color: rgb(63, 63, 63); font-size: 17px; line-height: 1.75em; font-family: Avenir, sans-serif; word-wrap: break-word !important;">从Redis+Lua的数据存储与运算一体化，过度到数据存储与并行运算分离，也大大减少了系统对硬件资源的要求，Redis集群规模减少十倍，如图表1。采用Redis+Lua方案实现上比较简单，开发工作量较小，收集器与Redis数据交换量小，这种方案更适合简单的逻辑计算比如计数器；goroutine的实现方案，虽然开发上复杂，与Redis数据交换量大了一些，但更适合像行情指标计算这类复杂的应用场景。</p>
<table width="736" style="box-sizing: border-box; border-collapse: collapse; border-spacing: 0px; max-width: 100%; font-size: 16px; margin: 0px 0px 10px; padding: 0px; width: 670px; color: rgb(62, 62, 62); font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; line-height: 25.6px; word-wrap: break-word !important;">
    <tbody style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">
        <tr style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">
            <td height="47" width="160" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">方案</td>
            <td width="87" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">机器数（1个部署单元）</td>
            <td width="87" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">Redis集群</td>
            <td width="87" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">总CPU核数</td>
            <td width="55" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">总内存</td>
            <td width="63" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">计算最大延迟</td>
        </tr>
        <tr style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">
            <td height="56" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">In-process：数据&ldquo;就地计算&rdquo;（利用Lua）</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">5台高配</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">90个节点</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">128核</td>
            <td width="3" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">128G</td>
            <td width="50" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">几十毫秒</td>
        </tr>
        <tr style="box-sizing: border-box; margin: 0px; padding: 0px; max-width: 100%; word-wrap: break-word !important;">
            <td height="37" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">Out of &nbsp;process：数据快照挪到运算节点（基于goroutine）</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">4台中配</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">9个节点</td>
            <td style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">32核</td>
            <td width="3" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">64G</td>
            <td width="50" style="box-sizing: border-box; margin: 0px; padding: 5px 10px; word-break: break-all; border: 1px solid rgb(221, 221, 221); max-width: 100%; word-wrap: break-word !important;">几毫秒</td>
        </tr>
    </tbody>
</table>]]></description>
			<link>http://meisw.wdlinux.cn//show-987-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:14</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-986-1.html</guid>
			<title>Redis: 为行情数据库设计键值</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;<span style="font-size: 12px; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;">&nbsp;</span><span style="font-size: 12px; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;">&nbsp;如果说用传统关系数据库如MSSQL,MYSQL,PGSQL来设计一个行情数据库，除表名外，就是列字段了。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;比如，表名：600036.SH_1min, &nbsp;(这里假定每个个股设计一张表，避免把所有的个股放在一张表中，导致数据以亿计，查询效率太低)</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;举例而言，其中一条记录（虚拟）</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; code :600036.SH Date :2014-10-09 DateTime: 930 Open: 9.60 High:10.08 Close:10.02 Low :9.54 Volume: 123456 Amount :78964531 Factor: 5.123</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 另外，成份股的指数权属作为另外一张表而存在，不放在这里，否则太大，也浪费空间。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; 如果以内存数据库Redis来设计key-value,相对的key 就会比较长，但value比较简单。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;因为key的唯一性，</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;比如，同样以上面的记录而言，可能就要设计一个唯一的KEY:</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key1: &nbsp;600036.SH_1min:2014-10-09:0930:Open &nbsp;=&gt; value1 :9.60</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key2: &nbsp;600036.SH_1min:2014-10-09:0930:High &nbsp; &nbsp;=&gt; value 2:10.08<br style="box-sizing: border-box;" />
</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;">&nbsp;</p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key3: &nbsp;600036.SH_1min:2014-10-09:0930:Close &nbsp;=&gt; value3 :10.02</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key4: &nbsp;600036.SH_1min:2014-10-09:0930:Low &nbsp; &nbsp; =&gt; value4 :9.54</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ......</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 也就是说</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set &nbsp;&nbsp;600036.SH_1min:2014-10-09:0930:Open &nbsp;9.60</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set &nbsp;&nbsp;600036.SH_1min:2014-10-09:0930:High &nbsp;10.08<br style="box-sizing: border-box;" />
</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set &nbsp;&nbsp;600036.SH_1min:2014-10-09:0930:Close&nbsp; &nbsp;10.02</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set &nbsp;&nbsp;600036.SH_1min:2014-10-09:0930:Low &nbsp;9.54</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.......</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这样，就可以建立一系列的KEY-VALUE结构的非结构化数据了。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;下面，针对历史行情数据库中，典型的日度数据，N分钟数据，TICK数据，我们要进行一个整体上的数据库设计。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(1) 类型的设计</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 我个人认为，用hash的方式来设历史行情库，可能会更好。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(2) KEY 的设计</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一般而言，而行情数据库的KEY要包含代码名称（比如，600036.SH）.但是，因为分钟数据和日度数据的粒度相差较大，如何统一考虑？</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;其中，不同类型的数据的文件名应有唯一性。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A、分钟数据：</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件变量名：&quot;600036.sh_1min&ldquo;，假设有6年的数据，6*250*270 &nbsp;约40万条左右的数据记录源（注意KEY个数还要乘以记录的字段数，下同。）</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; KEY ： &ldquo;600036.sh_1min_2014-10-09_930&rdquo;&nbsp; =&gt; 开盘价，收盘价，最高价，最低价，成交量，成交金额，复权因子....</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; B、TICK数据：</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件变量名：&rdquo;600036.sh_Tick_<span style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(51, 51, 51); font-family: Arial; line-height: 25.9954px;">2014-10-09</span>&ldquo; &nbsp;</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # &nbsp;把每天的TICK，有数千条（股票）甚至数万条（期货）放到一个变量中。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;KEY：&nbsp;&rdquo;600036.sh_Tick_2014-10-09 _930_01.001</span><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&ldquo; =&gt;</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; C、日度数据：</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件变量名：&rdquo;600036.sh_1day&ldquo;，假设6年数据，此文件大约会储存 6*250 =1500条左右数据源。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; KEY： &ldquo; 600036.sh_1day_2014-10-09&rdquo; =&gt;</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;另外，数据中应考虑不同类类型的数据，可能具有不同的特征，如 股票：复权因子，期货：未平仓合约量 。</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; （3）性能比较</span></p>
<p style="box-sizing: border-box; margin-bottom: 0px; word-wrap: break-word; word-break: normal; color: rgb(69, 69, 69); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-size: 16px;"><span style="box-sizing: border-box; margin: 0px; padding: 0px; font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;数据如何设计，关键要看性能和维度容易程度。这块需要后续实证了。</span></p>]]></description>
			<link>http://meisw.wdlinux.cn//show-986-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:13</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-985-1.html</guid>
			<title>redis应用,nginx,lua</title>
			<author>admin</author>
			<description><![CDATA[<h1 class="csdn_top" style="box-sizing: border-box; margin: 0px; font-size: 24px; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; line-height: 38px; color: rgb(44, 48, 51); padding: 0px 29px;">nginx + lua + redis 防刷和限流</h1>
<p>&nbsp;</p>
<div>http://blog.csdn.net/fenglvming/article/details/51996406</div>
<div>&nbsp;</div>
<div>
<h1 class="csdn_top" style="box-sizing: border-box; margin: 0px; font-size: 24px; font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; line-height: 38px; color: rgb(44, 48, 51); padding: 0px 29px;">利用redis + lua解决抢红包高并发的问题</h1>
</div>
<div>http://blog.csdn.net/hengyunabc/article/details/19433779</div>
<div>&nbsp;</div>
<div><font face="microsoft yahei"><span style="font-size: 18px;"><strong>Go实战--golang中使用redis(redigo和go-redis/redis)</strong></span></font></div>
<div><font face="microsoft yahei"><span style="font-size: 18px;"><strong>http://blog.csdn.net/wangshubo1989/article/details/75050024</strong></span></font></div>]]></description>
			<link>http://meisw.wdlinux.cn//show-985-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:12</pubDate>
		</item>
		<item>
			<guid>http://meisw.wdlinux.cn//show-984-1.html</guid>
			<title>redis的常用命令</title>
			<author>admin</author>
			<description><![CDATA[<p>&nbsp;redis的常用命令主要分为两个方面、一个是键值相关命令、一个是服务器相关命令</p>
<div>1、键值相关命令</div>
<div>&nbsp; &nbsp; &nbsp; keys * 取出当前所有的key</div>
<div>&nbsp; &nbsp; &nbsp; exists name 查看n是否有name这个key</div>
<div>&nbsp; &nbsp; &nbsp; del name 删除key name</div>
<div>&nbsp; &nbsp; &nbsp; expire confirm 100 设置confirm这个key100秒过期</div>
<div>&nbsp; &nbsp; &nbsp; ttl confirm 获取confirm 这个key的有效时长</div>
<div>&nbsp; &nbsp; &nbsp; select 0 选择到0数据库 redis默认的数据库是0~15一共16个数据库</div>
<div>&nbsp; &nbsp; &nbsp; move confirm 1 将当前数据库中的key移动到其他的数据库中，这里就是把confire这个key从当前数据库中移动到1中</div>
<div>&nbsp; &nbsp; &nbsp; persist confirm 移除confirm这个key的过期时间</div>
<div>&nbsp; &nbsp; &nbsp; randomkey 随机返回数据库里面的一个key</div>
<div>&nbsp; &nbsp; &nbsp; rename key2 key3 重命名key2 为key3</div>
<div>&nbsp; &nbsp; &nbsp; type key2 返回key的数据类型</div>
<div>2、服务器相关命令</div>
<div>&nbsp; &nbsp; &nbsp; ping PONG返回响应是否连接成功</div>
<div>&nbsp; &nbsp; &nbsp; echo 在命令行打印一些内容</div>
<div>&nbsp; &nbsp; &nbsp; select 0~15 编号的数据库</div>
<div>&nbsp; &nbsp; &nbsp; quit&nbsp; /exit 退出客户端</div>
<div>&nbsp; &nbsp; &nbsp; dbsize 返回当前数据库中所有key的数量</div>
<div>&nbsp; &nbsp; &nbsp; info 返回redis的相关信息</div>
<div>&nbsp; &nbsp; &nbsp; config get dir/* 实时传储收到的请求</div>
<div>&nbsp; &nbsp; &nbsp; flushdb 删除当前选择数据库中的所有key</div>
<div>&nbsp; &nbsp; &nbsp; flushall 删除所有数据库中的数据库</div>]]></description>
			<link>http://meisw.wdlinux.cn//show-984-1.html</link>
			<category domain="http://meisw.wdlinux.cn//category-58-1.html">redis</category>
			<pubDate>2017-12-03 15:10</pubDate>
		</item>
	</channel>
</rss>
