文档章节

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

D
 DeffPuzzL
发布于 06/13 23:19
字数 1384
阅读 68
收藏 0
点赞 0
评论 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
码字总数 4609
作品 1
武汉
程序员
C 语言编写的内存数据库 - STVM

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

DeffPuzzL ⋅ 03/02 ⋅ 1

Redis常见的应用场景解析

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

IT米粉 ⋅ 2017/09/25 ⋅ 0

Redis在游戏开发中的典型应用

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

夏周tony ⋅ 2017/12/25 ⋅ 0

记5.28大促压测的性能优化—线程池相关问题

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

王清培 ⋅ 2017/06/04 ⋅ 0

分布式锁实现汇总

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

Wang_Coder ⋅ 2017/12/01 ⋅ 0

关于秒杀的系统架构优化思路

解决方案1: 将存库从MySQL前移到Redis中,所有的写操作放到内存中,由于Redis中不存在锁故不会出现互相等待,并且由于Redis的写性能和读性能都远高于MySQL,这就解决了高并发下的性能问题。...

萧小蚁 ⋅ 2016/12/20 ⋅ 0

关于Redis的应用

写这篇文章主要是在开发www.ximalaya.com的feed(登录首页看到的好友动态,未登录是看不到的)模块使用Redis的一些经验。(www.ximalaya.com是音频为传播介质的SNS网站,喜欢的同学不妨用一用...

李国刚 ⋅ 2012/12/10 ⋅ 3

SegmentFault 技术周刊 Vol.37 - 分布式缓存利器:Redis

Redis 是由意大利程序员 Salvatore Sanfilippo(昵称:antirez)开发的一款内存高速缓存数据库。Redis 全称为 Remote Dictionary Server(远程数据服务),使用 C 语言编写,是一个 key-valu...

keke ⋅ 2017/11/16 ⋅ 0

Linux下常用轻量级队列服务比较

Linux IPC: IPC进程间通信(Inter-Process Communication)就是指多个进程之间相互通信,交换信息的方法。 系统消息队列功能是这些方法中的其中一种。使用此队列不需要额外安装服务,是系统内...

苗雨顺 ⋅ 2014/03/24 ⋅ 1

Redis的那些最常见面试问题

 随笔:经过长达一周的奔波和面试,电话面试,回首今天终于成功的入职了,总共面试了大概10家公司,包括阿里,京东,IBM等等,京东技术过了,学历因为非统招就被pass了,阿里面了2次电话面试...

码上青天 ⋅ 05/03 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 25分钟前 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

eclipse酷炫大法之设置主题、皮肤

eclipse酷炫大法 目前两款不错的eclipse 1.系统设置 Window->Preferences->General->Appearance 2.Eclipse Marketplace下载【推荐】 Help->Eclipse Marketplace->搜索‘theme’进行安装 比如......

anlve ⋅ 昨天 ⋅ 0

vim编辑模式、vim命令模式、vim实践

vim编辑模式 编辑模式用来输入或修改文本内容,编辑模式除了Esc外其他键几乎都是输入 如何进入编辑模式 一般模式输入以下按键,均可进入编辑模式,左下角提示 insert(中文为插入) 字样 i ...

蛋黄Yolks ⋅ 昨天 ⋅ 0

大数据入门基础:SSH介绍

什么是ssh 简单说,SSH是一种网络协议,用于计算机之间的加密登录。 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码...

董黎明 ⋅ 昨天 ⋅ 0

web3j教程

web3j是一个轻量级、高度模块化、响应式、类型安全的Java和Android类库提供丰富API,用于处理以太坊智能合约及与以太坊网络上的客户端(节点)进行集成。 汇智网最新发布的web3j教程,详细讲解...

汇智网教程 ⋅ 昨天 ⋅ 0

谷歌:安全问题机制并不如你想象中安全

腾讯科技讯 5月25日,如今的你或许已经对许多网站所使用的“安全问题机制”习以为常了,但你真的认为包括“你第一个宠物的名字是什么?”这些问题能够保障你的帐户安全吗? 根据谷歌(微博)安...

问题终结者 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部