我正在开发一个 Web 应用程序(Nginx+PHP7.3),它将使用 Redis 数据库来存储一些数据(主要是计算事物),我必须决定如何存储数据。在我的情况下,重要的是速度和性能,并且还要保持每秒低操作数,以便能够处理与 Web 应用程序的许多并发连接。
选项 1:将 JSON 数据存储在单个键上
为了保存数据,我将使用单个 SET 操作,即:
$redis->set("MyKey-UserID", '{"clicks":123,"downloads":1234,"views":123}');
Run Code Online (Sandbox Code Playgroud)
然后更新数据我会使用两个操作(GET + SET),即:
$array = json_decode($redis->get("MyKey-UserID"), true);
$array['clicks']++;
$array['downloads']++;
$array['views']++;
$redis->set("MyKey-UserID", json_encode($array));
Run Code Online (Sandbox Code Playgroud)
选项 2:具有单个值的多个键
为了保存数据,我将使用多个 SET 操作,即:
$redis->set("MyKey-UserID-Clicks", 123);
$redis->set("MyKey-UserID-Downloads", 1234);
$redis->set("MyKey-UserID-Views", 123);
Run Code Online (Sandbox Code Playgroud)
然后更新数据我会使用多个 INCR 操作,即:
$redis->incr("MyKey-UserID-Clicks");
$redis->incr("MyKey-UserID-Downloads");
$redis->incr("MyKey-UserID-Views");
Run Code Online (Sandbox Code Playgroud)
我选择的选项 + 问题
我个人会使用选项 1,您有什么看法?
您认为使用 GET + SET 仍然会像使用 INCR 一样快吗?
您如何看待选项 2?
我对选项 1 的利弊
选项 1 优点:
选项 1 缺点:
一些有用的答案
@Samveen(链接)
如果预期会同时修改 JSON 负载,则选项 1 不是一个好主意(非原子读-修改-写的经典问题)
我们有很多并发连接,所以也许选项 2 是赢家。
我在听取@TheDude 的建议后添加了我的答案
选项 3:使用哈希(赢家)
为了保存数据,我将使用一个 hMSet,即:
$redis->hMSet('MyKey-UserID', array('clicks' => 123, 'downloads' => 123, 'views' => 123));
Run Code Online (Sandbox Code Playgroud)
然后要更新所有字段,我将使用多个 hIncrBy,即:
$redis->hIncrBy('MyKey-UserID', 'clicks', 2);
$redis->hIncrBy('MyKey-UserID', 'downloads', 2);
$redis->hIncrBy('MyKey-UserID', 'views', 2);
Run Code Online (Sandbox Code Playgroud)
使用这种方法,我可以拥有一个哈希值 (MyKey-UserID),然后添加自定义字段。
所以数据库仍然很小(与选项 2 相比)并且并发写入会很好(与选项 1 相比)。
根据phpredis,我还可以使用 multi() 在一个操作中运行多个命令:
Redis::MULTI 命令块作为单个事务运行
https://github.com/phpredis/phpredis#multi-exec-discard
所以我可以像这样更新多个字段或所有字段,只执行一项操作:
$ret = $redis->multi()
->hIncrBy('MyKey-UserID', 'clicks', 2)
->hIncrBy('MyKey-UserID', 'downloads', 2)
->hIncrBy('MyKey-UserID', 'views', 2)
->exec();
Run Code Online (Sandbox Code Playgroud)
哈希与 SET/GET (key=value) 数据类型
根据这个答案:https : //stackoverflow.com/a/24505485/2972081
尽可能使用哈希
小散列被编码在一个非常小的空间中,因此您应该尝试在每次可能时使用散列来表示您的数据。例如,如果您在 Web 应用程序中有代表用户的对象,而不是对姓名、姓氏、电子邮件、密码使用不同的键,而是使用包含所有必填字段的单个哈希。
我做了一些基准测试,结果如下:
hset myhash rand_string rand_int: 31377.47 requests per second
hget myhash rand_string: 30750.31 requests per second
hincrby myhash rand_string: 30312.21 requests per second
set rand_string: 30703.10 requests per second
get rand_string: 30969.34 requests per second
incrby rand_string: 30581.04 requests per second
Run Code Online (Sandbox Code Playgroud)
我用于基准测试的命令是这样的:
redis-benchmark -n 100000 -q hset myhash rand_string rand_int
Run Code Online (Sandbox Code Playgroud)
所以哈希和 Get/Set(字符串)一样快。