当前位置: 首页 > 工具软件 > STVM > 使用案例 >

REDIS列表与STVM无锁队列性能比较

安经纶
2023-12-01

redis-list队列功能,生产-消费模式,大多用于项目的事件驱动,本文将最近测试的REDIS列表与STVM无锁环形队列性能做以下测试报告,仅供大家参考。

       由于STVM本身支持多进程,多线程,为了测试对比性,STVM网络服务启动1个线程,单张队列表,客户端采用多进程,多线程,全部采用单机部署。

注意gcc 版本必须 >= 4.1.2

 

测试配置:

机器配置如下:

在64位 Ubuntu上测试,机器配置如下:

4G RAM,CPU:Intel(R) Core(TM) i3 CPU       M 380  @ 2.53GHz  4核

 

测试案例:

本地调用

      由于redis不支持本地调用接口,因此在本地调用仅展示数据。

  • STVM多线程本地PUSH数据
线程数400W记录5次平均耗时(单位秒)TPS
12.7721,442,897
21.9442,057,825
41.6782,383,790
101,6082,487,253
  • STVM多进程本地PUSH数据:
进程数400W记录5次平均耗时(单位秒)TPS
22.7721,993,223
41.9442,326,664
51.6782,322,341

结果分析:

线程效率跟进程效率相差不大,因为是原子锁(CAS),多线程下存在少量优势。

  • STVM多线程本地POP数据
线程数400W记录5次平均耗时(单位秒)TPS
13.0491,311,992
22.1901,826,651
41.9262,077,059
101.8672,142,934
  • STVM多进程本地POP数据
进程数400W记录5次平均耗时(单位秒)TPS
22.1371,872,133
41.8282,188,432
51.8442,169,668

结果分析:

线程效率跟进程效率相差不大,因为是原子锁(CAS),多线程下存在少量优势。

  • STVM多线程本地PUSH-POP数据
线程数800W记录5次平均耗时(单位秒)TPS
1-POP 1-PUSH3.5072,281,152
1-POP 2-PUSH2.9332,727,583
2-POP 2-PUSH2.5773,104,385

PUSH 400W, POP 400记录,测试性能。

网络调用

  考虑网络IO,redis队列的value的大小跟stvm单元记录大小一致。

  • REDIS多线程同步PUSH数据
线程数400W记录5次平均耗时(单位秒)TPS
1186.20121,482
294.46842,342
481.21749,251
  • STVM多线程同步PUSH数据
线程数400W记录5次平均耗时(单位秒)TPS
1118.46633,765
250.70578,888
437.662106,209

 

  • REDIS多线程POP数据
线程数400W记录5次平均耗时(单位秒)TPS
1167.15723,930
274.06754,006
465.92360,667
  • STVM多线程POP数据
线程数400W记录5次平均耗时(单位秒)TPS
1120.65033,154
253.87874,241
437.622106,322

 

  • REDIS多线程异步PUSH
线程数400W记录5次平均耗时(单位秒)TPS
150.28979,289
246.16386,649
439.649100,885
  • STVM多线程异步PUSH
线程数400W记录5次平均耗时(单位秒)TPS
111.166358,238
29.846406,246
49.311429,599

结果分析:

性能优势主要体现在CAS原子方法上。

 

在相同IO下 ,redis最大性能10W,stvm网络最大性能42W,STVM主要优势在于本地调用达100W+,多线程下可到达200W+,除外如果新增多个队列表,只要机器资源充足,性能将会倍数增长, 这对于单机群体优势明显。

附上一个push和pop多线程测试代码:

#include    "tvm.h"

#define    QUEUE_USER_INFO            21

typedef unsigned long long uint64;

extern uint64 get_tick_time();

typedef struct _ST_ARG_
{
    uint64 rows;
    uint64 start;
    int    threadIndex;
}ARG;

typedef struct  __QUEUE_USER_INFO
{
   long    acct_id;
   char    user_no[21];
   char    user_type[2];
   char    user_nm[81];
   char    user_addr[161];
   char    user_phone[31];
}dbUser;

void*    vPushQueue(void *arg)
{
    int    i;
    dbUser stUser;
    ARG    *pArgInfo = (ARG *)arg;
    SATvm  *pstSavm = (SATvm *)pCloneSATvm();

    queueinit(pstSavm, stUser, QUEUE_USER_INFO);         // 绑定变量
    strcpy(stUser.user_no,    "20180223");               // 对结构体赋值
    strcpy(stUser.user_type,  "1");                      // 对结构体赋值
    strcpy(stUser.user_nm,    "Savens Liu");             // 对结构体赋值
    strcpy(stUser.user_addr,  "China");                  // 对结构体赋值
    strcpy(stUser.user_phone, "18672911111");            // 对结构体赋值

    for(i = 0; i < pArgInfo->rows; i ++)
    {
        stUser.acct_id = i;                           // 对结构体赋值
        if(RC_SUCC != lPush(pstSavm))
        {
            fprintf(stderr, "Push error:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
            return NULL;
        }
    }

    return NULL;
}

int   main(int argc, char *argv[])
{
    uint64    uTime;
    ARG       arg[100];
    pthread_t thread[10];
    int       i, j, rows = 0, num;
    SATvm     *pstSavm = (SATvm *)pGetSATvm();

    if(argc < 2)
    {
        fprintf(stderr, "lost thread num\n");
        return -1;
    }

    if(1 != argc)
        num = strlen(argv[1])>0?atoi(argv[1]):1;
    else
        num = 1;

    vHoldConnect(pstSavm);
    if(RC_SUCC != lAttchTable(pstSavm, QUEUE_USER_INFO))
    {
        fprintf(stderr, "attch failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
        return RC_FAIL;
    }
    if(argc == 3)
        rows = atol(argv[2]) / num;
    else
        rows = 4000000 / num;
    for(i = 0, uTime = get_tick_time(); i < num; i++)
    {
        arg[i].threadIndex = i + 1;
        arg[i].start = rows * i;
        arg[i].rows = rows;
        pthread_create(&thread[i], NULL, vPushQueue, (void*)&arg[i]);
    }

    for(j = 0; j < num; j++)
         pthread_join(thread[j], NULL);

    fprintf(stdout, "cost_time:[%llu]\r\n", get_tick_time() - uTime);
    vHoldRelease(pstSavm);
    return RC_SUCC;
}

 

#include    "tvm.h"

#define    QUEUE_USER_INFO            21

typedef unsigned long long uint64;

extern uint64 get_tick_time();

typedef struct _ST_ARG_
{
    uint64 rows;
    uint64 start;
    int    threadIndex;
}ARG;

typedef struct  __QUEUE_USER_INFO
{
   long    acct_id;
   char    user_no[21];
   char    user_type[2];
   char    user_nm[81];
   char    user_addr[161];
   char    user_phone[31];
}dbUser;

void*    vPopQueue(void *arg)
{
    int    i;
    dbUser stUser;
    ARG    *pArgInfo = (ARG *)arg;
    SATvm  *pstSavm = (SATvm *)pCloneSATvm();

    queueinit(pstSavm, stUser, QUEUE_USER_INFO);          // 绑定变量
    for(i = 0; i < pArgInfo->rows; i ++)
    {
        if(RC_SUCC != lPop(pstSavm, (void *)&stUser, QUE_NORMAL))
        {
            fprintf(stderr, "Pop error:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
            return NULL;
        }
    }

    return NULL;
}

int   main(int argc, char *argv[])
{
    uint64    uTime;
    ARG       arg[100];
    pthread_t thread[10];
    int       i, j, rows = 0, num;
    SATvm     *pstSavm = (SATvm *)pGetSATvm();

    if(argc < 2)
    {
        fprintf(stderr, "lost thread num\n");
        return -1;
    }

    if(1 != argc)
        num = strlen(argv[1])>0?atoi(argv[1]):1;
    else
        num = 1;

    vHoldConnect(pstSavm);
    if(RC_SUCC != lAttchTable(pstSavm, QUEUE_USER_INFO))
    {
        fprintf(stderr, "attch failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
        return RC_FAIL;
    }

    if(argc == 3)
        rows = atol(argv[2]) / num;
    else
        rows = 4000000 / num;
    for(i = 0, uTime = get_tick_time(); i < num; i++)
    {
        arg[i].threadIndex = i + 1;
        arg[i].start = rows * i;
        arg[i].rows = rows;
        pthread_create(&thread[i], NULL, vPopQueue, (void*)&arg[i]);
    }

    for(j = 0; j < num; j++)
         pthread_join(thread[j], NULL);

    fprintf(stdout, "cost_time:[%llu]\r\n", get_tick_time() - uTime);
    vHoldRelease(pstSavm);
    fflush(stdout);
    return RC_SUCC;
}

 

 

转载于:https://my.oschina.net/deffpuzzl/blog/1829875

 类似资料: