文档章节

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

D
 DeffPuzzL
发布于 06/13 23:19
字数 1384
阅读 96
收藏 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常见的应用场景解析

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
分布式锁实现汇总

[TOC] 分布式锁实现汇总 很多时候我们需要保证同一时间一个方法只能被同一个线程调用,在单机环境中,Java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就...

Wang_Coder
2017/12/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

(三)Nginx配置·续

概述 前文写了关于Nginx环境配置,但是还没有完,接下来将会继续讲三个相关的配置 主要是以下三个 1.Nginx访问日志 2.Nginx日志切割 3.静态文件不记录日志和过期时间 Nginx访问日志 1.先看看...

杉下
今天
1
0
jquery创建类似于java的map

var map = {}; // Map map = new HashMap(); map[key] = value; // map.put(key, value); var value = map[key]; // Object value = map.get(key); var has = key in map; // boolean has = ......

SuperDabai
今天
0
0
java大数据转换16进制转10进制

public static void main(String[] args) {String hex = "0xdbf3accc683297cf0000";BigInteger amount = new BigInteger(hex.substring(2), 16);System.out.println(amount);......

任梁荣
昨天
2
0
OSChina 周六乱弹 —— 目测我们程序员丁克的几率不大

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @真Skr小机灵鬼儿:8.13分享Jocelyn Pook/Russian Red的单曲《Loving Strangers》 《Loving Strangers》- Jocelyn Pook/Russian Red 手机党少...

小小编辑
昨天
13
3
TypeScript基础入门 - 函数 - 剩余参数

转载 TypeScript基础入门 - 函数 - 剩余参数 项目实践仓库 https://github.com/durban89/typescript_demo.gittag: 1.2.1 为了保证后面的学习演示需要安装下ts-node,这样后面的每个操作都能...

durban
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部