我正在开发一个Web应用程序(Nginx + PHP7.3),该应用程序将使用Redis数据库存储一些数据(主要用于计数),我必须决定如何存储数据。就我而言,重要的是速度和性能,并保持每秒较低的操作速度,以便能够处理与Web应用程序的许多并发连接。
选项1:将JSON数据存储在单个密钥上
要保存数据,我将使用单个SET操作,即:
$redis->set("MyKey-UserID", '{"clicks":123,"downloads":1234,"views":123}');
然后要更新数据,我将使用两种操作(GET + SET),即:
$array = json_decode($redis->get("MyKey-UserID"), true);
$array['clicks']++;
$array['downloads']++;
$array['views']++;
$redis->set("MyKey-UserID", json_encode($array));
选项2:具有单个值的多个键
要保存数据,我将使用多个SET操作,即:
$redis->set("MyKey-UserID-Clicks", 123);
$redis->set("MyKey-UserID-Downloads", 1234);
$redis->set("MyKey-UserID-Views", 123);
然后要更新数据,我将使用多个INCR操作,即:
$redis->incr("MyKey-UserID-Clicks");
$redis->incr("MyKey-UserID-Downloads");
$redis->incr("MyKey-UserID-Views");
我选择的选项+问题
我个人会使用选项1,您对此有何看法?
您认为使用GET + SET还是使用INCR仍然会很快?
您对方案2有何看法?
我在选项1中的优点/缺点
选项1优点:
选项1缺点:
一些有用的答案
@Samveen(Link)
如果同时修改JSON,则选项1不是一个好主意 有效载荷是预期的(非原子的经典问题 读-修改-写)
我们有许多并发连接,所以选项2可能是赢家。
答案 0 :(得分:1)
如果您需要更新单个字段并重新保存它,那么选项1并不理想,因为它不能正确处理并发写入。
您应该能够在Redis中用作HASH
,并使用HINCRBY来增加哈希中的各个键。将其与管道结合使用,更新多个密钥时,您只会向Redis发出一个请求。
您可以使用HGETALL来获取哈希中的所有键/值对。
答案 1 :(得分:0)
我在接受@TheDude的建议后添加了答案
选项3:使用哈希(优胜者)
要保存数据,我将使用一个hMSet,即:
$redis->hMSet('MyKey-UserID', array('clicks' => 123, 'downloads' => 123, 'views' => 123));
然后更新所有字段,我将使用多个hIncrBy,即:
$redis->hIncrBy('MyKey-UserID', 'clicks', 2);
$redis->hIncrBy('MyKey-UserID', 'downloads', 2);
$redis->hIncrBy('MyKey-UserID', 'views', 2);
使用这种方法,我可以拥有一个哈希(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();
哈希与SET / GET(键=值)数据类型
根据此答案: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
我用于基准测试的命令是这样的:
redis-benchmark -n 100000 -q hset myhash rand_string rand_int
所以散列与Get / Set(字符串)一样快。