用workerman代替redis

lxping

redis优点主要是内存读取和本地持久化,但提供的数据类型太简单,只能字符串和一维key的操作。所以做做简单的存储和并发检索还是可以的,但是要想更复杂的功能,我们就要基于redis做封装。
那么,如果用workerman来开发仿造一个redis,php-frm直接连接worker进程中的内存变量,两者都是常驻内存,数据也都是在内存中的,就像Gateway::bindUid一样的原理,岂不是更爽。
暂且不管redis的其他特性,单就workerman替代redis方案的可能性和效率做比较,我做了个demo测试。

下面分别对workerman和redis做字符串set操作,为了公平,workerman代码里做了key值不存在就设置,存在就覆盖的操作。测试结果如下:100万的set操作,workerman只需要7秒,redis需要32秒
截图

下面截图是redis的rpush和php的array_push对比,速度秒数reids。不过测试也发现一些缺点,php模拟rpush时很占用内存,lpush无法实现,主要是php的array_unshift性能不行。
截图

下面是代码,大家可以自行测试

web代码:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$wm = stream_socket_client('tcp://127.0.0.1:8899');

$time = microtime(true);
$key = 0;
for ($i=0; $i < 10000; $i++)
{
    $redis->set('key', ++$key);
}

echo 'redis 1w:'. (microtime(true) - $time) . '<br>';

$time = microtime(true);
for ($i=0; $i < 100000; $i++)
{
    $redis->set('key', ++$key);
}

echo 'redis 10w:'. (microtime(true) - $time) . '<br>';

$time = microtime(true);
for ($i=0; $i < 1000000; $i++)
{
    $redis->set('key', ++$key);
}

echo 'redis 100w:'. (microtime(true) - $time) . '<br>';
echo 'redis get:'. $redis->get('key') . '<br><br>';

$time = microtime(true);
for ($i=0; $i < 10000; $i++)
{
    fwrite($wm, json_encode(['type' => 'set', 'key' => 'key', 'value' => ++$key])."\n");
}

echo 'worker 1w:'. (microtime(true) - $time) . '<br>';

$time = microtime(true);
for ($i=0; $i < 100000; $i++)
{
    fwrite($wm, json_encode(['type' => 'set', 'key' => 'key', 'value' => ++$key])."\n");
}

echo 'worker 10w:'. (microtime(true) - $time) . '<br>';

$time = microtime(true);
for ($i=0; $i < 1000000; $i++)
{
    fwrite($wm, json_encode(['type' => 'set', 'key' => 'key', 'value' => ++$key])."\n");
}

echo 'worker 100w:'. (microtime(true) - $time) . '<br>';
fwrite($wm, json_encode(['type' => 'get', 'key' => 'key'])."\n");
echo 'worker get:'. fgets($wm, 1024);

workerman代码:

<?php

use \Workerman\Worker;

// 自动加载类
require_once __DIR__ . '/../../vendor/autoload.php';

$worker = new Worker('text://127.0.0.1:8899');
$worker->name = 'workerman';
$worker->count = 1;

$_session = [];

$worker->onMessage = function($connection, $data)
{
    global $_session;

    $data = json_decode($data);
    switch ($data->type) {
        case 'get':
            $connection->send($_session[$data->key]);
            break;
        case 'set':
            $_session[$data->key] = $data->value;
            break;
    }
};

// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
    Worker::runAll();
}
3145 1 0
1个回答

six

array_unshift 慢是因为每次调用要重建索引。
数组元素越多越慢。
php 有splqueue https://www.php.net/manual/zh/class.splqueue.php ,专门做队列的,而且比php数组省内存。
按道理比array更快

  • lxping 2020-02-28

    谢谢大神,才发现php一系列牛逼的扩展库

年代过于久远,无法发表回答
🔝