Redis 更深入一点

Redis 更深入一点 问的更深一点

Redis 管道(Pipelining)

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @Post("/test_pipelie")
*/
public function test_pipelie()
{
$pipe = $this->redis->multi(RedisTool::PIPELINE);

for ($i = 0; $i < 100; $i++) {
$pipe->set("key::$i", str_pad($i, 4, '0', 0));
$pipe->get("key::$i");
}

$res = $pipe->exec();
print_r($res);
}

Redis 内存优化

Redis2.2版本及以后,存储集合数据的时候会采用内存压缩技术,以使用更少的内存存储更多的数据。如Hashes,Lists,Sets和Sorted Sets,当这些集合中的所有数都小于一个给定的元素,并且集合中元素数量小于某个值时,存储的数据会被以一种非常节省内存的方式进行编码,使用这种编码理论上至少会节省10倍以上内存(平均节省5倍以上内存)。并且这种编码技术对用户和redis api透明。因为使用这种编码是用CPU换内存,所以我们提供了更改阈值的方法,只需在redis.conf里面进行修改即可.

1
2
3
4
5
6
7
hash-max-zipmap-entries 64 (2.6以上使用hash-max-ziplist-entries)
hash-max-zipmap-value 512 (2.6以上使用hash-max-ziplist-value)
list-max-ziplist-entries 512
list-max-ziplist-value 64
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
set-max-intset-entries 512
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @Post("/test_memory")
* $redis->config("GET", "*max-*-entries*");
* $redis->config("SET", "dir", "/var/run/redis/dumps/");
*/
public function test_memory()
{
// hash-max-zipmap-entries 256
$this->redis->config('set', 'hash-max-zipmap-entries',256);

// 相应的最大键值长度设置:
// hash-max-zipmap-value 1024
$this->redis->config('set', 'hash-max-zipmap-value',1024);
}

Redis 事务

MULTIEXECDISCARDWATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 /**
* @Post("/test_transaction")
*/
public function test_transaction()
{
$this->redis->watch('number');

$this->redis->multi();
$this->redis->set('favorite_fruit', 'cherry');
$this->redis->incrBy('number', 3);
$this->redis->get('favorite_fruit');
$this->redis->ping();
// $this->redis->discard(); // 取消事务
dd($this->redis->exec());
}

/* array:4 [
0 => true
1 => 3
2 => "cherry"
3 => "+PONG"
] */
  • WATCH: 用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
  • UNATCH: 用于取消 WATCH 命令对所有 key 的监视。
  • MULTI: 用于标记一个事务块的开始。
  • EXEC: 用于执行所有事务块内的命令。
  • DISCARD: 用于取消事务放弃执行事务块内的所有命令。

为什么 Redis 不支持回 (roll back) ?

如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令” 这种做法可能会让你觉得有点奇怪。

以下是这种做法的优点:

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。

  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

原文地址: 为什么 Redis 不支持回滚(roll back)

Redis 分布式锁

分布式锁在很多场景中是非常有用的原语, 不同的进程必须以独占资源的方式实现资源共享就是一个典型的例子。
这个页面试图提供一个使用Redis实现分布式锁的规范算法。我们提出一种算法,叫Redlock
Redlock-PHP

  • 算法只需具备3个特性就可以实现一个最低保障的分布式锁。
      1. 安全属性 (Safety property): 独享(相互排斥)。在任意一个时刻,只有一个客户端持有锁
      1. 活性A(Liveness property A): 无死锁。即便持有锁的客户端崩溃(crashed)或者网络被分裂(gets partitioned),锁仍然可以被获取。
      1. 活性B(Liveness property B): 容错。 只要大部分Redis节点都活着,客户端就可以获取和释放锁.

Redis 发布/订阅(Pub/Sub)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Redis-发布订阅
* @Post("/test_pub_sub")
*/
public function test_pub_sub()
{
// 将信息 message 发送到指定的频道 channel 。
$this->redis->publish('channel', 'message');

// 订阅给定的一个或多个频道的信息。
$this->redis->subscribe(['channel'], 'callback');

// 订阅一个或多个符合给定模式的频道
$this->redis->psubscribe(['msg*'], 'callback');

// PUBSUB 是一个查看订阅与发布系统状态的内省命令, 它由数个不同格式的子命令组成, 以下将分别对这些子命令进行介绍。
// 列出当前的活跃频道。
$this->redis->pubsub('keyword', 'argument');
}
  • 发布
1
2
3
4
5
6
7
8
9
10
/**
* 发布
* @Post("/test_publish")
*/
public function test_publish()
{
$this->redis->publish('msg', '来自MSG频道的推送');
echo "MSG频道消息推送成功 \n";
$this->redis->close();
}
  • 订阅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 订阅
* @Post("/test_subscribe")
*/
public function test_subscribe()
{
// ini_set('default_socket_timeout', -1);

echo "订阅MSG频道, 等待消息推送...\n";

$callback = function ($msg) {
echo $msg;
};

$this->redis->subscribe(['msg'], $callback);
}

Redis 主从复制

在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。

这个系统的运行依靠三个主要的机制:

  • 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
  • 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
  • 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

Redis 大量写入数据

Redis实例需要装载大量用户在短时间内产生的数据,数以百万计的keys需要被快速的创建?

  • 使用Luke协议

使用正常模式的Redis 客户端执行大量数据插入不是一个好主意:因为一个个的插入会有大量的时间浪费在每一个命令往返时间上。使用管道(pipelining)是一种可行的办法,但是在大量插入数据的同时又需要执行其他新命令时,这时读取数据的同时需要确保请可能快的的写入数据。

只有一小部分的客户端支持非阻塞输入/输出(non-blocking I/O),并且并不是所有客户端能以最大限度的提高吞吐量的高效的方式来分析答复。

  • 生成Redis协议

它会非常简单的生成和解析Redis协议,Redis协议文档请参考Redis协议说明。 但是为了生成大量数据插入的目标,你需要了解每一个细节协议,每个命令会用如下方式表示:

1
2
3
4
5
6
*<args><cr><lf>
$<len><cr><lf>
<arg0><cr><lf>
<arg1><cr><lf>
...
<argN><cr><lf>

这里的是”\r”(或者是ASCII的13)、是”\n”(或者是ASCII的10)。

Redis 集群

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2022 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :