存档

‘Redis’ 分类的存档

Redis简明入门教程

2020年7月7日 评论已被关闭

【第一节】
Redis是键值(key-value)存储数据库家族中的一员。
何为键值存储?其本质是具备将数据(value)存储到一个键(key)中的能力。这些数据后续可通过并只能通过之前那个key来获取。
通常,Redis被称为数据结构服务器。这是因为,从表面来看,Redis可以以key-value这样简单的形式来存储或获取数据。
但实际上,存储在Redis中的value可以包含复杂的数据结构,比如:字符串、链表、哈希表、集合、有序集合以及适用于概率学的数据结构hyperloglog。

先举个例子。
我们使用set命令将“fido”这个value存储到“server:name”这个key中。
SET server:name “fido”

Redis可以“持久”(依赖于数据过期和持久化策略)存储我们的数据。

这样,我们后续就可以询问Redis:保存在server:name键中的值是什么?
Redis会告诉我们:fido。这通过以下命令实现:
GET server:name
=> “fido”

你可以直接在redis命令行工具redis-cli中输入本文中的命令,=> 代表命令执行后的的输出。

Redis提供用于检测一个key是否存在的命令:
EXISTS server:name
=> 1
EXISTS server:blabla
=> 0
若key存在,返回1;不存在,返回0.

【第二节】
其他基本命令包括:del(删除一个key及存储其中的value)、incr(增加存储在key中数字的数值)。
SET connections 10
INCR connections
=> 11
INCR connections
=> 12
DEL connections
INCR connections
=> 1

incr支持设置每次操作的增量,默认为1。
INCRBY connections 100
=> 101

和incr对应的是decr,用于减少数值型value的值。
DECR connections
=> 100
DECRBY connections 10
=> 90
incr和decr非常适合计数器场景。

【第三节】
也许你会问:incr和decr这样的操作很简单啊,可以通过几行代码就能实现。比如:
x = GET count
x = x + 1
SET count x

确实。但这只适用于单客户端访问一个key的场景。想想一下,如果有两个客户端同时访问这个key呢?
A读取计数器的值为10,同时B也读到了10.
A将计数器的值加1后,将其写回数据库,此时计数器值为11;
B也将计数器的值加1,并将其写回数据库。此时计数器的值仍为11,而不是12.

显然,这种场景之下的计数器并没有起到正确的计数作用。

这是因为上述两个客户端对key的增加操作不是原子性的,需要3步才能完成。
Redis的incr很好的避免了这个问题,它是一个原子操作,一步搞定。

Redis中所有通过单条命令实现的操作都是原子的,包括那些适用于复杂数据结构上的操作。

因此使用Redis命令修改键值时,我们不需要考虑并发访问的问题。

【第四节】
我们向Redis存储key时,可以设置其存活时间,即这个key只在Redis中保留一段时间,过期后就不可再被访问。
这在Redis中通过expire和ttl命令实现。这两个命令的时间单位是秒。还有两个相似的命令,其时间单位是毫秒:pexpire和pttl。
SET resource:lock “Redis Demo”
EXPIRE resource:lock 120

上边,expire将resource:lock的过期时长设为120秒。可以使用ttl查看某个key的剩余存活时长。
TTL resource:lock
=> 113
//113秒之后
TTL resource:lock
=> -2

-2表示这个key不复存在。-1表示表示key永不过期。
注意,若对一个key重新执行set操作,其过期时长将被重置。
SET resource:lock “Redis Demo 1”
EXPIRE resource:lock 120
TTL resource:lock
=> 119

SET resource:lock “Redis Demo 2”
TTL resource:lock
=> -1

set接受额外的参数用于在设置key的值的同时直接设置其过期时长,这“两个”操作是一个原子操作。
SET resource:lock “Redis Demo 3” EX 5
TTL resource:lock
=> 5

Redis也支持取消一个key的过期设置,使其永久存在。这通过persist命令实现。
SET resource:lock “Redis Demo 3” EX 5
PERSIST resource:lock
TTL resource:lock
=> -1

【第五节】
我们开始时已经提到,Redis支持一些复杂的数据结构。现在做下介绍。
第一个就是list。list是一系列的有序值。与list相关的一些重要命令包括:rpush、lpush、llen、lrange、lpop、rpop等。
Redis中的list是可以随手就用的,只要表示list的key不是其他类型。什么意思?
在Redis中,你不需要在使用复杂数据结构之前,先创建一个key然后再为其赋值。你可以直接使用命令来操作这些结构,如果指定的key不存在,Redis会自动创建这个key。
相应的,如果一个key在经历一些操作之后变为空值,这个key也会自动从key空间中被删除。

rpush:向list尾部追加一个元素。
RPUSH friends “Alice”
RPUSH friends “Bob”

lpush:在list头部插入一个元素。
LPUSH friends “Sam”

lrange:获取list元素子集。它的第一个参数是起始元素的索引,第二个参数是结束元素的索引。
第二个参数是-1时,表示一直到list的最后一个(倒数第一个)元素,-2表示倒数第二个元素,以此类推。
LRANGE friends 0 -1
=> 1) “Sam”, 2) “Alice”, 3) “Bob”

LRANGE friends 0 1
=> 1) “Sam”, 2) “Alice”

LRANGE friends 1 2
=> 1) “Alice”, 2) “Bob”

除了添加和获取基于索引的子集之外,list还可以从开头或结尾删除并获取一个元素,即pop操作。
lpop:删除并返回list的第一个元素。
LPOP friends
=> “Sam”

rpop:删除并返回list的最后一个元素。
RPOP friends
=> “Bob”

llen:获取list元素个数。
LLEN friends
=> 1

rpush和lpush参数个数是可变的,我们可以在一条命令中指定多个参数。
RPUSH friends 1 2 3
=> 6
这里,6表示执行push之后list的长度。

【第六节】
接下来,我们介绍set。set和list类似,区别在于,set中的元素是无序的,并且是唯一的。
这两种数据结构都很重要。list可快速访问头部或尾部的元素,set可快速测试元素是否存在。

和set相关的一些重要命令包括:sadd、srem、sismember、smembers和sunion等。

sadd:向set中添加元素,支持可变参数,能同时添加多个元素。
SADD superpowers “flight”
SADD superpowers “x-ray vision” “reflexes”

srem:从set中删除元素,返回值1或0表示元素是否存在于set中。
SREM superpowers “reflexes”
=> 1
SREM superpowers “making pizza”
=> 0

sismember:测试元素是否存在于set中,返回1表示存在,0表示不存在。
SISMEMBER superpowers “flight”
=> 1
SISMEMBER superpowers “reflexes”
=> 0

sunion:计算两个或多个set的并集,返回所有并集中的元素。
SADD birdpowers “pecking”
SADD birdpowers “flight”
SUNION superpowers birdpowers
=> 1) “pecking”, 2) “x-ray vision”, 3) “flight”

sadd的执行结果和srem的结果一样重要。0表明要添加的元素已存在,1表示添加成功。
SADD superpowers “flight”
=> 0
SADD superpowers “invisibility”
=> 1

set也有个和list类似的pop命令,用于从其中删除并返回若干元素。由于set是无序的,被删除并返回的元素也是随机的。
SADD letters a b c d e f
=> 6
SPOP letters 2
=> 1) “c” 2) “a”

spop在key之后的参数为要删除的元素的个数。
set专门有一个命令用于随机返回其中的若干元素,只是返回,不删除。这个命令是srandmember。用法和spop类似,可自行试验。

【第七节】
set是很好用的数据结构,但因为其中的元素是无序的,对某些场景就不太合适了。
Redis 1.2开始引入了有序set:sorted set。
sorted set和set有些相似,区别在于其中的每个元素都关联了个分数(score)。这个分数用于对sorted set中的元素进行排序。

ZADD hackers 1940 “Alan Kay”
ZADD hackers 1906 “Grace Hopper”
ZADD hackers 1953 “Richard Stallman”
ZADD hackers 1965 “Yukihiro Matsumoto”
ZADD hackers 1916 “Claude Shannon”
ZADD hackers 1969 “Linus Torvalds”
ZADD hackers 1957 “Sophie Wilson”
ZADD hackers 1912 “Alan Turing”
这个例子中,集合元素的score是生日年份,元素的值为人名。

我们可以使用zrange获取sorted set中某个范围段的元素。
ZRANGE hackers 2 4
=> 1) “Claude Shannon”, 2) “Alan Kay”, 3) “Richard Stallman”

【第八节】
字符串、list、set和sorted set这些结构已经能处理很多工作了,但Redis还提供了一种数据结构:hash。
hash是字符串字段到字符串值的映射,所以适合表示对象结构。

比如,一个User包含name、surname、age等字段。我们可以用hash存储User的信息。
HSET user:1000 name “John Smith”
HSET user:1000 email “john.smith@example.com”
HSET user:1000 password “s3cret”
我们使用用户标识user:1000作为key,将各个字段依次设置到key中。

可以一次同时设置多个字段值。
HMSET user:1001 name “Mary Jones” password “hidden” email “mjones@example.com”

使用hgetall来获取所有字段。
HGETALL user:1000

也可以每次只获取一个字段的值。
HGET user:1001 name => “Mary Jones”

Redis支持对hash中的某个字段进行incr操作。
HSET user:1000 visits 10
HINCRBY user:1000 visits 1
=> 11
HINCRBY user:1000 visits 10
=> 21

HDEL user:1000 visits
HINCRBY user:1000 visits 1
=> 1

 

【本文译自Redis在线演示教程

分类: Redis 标签: ,

基于腾讯云CVM自建高可用Redis实践【转】

2020年6月11日 评论已被关闭

在企业实际生产环境中为了能够给业务上层应用提供高可靠、低延迟、低数据损失的Redis缓存服务,本文通过对目前主流的几种redis高可用方案进行对比分析,并基于腾讯云CVM和HAVIP等基础产品进行搭建、配置、测试、总结,供大家参考。

分类: Redis 标签:

如何将redis一个list中的数据全部移动到另一个list

2018年7月21日 没有评论

有时候我们需要将一个list中的数据全部移动到另一个list中,而Redis目前没有直接提供这样的命令。

怎么办?

很简单,逐一pop出list a中的数据,再push到list b中。当然pop+push可以通过rpoplpush来实现。所以对源list做个遍历就行了。

#!/bin/sh

host=”127.0.0.1″
port=”6379″
passwd=”foobar”
srcList=”listSrc”
dstList=”listDest”

while[ 1 == 1 ];do
ret=$(redis-cli -h $host -p $port -a $passwd rpoplpush $srcList $dstList)
[ -z $ret ] && return
done

分类: Redis 标签:

非root用户启动和运行redis

2018年5月30日 没有评论

    redis之前爆出过一个漏洞,攻击者可藉此漏洞获取系统root权限。在之前的文章里,我们了解了如何增强redis的安全性。我们还可以使用非root用户来运行redis,进而进一步提升系统安全性。

  1. 以root身份正常安装redis
  2. 切换非root用户登入系统,比如test
  3. 拷贝redis默认配置文件到test的根目录(或其他test有访问权限的目录):

    sudo copy /etc/redis/6379.conf /home/test/

  4. 修改test下配置文件的属主:

    sudo chown test.test /home/test/6379.conf

  5. 修改配置文件中redis运行使用到的相关文件和目录的路径,可通过grep 6379 /home/test/6379.conf查找这些文件和目录,将这些路径修改到test用户根目录下

    pidfile /home/test/run/redis_6379.pid
    logfile /home/test/log/redis_6379.log
    dir /home/test/lib/redis/6379

  6. 创建这些文件和目录

    mkdir -p /home/test/run/ /home/test/log  /home/test/lib/redis/6379

  7. 启动redis

    /usr/local/bin/redis-server /home/test/6379.conf

分类: Redis, 安全, 开发 标签:

使用openresty+redis轻松实现网站访问统计

2017年2月16日 没有评论

网站的受访统计是网站运营和优化的一个重要参考数据,对于并发量较大的网站,我们可以通过nginx+redis的架构来简单实现页面受访统计。这主要得益于nginx的高并发性能和redis快速存取内存数据。实际应用中,我们可以使用openresty来快速搭建统计系统。

openresty集合了lua和lua-redis访问库,可以通过编写nginx.conf配置文件实现对redis数据库的存取。简单且高效。

  1. 安装和配置openresty及redis
  2. 修改nginx.conf,示例:

    http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    server {
    listen 8088;
    server_name www.test.com;

    location /get_pv {
    set $id_param $args;
    content_by_lua ‘
    local redis_mod = require “resty.redis”
    local redis_db= redis_mod:new()
    redis_db:set_timeout(1000) — 1 second

    local ok, err = redis_db:connect(“127.0.0.1”, 6379)
    if not ok then
    ngx.log(ngx.ERR, “failed to connect to redis: “, err)
    return ngx.exit(500)
    end

    local id = string.sub(ngx.var.id_param, 4)
    local pv, err = redis_db:get(id)
    if not pv then
    redis_db:close()
    ngx.log(ngx.ERR, “failed to get redis key: “, id, err)
    return ngx.exit(500)
    end

    if pv == ngx.null then
    redis_db:close()
    ngx.log(ngx.ERR, “no pv found for “, id)
    return ngx.exit(400)
    end

    redis_db:close()

    ngx.header.content_type = “text/plain”;
    ngx.say(pv)
    ‘;
    }
    }

    server {
    listen 9099;
    server_name www.test.com;

    location /set_pv {
    set $id_param $args;
    content_by_lua ‘
    local redis_mod = require “resty.redis”
    local redis_db= redis_mod:new()
    redis_db:set_timeout(1000) — 1 second

    local ok, err = redis_db:connect(“127.0.0.1”, 6379)
    if not ok then
    ngx.log(ngx.ERR, “failed to connect to redis: “, err)
    return ngx.exit(500)
    end

    local id = string.sub(ngx.var.id_param, 4)
    local pv = redis_db:incr(id)
    if not pv then
    redis_db:close()
    ngx.log(ngx.ERR, “failed to incr redis key: “, id, err)
    return ngx.exit(500)
    end

    redis_db:close()

    ngx.header.content_type = “text/plain”;
    ngx.say(pv)
    ‘;
    }
    }
    }

  3. 在网站页面中部署统计代码

<iframe frameborder=”0″ scrolling=”no” width=”0″  height=”0″ style=”display:none;” src=”http://www.test.com:9099/set_pv?id=page_411“></iframe>

分类: Lua, Redis, 开发 标签: , , ,

Redis低版本无法向前兼容高版本RDB文件

2016年9月26日 没有评论

今天做了一个操作导致Redis无法启动。

在部署某一程序的过程中,先是单独安装了3.2.3版本的redis,安装完成后ps一下,redis已经启动。然后又使用安装包部署程序,安装包中包含一个2.8.13版本的redis,直接把之前装的3.2.3的redis给覆盖掉了。程序安装完成后发现redis进程没了,而且通过service redis_6379 restart无法启动。

怎么回事?查看/var/log/redis_6379.log发现如下错误:

[31934] 26 Sep 11:31:47.087 # Can’t handle RDB format version 7
[31934] 26 Sep 11:31:47.087 # Fatal error loading the DB: Invalid argument. Exiting.

哦,当前版本的redis无法处理version=7的RDB格式,这才明白是兼容性问题,但这种“向前兼容”一般很难做到的。

解决办法:删除rdb文件/var/lib/redis/6379/dump.rdb,重启redis就行了。

2017.11.08:今天在redis官网上看到一篇文章,是介绍redis rdb文件版本历史的,参这里。详细介绍了各版本的演进历史,并说明了高版本rdb文件回退到低版本的方法,有需要的朋友可以了解一下。

分类: Redis, 运维 标签: ,