文档章节

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

D
 DeffPuzzL
发布于 06/13 23:19
字数 1384
阅读 112
收藏 0

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
1 2.772 1,442,897
2 1.944 2,057,825
4 1.678 2,383,790
10 1,608 2,487,253
  • STVM多进程本地PUSH数据:
进程数 400W记录5次平均耗时(单位秒) TPS
2 2.772 1,993,223
4 1.944 2,326,664
5 1.678 2,322,341

结果分析:

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

  • STVM多线程本地POP数据
线程数 400W记录5次平均耗时(单位秒) TPS
1 3.049 1,311,992
2 2.190 1,826,651
4 1.926 2,077,059
10 1.867 2,142,934
  • STVM多进程本地POP数据
进程数 400W记录5次平均耗时(单位秒) TPS
2 2.137 1,872,133
4 1.828 2,188,432
5 1.844 2,169,668

结果分析:

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

  • STVM多线程本地PUSH-POP数据
线程数 800W记录5次平均耗时(单位秒) TPS
1-POP 1-PUSH 3.507 2,281,152
1-POP 2-PUSH 2.933 2,727,583
2-POP 2-PUSH 2.577 3,104,385

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

网络调用

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

  • REDIS多线程同步PUSH数据
线程数 400W记录5次平均耗时(单位秒) TPS
1 186.201 21,482
2 94.468 42,342
4 81.217 49,251
  • STVM多线程同步PUSH数据
线程数 400W记录5次平均耗时(单位秒) TPS
1 118.466 33,765
2 50.705 78,888
4 37.662 106,209

 

  • REDIS多线程POP数据
线程数 400W记录5次平均耗时(单位秒) TPS
1 167.157 23,930
2 74.067 54,006
4 65.923 60,667
  • STVM多线程POP数据
线程数 400W记录5次平均耗时(单位秒) TPS
1 120.650 33,154
2 53.878 74,241
4 37.622 106,322

 

  • REDIS多线程异步PUSH
线程数 400W记录5次平均耗时(单位秒) TPS
1 50.289 79,289
2 46.163 86,649
4 39.649 100,885
  • STVM多线程异步PUSH
线程数 400W记录5次平均耗时(单位秒) TPS
1 11.166 358,238
2 9.846 406,246
4 9.311 429,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;
}

 

 

© 著作权归作者所有

共有 人打赏支持
D
粉丝 1
博文 3
码字总数 4588
作品 1
武汉
程序员
C 语言编写的内存数据库 - STVM

STVM(truck of Virtual memory table)是一个开源的使用ANSI C语言编写、支持本地API调用和网络调用,全表数据基于IPC共享内存方式存储, 基于C语言struck结构定义记录行,RB-Tree和hash作为...

DeffPuzzL
03/02
0
1
Redis 的 8 大应用场景!

之前讲过Redis的介绍,及使用Redis带来的优势,这章整理了一下Redis的应用场景,也是非常重要的,学不学得好,能正常落地是关键。 下面一一来分析下Redis的应用场景都有哪些。 1、缓存 缓存现...

Java技术栈
08/29
0
0
Redis常见的应用场景解析

Redis是一个key-value存储系统,现在在各种系统中的使用越来越多,大部分情况下是因为其高性能的特性,被当做缓存使用,这里介绍下Redis经常遇到的使用场景。 Redis特性 一个产品的使用场景肯...

IT米粉
2017/09/25
0
0
Redis在游戏开发中的典型应用

1. 摘要 Redis作为目前最流行的键值对存储数据库,有着丰富的数据结构支持,在民生、金融、游戏、直播等诸多领域都有广泛的应用,大大提升了开发者的开发效率。今天我们主要介绍Redis在游戏开...

夏周tony
2017/12/25
0
0
记5.28大促压测的性能优化—线程池相关问题

目录: 1.环境介绍 2.症状 3.诊断 4.结论 5.解决 6.对比java实现 废话就不多说了,本文分享下博主在5.28大促压测期间解决的一个性能问题,觉得这个还是比较有意思的,值得总结拿出来分享下。...

王清培
2017/06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用JDK自带的jmap和jhat监控处于运行状态的Java进程

对于处于运行状态中的Java进程,JDK自带了很多工具,允许Java开发人员监控运行进程中的各种状态,比如该进程内部创建了多少个对象实例,消耗了多少内存,等等。 本文基于JDK1.8而写成。 我下...

JerryWang_SAP
14分钟前
1
0
下单接口调优实战,性能提高10倍

概述 最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了,如果改动太大,怕有风险。另外开发成本和测试成本也非常大。对于这种...

Sam哥哥聊技术
47分钟前
4
1
rabbitMQ的安装和配置

在Windows下进行rabbitMQ的安装 第一步:软件下载 在安装rabbitMQ之前,需要先安装Erlang。 Erlang官网:http://www.erlang.org/downloads rabbitMQ官网:http://www.rabbitmq.com/download....

狼王黄师傅
今天
3
0
Vue-Element-Upload

记录一下文件上传封装Js 代码示例 封装:uploadFile.vue <template> <el-upload v-model="attachment" ref="upload" class="upload-demo" :action="uploadUrl" ......

华山猛男
今天
4
0
AWVS破解及使用手册

1.安装 因为是windows软件,比较简单,此部分略: 破解插件下载: 链接: https://pan.baidu.com/s/1x9LK9F3KvqDgTvXDjoSZnQ 提取码: 7k4u 2.创建扫描目标 2-1.Targets->Add Target 2-2.对话框...

硅谷课堂
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部