EVAL script numkeys key [key …] arg [arg …]

起始版本:2.6.0

时间复杂度:取决于脚本本身的执行的时间复杂度。

EVAL简介

EVAL 和 EVALSHA 命令是从 Redis 2.6.0 版本开始的,使用内置的 Lua 解释器,可以对 Lua 脚本进行求值。

EVAL的第一个参数是一段 Lua 5.1 脚本程序。 这段Lua脚本不需要(也不应该)定义函数。它运行在 Redis 服务器中。

EVAL的第二个参数是参数的个数,后面的参数(从第三个参数),表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。

在命令的最后,那些不是键名参数的附加参数 arg [arg …] ,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。

查看全部


如果不是什么非常重要的功能,简单的单实例redis锁就可以了。

分布式锁问题

SETNX用来加锁,需要处理的第一个问题就是过期问题。

使用Redis实现分布式锁的规范算法。我们提出一种算法,叫Redlock,Java的库是redisson,地址是:

https://github.com/redisson/redisson

单Redis实例实现分布式锁的正确方法

在尝试克服上述单实例设置的限制之前,让我们先讨论一下在这种简单情况下实现分布式锁的正确做法,实际上这是一种可行的方案,尽管存在竞态,结果仍然是可接受的,另外,这里讨论的单实例加锁方法也是分布式加锁算法的基础。

查看全部


细说的话可以扯很多,但是我觉得其实没太大必要(小声BB:很多解决方案我也没太弄明白)。我个人觉得引入缓存之后,如果为了短时间的不一致性问题,选择让系统设计变得更加复杂的话,完全没必要。

下面单独对 Cache Aside Pattern(旁路缓存模式) 来聊聊。

Cache Aside Pattern 中遇到写请求是这样的:更新 DB,然后直接删除 cache 。

如果更新数据库成功,而删除缓存这一步失败的情况的话,简单说两个解决方案:

  1. 缓存失效时间变短(不推荐,治标不治本) :我们让缓存数据的过期时间变短,这样的话缓存就会从数据库中加载数据。另外,这种解决办法对于先操作缓存后操作数据库的场景不适用。
  2. 增加cache更新重试机制(常用): 如果 cache 服务当前不可用导致缓存删除失败的话,我们就隔一段时间进行重试,重试次数可以自己定。如果多次重试还是失败的话,我们可以把当前更新失败的 key 存入队列中,等缓存服务可用之后,再将 缓存中对应的 key 删除即可。

3种更新方法

1、写DB,然后删缓存

不可以反着来,反着来可能会出错。

这么做小概率出错,场景如下:小概率是因为3操作一般比2操作要快的多,DB毕竟慢。

1、请求1从DB读数据A

2、请求2写更新数据 A 到数据库并把删除cache中的A数据

3、请求1将数据A写入cache。

缺陷1:首次请求数据一定不在 cache 的问题

解决办法:可以将热点数据可以提前放入cache 中。

缺陷2:写操作比较频繁的话导致cache中的数据会被频繁被删除,这样会影响缓存命中率 。

解决办法:

查看全部


不重启更新

Redis 被设计成服务器上的长时间运行进程。针对运行实例,有许多配置选项可以通过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,可以从 AOF 切换到 RDB 的快照持久性或其他方式而不需要重启 Redis。检索 ‘CONFIG GET *’ 命令获取更多信息。 但偶尔重新启动是必须的,如为升级 Redis 程序到新的版本,或者当你需要修改某些目前 CONFIG 命令还不支持的配置参数的时候。 下列步骤通常用来避免任何形式的停机。

  • 为你的 Redis 实例配置新的从实例。为此你需要一台额外的服务器,或者你的服务器有足够的内存以便同时运行两个 Redis 实例。
  • 如果你用单一的服务器,需确保从实例用与主实例不同的端口启动,否则从实例根本不会启动成功。
  • 等待复制机制的初始同步完成(检查从实例的日志文件)。
  • 用 INFO 命令确认在主从实例中有同样数量的键值。用 redis-cli 检查从实例工作正常并响应你的命令。 使用config set slave-read-only no,允许写slave。
  • 配置你所有的客户端以便使用新的实例(即从实例)
  • 当你确认主实例不再接收到任何请求(你可以用 MONITOR 命令监视到),使用 SLAVEOF NO ONE 命令切换从实例为主实例,然后关闭原先的主实例。

磁盘持久化技术RDB/AOF

RDB 的优点:

  • RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
  • RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心,或者是Amazon S3(可能得加密)。
  • RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
  • RDB在重启保存了大数据集的实例时比AOF要快。

查看全部


安全问题

1、Redis常规安全模式

2、网络安全

3、认证的特性

4、禁用的特殊命令

5、溢出和代码安全

Redis常规安全模式

这是个特殊的例子,但是,正常情况下,对Redis的非法访问需要通过实现ACLs,验证用户输入和决定Redis实例上可以执行哪些操作这些方式来控制。

总而言之,Redis并没有最大地去优化安全方面,而是尽最大可能去优化高性能和易用性。

网络安全

记住在redis.conf文件中增加下面这一行配置就可以把Redis绑定在单个接口上。

1
bind 127.0.0.1

不禁止外部访问redis的话,将会产生非常严重的后果。比如,一个FLUSHALL操作就可以当做外部攻击来删除Redis上的所有数据。

查看全部


心跳信息,消息头有一个16384/8的char数组,记录自己的槽信息,这是个bitmap 按位操作,1表示在。

心跳信息,消息体有被选中节点的信息,只是单个节点的信息。

所以整个ping消息的大小取决于myslots的大小而不是集群总节点的大小。16384正合适。

为什么Redis集群有16384个槽

image-20201229152114309

用槽的好处,就是扩容和容错特别好,个别分片有问题,影响范围小,很方便迁移,新增节点也容易,把部分的槽数据迁走就行了。

关键问题,为什么是16384呢?

The reason is:

Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.

​ At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

节点之间,定期会交换数据信息,发送心跳的ping/pong消息,这个涉及到消息的大小。

在redis节点发送心跳包时需要把所有的槽放到这个心跳包里,以便让节点知道当前集群信息,16384=16k,在发送心跳包时使用bitmap压缩后是2k(2 * 8 (8 bit) * 1024(1k) = 2K),也就是说使用2k的空间创建了16k的槽数。

虽然使用CRC16算法最多可以分配65535(2^16-1)个槽位,65535=65k,压缩后就是8k(8 * 8 (8 bit) * 1024(1k) = 8K),也就是说需要需要8k的心跳包,作者认为这样做不太值得;并且一般情况下一个redis集群不会有超过1000个master节点,所以16k的槽位是个比较合适的选择。

查看全部


在linux上可以有500K的RPS(requests per second)

一般来说CPU不是瓶颈,内存和网络才是

1、sentinel和cluster区别和各自适用场景?

高可用 TODO husd

2、redis单线程为什么快?

1、Redis是纯内存操作,需要的时候需要我们手动持久化到硬盘中

2、Redis是单线程,从而避开了多线程中上下文频繁切换的操作。

3、Redis数据结构简单、对数据的操作也比较简单

4、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求

5、使用多路I/O复用模型,非阻塞I/O

查看全部