Redis 简介
Redis是一款以键值对形式保存在内存中的数据存储,您可以将其与应用程序集成以存储易失性数据。 必须注意它是不稳定的,因为一旦你退出Redis,你存储的所有数据都将丢失。
它通过在键(key)中存储一些值(value)来工作。
它支持多种数据类型,如strings, hashes, lists, sets, bitmaps等等。
Redis 作用
Redis通常用作缓存机制。 例如,假设你的应用程序有一个端点执行一个计算繁重的任务,并向用户返回一个大的json。 如果您对每个请求反复重复这项工作,您很可能会在您的客户端 - 服务器通信中引入瓶颈。 一个常用的解决方案是执行一次工作,然后将结果存储在Redis中。 用户下一次发出相同的请求时,应用程序只检查结果是否被缓存并返回。
当然这种模式要求你遵循一套规则:
存储的每个结果都应该是唯一命名空间的。在下面的示例中,结果应该按每个用户标识(例如)进行高速缓存,以及可以将两个请求标识为相同的任何其他附加参数。
您应该在您存储在Redis中的每个结果中强制执行TTL(time to live,生存时间)。
15分钟的TTL意味着15分钟后,结果从Redis中消失。这意味着在初始请求15分钟后,新的用户请求会再次触发服务器上的繁重计算。这取决于您的应用程序和用户需求,因此需要花点时间思考这个问题。
不要过度使用Redis。这个很重要。 Redis对于某些任务非常有用,而不是所有的任务。适当时使用适当的数据库。例如,您不应将用户凭据和首选项存储在Redis中。
如果您正在处理大量数据集,在Redis上进行查询时要非常小心。如果您的应用程序每分钟对Redis执行多次读取和/或写入操作,则Redis的一个错误查询(例如,列出当前存在的所有键)可能会导致停机,可能会破坏整个应用程序。这当然取决于应用程序的整体基础架构。
对于本博客文章剩下的部分,我将讨论Redis支持的主要数据类型以及各自的基本命令。我将使用Redis的Ruby实现(您可以在这里找到这些实现),并向您展示如何在Rails应用程序中设置Redis。几乎所有的编程语言都有Redis的端口,在这些语言之间公共的API应该非常相似,因此,通过读取官方存储库中的README文件为您偏好的开发环境配置redis应该是很简单的事情。
在Rails应用程序中设置Redis
只需将redis附加到本地Gemfile即可
gem 'redis'
然后在 config/initializer 文件夹中创建一个名为 redis.rb 的新的初始化类:
Redis.current = Redis.new(host: 'localhost', port: 6379)
您还可以传递其他选项,例如密码、特定unix套接字的路径、驱动程序和特定数据库名称,具体取决于您如何配置redis。 在官方的ruby gem上查看README文件,了解更多关于如何配置redis的信息。
常用命令
这些命令不是特定于数据类型的命令,而是任何Redis密钥本身
·删除密钥
Redis.current.del('some key')
·检查密钥是否存在
Redis.current.exists('some key')
·获取数据库中的所有密钥
Redis.current.keys
!警告 !! :禁止不惜一切代价在生产Redis服务器上运行上面的命令,因为此操作具有O(N)复杂性,其中N是您在Redis中当前拥有的密钥数量。
·在密钥中设置TTL
Redis.current.expire('some key', 5000)
第二个参数是到期时间,以毫秒为单位。这意味着密钥'some key‘将在5秒内过期。
·重命名一个密钥
Redis.current.rename('some key', 'new key')
如果您不知道或不记得某个键当前拥有哪种数据结构,则可以要求redis通知您:
Redis.current.type('key') => 'String', 'Set', 'Hash', ...
如果您确实想要扫描Redis中的所有密钥(例如,要检查名称中是否存在特定模式的密钥),则正确的方法是使用scan命令。
举个例子,假设我们当前的Redis数据库拥有10亿个密钥,并且您想知道是否存在具有名称模式some:cache:key的任一密钥。再强调一下,您不要执行Redis.current.keys命令并遍历返回的集合来查找它。这样你不但可能会杀死你的应用程序内存,而且你也可能会杀死Redis。
scan命令允许您使用游标反复查找数据库中的键。您为它提供了一个初始光标,redis将扫描以下N个键(可配置),然后返回您在下一次调用中应使用的下一个光标(以及扫描的键)。
为正确使用此命令,每当redis返回0作为下一个游标时,应该停止扫描。这意味着没有更多的键可以扫描。在上面的示例中,要查找包含模式some:cache:key 的键,我们将按以下方式使用scan:
Redis.current.scan(0, match: '*some:cache:key*')
模式之前和之后的星号意味着'我不关心这个特定模式之前或之后的任何内容,所以密钥random:some:cache:key:random 将匹配。
第一次调用将返回结果,例如迭代器1000或者任何匹配该模式的键值。鉴于迭代器不是0,我们可以继续:
Redis.current.scan(1000, match: '*some:cache:key*')
这个调用会返回迭代器10,所以我们继续:
Redis.current.scan(10, match: '*some:cache:key*')
这个调用会返回迭代器0,所以我们知道没有更多的键匹配这个模式。不言而喻,您应该保存每个扫描命令的结果,将匹配的键的组成一个列表。
Strings / Integers(字符串/整数)
在本节中,我们将学习有关从redis存储和检索字符串和整数值的基本操作。
·将新的字符串值存储在密钥中
Redis.current.set('mykey', 'myvalue')
·检索密钥mykey的值
Redis.current.get('mykey') => 'myvalue'
·在一个键中设置一个新的字符串值,保证键值之前不存在
Redis.current.setnx('mykey', 10) => false(因为'mykey'键已经存在)
Redis.current.setnx('another key', 10) => 'OK'
Hashes(哈希)
Redis中的hash是一个数据结构,它可以包含几个键 - 值对(就像Ruby中的hash)
·在哈希myhash中创建一个新的键/值对:
Redis.current.hset('myhash', 'my hash field', 10)
·在myhash中检索字段 my hash field的值:
Redis.current.hget('myhash', 'my hash field')
·还有一种方法可以在单个命令中创建包含多个字段的哈希:
Redis.current.hmset('myhash', 'field 1', 'value field 1', 'field 2', 'value field 2', 'field 3', 'value field 3')
这里我用字符串来展示示例,但是当然你也可以存储整数,甚至是json转储,例如:
Redis.current.hmset('myhash', 'field 3', '{\" key \": \" value \"}')
同样,您也可以通过单个命令从多个字段中检索值
Redis.current.hmget('myhash', 'field 2', 'field 3') => {'field 2' => 'value field 2', 'field 3' => 'value field 3'}
·从散列中删除一个或多个字段
Redis.current.hdel('myhash', 'field 2', 'field 3')
·检索某个完整哈希
Redis.current.hgetall('myhash') => {'field 1' => 'value field 1', 'field 2' => 'value field 2', 'field 3' => 'value field 3'}
Lists(列表)
·在列表中添加一个新元素(添加到列表的开头)
Redis.current.lpush("mylist", 10)
·追加一个新元素到列表中(添加到列表的末尾)
Redis.current.rpush("mylist", JSON.dump({ some_hash_key: 2}))
·从列表中删除元素
Redis.current.lrem("mylist", 1, 10)
lrem方法接受三个参数。第一个参数是保存列表的键的名称,第三个参数是我们想要从列表中删除的元素,第二个参数是一个整数且符合以下情况:
·当为0时,它将删除列表中与我们要移除的元素相等的所有元素。例如,如果我们在列表中调用Redis.current.lrem(“mylist”,0,10)的值为10的几个元素将删除列表中值为10的所有元素
·当为正数时,将移除与我们想要移除的元素相匹配的第一个元素,从列表头到尾部
·当为负数时,将移除与我们想要移除的元素匹配的第一个元素,从列表的尾部开始到头部。例如,如果要删除列表中给定元素的第一个或最后一个元素,最后两个选项很有用
·获取列表的元素
Redis.current.lrange("mylist", 0, -1)
这个方法的第二个和第三个参数指定了我们想要的元素的范围。当使用0和-1时,这意味着我们需要从开始到结束的所有元素。如果我们只想要前两个元素,我们必须编写Redis.current.lrange("mylist", 0, 1)等等。
如果您不知道列表的当前大小:
Redis.current.llen("mylist")
Sets(集合)
如果想要保持具有唯一元素的数据结构,集合很有用。
·向集合添加新元素
Redis.current.sadd("myset", "myelement")
请注意,如果元素“myelement”已经存在于集合“myset”中,它将被忽略,因此不会被添加
·从集合中删除元素
Redis.current.srem("myset", "myelement")
·获取集合当前的所有成员
Redis.current.smembers("myset")
·检查一个元素是否已经在一个集合中
Redis.current.sismember("myset", "myelement")
结束语
这里给出的命令列表只是一个快速的“cheasheet”,可以用来快速查找Redis最常见的用例。有关完整命令的列表,请查看官方的redis文档。
最后,请注意你正在如何使用redis。如果redis与运行应用程序的机器不在同一台机器上,请考虑每个redis调用都是网络请求。另外,要非常小心使用从列表中返回所有内容的命令,例如smembers,lrange,hgetall等。如果您的应用程序非常大,您可能不仅会泛滥您的应用程序内存,还可能阻塞redis一段时间。注意始终使用基于迭代的搜索,如scan。
谢谢阅读!
本文翻译自https://dev.to/luispcosta/redis---an-introduction-3lof,作者将其翻译为中文并排版,方便国内读者学习使用。
网友评论