Redi/S 是用 Swift 编程语言实现的 Redis 服务器。它基于 Apple 的 SwiftNIO 框架。
Redis 是什么? 请查看其主页,但它是一个易于使用且非常流行的键值存储,具有 PubSub 功能。
它并非旨在取代基于 C 的 Redis 服务器,但目标是使其功能完备且性能良好。
用例
Redi/S 支持很多命令,包括 PubSub 和监控。
Redi/S 不 支持很多命令,包括事务或 HyperLogLogs。
有一个 支持的命令列表。
欢迎贡献! 很多缺失的功能很容易添加!
性能有所不同,例如,列表是使用数组实现的(因此 RPUSH 还可以,LPUSH 非常慢)。但仅看简单的 GET/SET,它与高度优化的 C 实现非常接近。
Redi/S (M1 Mac Mini 上的 1 个 NIO 线程)
helge@M1ni ~ $ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q
WARNING: Could not fetch server CONFIG
SET: 163345.31 requests per second, p50=0.255 msec
GET: 167336.02 requests per second, p50=0.239 msec
INCR: 158780.56 requests per second, p50=0.239 msec
RPUSH: 157480.31 requests per second, p50=0.271 msec
请注意,更多线程最终会变得更糟。 不是很确定为什么。
Redi/S (MacPro 3,7 GHz 四核 Intel Xeon E5 上的 2 个 NIO 线程)
helge@ZeaPro ~ $ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q
SET: 48003.07 requests per second
GET: 48459.00 requests per second
INCR: 43890.45 requests per second
RPUSH: 46087.20 requests per second
Redis 4.0.8(相同的 MacPro 3,7 GHz 四核 Intel Xeon E5)
helge@ZeaPro ~ $ redis-benchmark -t SET,GET,RPUSH,INCR -n 500000 -q
SET: 54884.74 requests per second
GET: 54442.51 requests per second
INCR: 54692.62 requests per second
RPUSH: 54013.18 requests per second
RaspberryPi 3B+ 上的 Redi/S
$ redis-benchmark -h zpi3b.local -p 1337 -t SET,GET,RPUSH,INCR -n 50000 -q
SET: 4119.29 requests per second
GET: 5056.12 requests per second
INCR: 3882.59 requests per second
RPUSH: 3872.07 requests per second
有 性能说明,查看 Redi/S 的具体 NIO 实现。
持久性效率非常低,数据库只是通过 Codable 以 JSON 形式转储。 很容易修复。
$ swift build -c release
$ .build/release/redi-s
2383:M 11 Apr 17:04:16.296 # sSZSsSZSsSZSs Redi/S is starting sSZSsSZSsSZSs
2383:M 11 Apr 17:04:16.302 # Redi/S bits=64, pid=2383, just started
2383:M 11 Apr 17:04:16.303 # Configuration loaded
____ _ _ ______
| _ \ ___ __| (_) / / ___| Redi/S 64 bit
| |_) / _ \/ _` | | / /\___ \
| _ < __/ (_| | |/ / ___) | Port: 1337
|_| \_\___|\__,_|_/_/ |____/ PID: 2383
2383:M 11 Apr 17:04:16.304 # Server initialized
2383:M 11 Apr 17:04:16.305 * Ready to accept connections
有一些效率低下的地方,最糟糕的是持久存储。 但总的来说,这似乎工作正常。
该实现已经增长了一些,可以使用一些重构,特别是数据库转储部分。
您想玩玩这个,但以前从未使用过 Redis? 好的,这是一个关于你可以用它做什么的小教程。
首先确保服务器在一个 shell 中运行
$ swift build -c release
$ .build/release/redi-s
83904:M 12 Apr 16:33:15.159 # sSZSsSZSsSZSs Redi/S is starting sSZSsSZSsSZSs
83904:M 12 Apr 16:33:15.169 # Redi/S bits=64, pid=83904, just started
83904:M 12 Apr 16:33:15.170 # Configuration loaded
____ _ _ ______
| _ \ ___ __| (_) / / ___| Redi/S 64 bit
| |_) / _ \/ _` | | / /\___ \
| _ < __/ (_| | |/ / ___) | Port: 1337
|_| \_\___|\__,_|_/_/ |____/ PID: 83904
83904:M 12 Apr 16:33:15.176 # Server initialized
83904:M 12 Apr 16:33:15.178 * Ready to accept connections
请注意服务器如何显示:“Port 1337”。 这是服务器正在运行的端口。
您可以直接连接到服务器并发出 Redis 命令(服务器然后在 telnet 模式
下运行连接,这与常规 RESP 协议不同)
$ nc localhost 1337
KEYS *
*0
SET theanswer 42
+OK
GET theanswer
$2
42
Redis 是一个键/值存储。 也就是说,它的作用类似于一个大的 Dictionary,可以从多个进程修改。 上面我们列出了可用的 KEYS
,然后我们将键 theanswer
设置为值 42,并检索它。 (Redis 提供了 出色的文档,其中介绍了可用的命令,Redi/S 实现了其中的许多命令,但并非全部)。
Redis 提供了一个名为 redis-cli
的工具,它是访问服务器的更方便的方式。 在 macOS 上,您可以使用 brew install redis
安装它(这也为您提供了真正的服务器),在 Ubuntu 上,您可以通过 sudo apt-get install redis-tools
获取它。
我们在上面的 telnet
中所做的同样的事情
$ redis-cli -p 1337
127.0.0.1:1337> KEYS *
1) "theanswer"
127.0.0.1:1337> SET theanswer 42
OK
127.0.0.1:1337> GET theanswer
"42"
Redis 特别适用于 HTTP 会话存储和缓存。 设置键时,您可以设置“过期时间”(以秒、毫秒或 Unix 时间戳为单位)
127.0.0.1:1337> EXPIRE theanswer 10
(integer) 1
127.0.0.1:1337> TTL theanswer
(integer) 6
127.0.0.1:1337> GET theanswer
"42"
127.0.0.1:1337> TTL theanswer
(integer) -2
127.0.0.1:1337> GET theanswer
(nil)
我们在这里使用“字符串”。 在 Redis 中,“字符串”实际上是“Data”对象,即字节的二进制数组(即使对于字节也是如此!)。 例如,在 Web 应用程序中,您可以使用您生成的“会话 ID”,将您的会话序列化为 Data 对象,然后像 SET session-id <session> TTL 600
一样存储它。
但是我们如何在分布式环境中生成键(例如会话 ID)? 像往常一样,有很多方法可以做到这一点。 例如,您可以使用 Redis 整数键,该键提供原子递增和递减操作
127.0.0.1:1337> SET idsequence 0
OK
127.0.0.1:1337> INCR idsequence
(integer) 1
127.0.0.1:1337> INCR idsequence
(integer) 2
或者,如果您在客户端生成键,则可以使用 SETNX 验证它们是否唯一。 例如
127.0.0.1:1337> SETNX mykey 10
(integer) 1
另一个客户端会得到
127.0.0.1:1337> SETNX mykey 10
(integer) 0
Redis 不仅可以存储字符串(读取:Data)值,还可以存储列表、集合和哈希(字典)。 以及其他一些数据类型:数据类型简介。
127.0.0.1:1337> RPUSH chatchannel "Hi guys!"
(integer) 1
127.0.0.1:1337> RPUSH chatchannel "How is it going?"
(integer) 2
127.0.0.1:1337> LLEN chatchannel
(integer) 2
127.0.0.1:1337> LRANGE chatchannel 0 -1
1) "Hi guys!"
2) "How is it going?"
127.0.0.1:1337> RPOP chatchannel
"How is it going?"
127.0.0.1:1337> RPOP chatchannel
"Hi guys!"
127.0.0.1:1337> RPOP chatchannel
(nil)
假设您要调试 Redis 服务器上发生的事情。 您可以通过连接一个新的客户端并将它置于“监控”模式来做到这一点。 Redis 服务器会将它接收到的所有命令回显到该监视器
$ redis-cli -p 1337
127.0.0.1:1337> MONITOR
OK
其他一些客户端
127.0.0.1:1337> hmset user:1000 username antirez birthyear 1976 verified 1
OK
127.0.0.1:1337> hmget user:1000 username verified
1) "antirez"
2) "1"
监视器将打印
1523545069.071390 [0 127.0.0.1:60904] "hmset" "user:1000" "username" "antirez" "birthyear" "1976" "verified" "1"
1523545087.016070 [0 127.0.0.1:60904] "hmget" "user:1000" "username" "verified"
Redis 包括一个简单的发布/订阅服务器。 任意数量的客户端可以订阅任意数量的频道。 其他客户端然后可以将“消息”推送到频道,并且所有订阅的客户端都将收到它们。
一个客户端
127.0.0.1:1337> PSUBSCRIBE thermostats*
Reading messages... (press Ctrl-C to quit)
1) psubscribe
2) "thermostats*"
3) (integer) 1
另一个客户端(回复包含消费者数量)
127.0.0.1:1337> PUBLISH thermostats:kitchen "temperature set to 42℃"
(integer) 1
订阅的客户端将获得
1) message
2) "thermostats:kitchen"
3) "temperatur set to 4242℃"
注意:PubSub 与键值存储分离。 您无法使用它来监视键!(有用于生产者/消费者场景的阻塞列表操作,但 Redi/S 尚不支持这些操作)
Redis 工具还包括一个名为 redis-benchmark
的工具,它类似于 apache-bench
或 wrk
,可用于测量服务器性能。
例如,用 50 万个 SET、GET、RPUSH 和 INCR 请求分别进行服务器练习
$ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q
SET: 43192.81 requests per second
GET: 46253.47 requests per second
INCR: 38952.95 requests per second
RPUSH: 39305.09 requests per second
由 ZeeZide 带给您。 我们喜欢 反馈、GitHub 星星、酷炫的 合同工作,大概您能想到的任何形式的赞美。
在 swift-server Slack 上有一个 #swift-nio
频道。