在之前的博客《 EasyDarwin幼教云视频平台在幼教平台领域大放异彩!》中我们也介绍到,EasyCMS+EasyDarwin+redis形成的EasyDarwin云平台方案,在幼教平台领域中稳定运营,收到了用户的良好口碑;

随着幼儿园平台用户和接入幼儿园的数量不断增加,EasyCMS的redis操作也越来越频繁,我们在运维中发现EasyCMS的cpu占用非常高,通过线程分析,发现大家都在等待一个redis操作对象,redis操作对象锁造成了资源竞争,于是,我们决定采用redis操作池,我们的基本思路是:

  1. 初始化建立16个redis操作对象RedisHandler,并保持连接redis server;
  2. 采用链表的方式管理RedisHandler,先进先出的方式从链表获取RedisHandler;
  3. 当从链表获取不到RedisHandler,表示资源不足,动态new一个RedisHandler;
  4. 每一次操作Redis完成后,将RedisHandler插入回链表;
  5. 限定一个RedisHandler链表的最大长度,当超过最大长度时,直接对RedisHandler进行销毁,不插回链表;

基于这个思路,我们实现了一个RedisHandler类:

#ifndef __EASY_REDIS_HANDLER_H__
#define __EASY_REDIS_HANDLER_H__

#include "OSHeaders.h"
#include "QTSServerInterface.h"
#ifdef WIN32
#include "Windows/hiredis.h"
#else
#include "hiredis.h"
#endif //WIN32

#include "Task.h"

class RedisReplyObjectDeleter
{
    public:
        RedisReplyObjectDeleter() : fReply(NULL) {}
        explicit RedisReplyObjectDeleter(redisReply* reply) : fReply(reply)  {}
        ~RedisReplyObjectDeleter()
        {
            if (fReply)
            {
                freeReplyObject(fReply);
            }
        }

        void ClearObject() { fReply = NULL; }

        void SetObject(redisReply* reply)
        {
            fReply = reply;
        }
        redisReply* GetObject() const { return fReply; }

    private:

        redisReply* fReply;
};

class EasyRedisHandler : public Task
{
public:

    EasyRedisHandler(const char* ip, UInt16 port, const char* passwd);
    virtual ~EasyRedisHandler();

    QTSS_Error RedisTTL();

    QTSS_Error RedisSetDevice(Easy_DeviceInfo_Params* inParams);
    QTSS_Error RedisDelDevice(Easy_DeviceInfo_Params* inParams);
    QTSS_Error RedisGetAssociatedDarwin(QTSS_GetAssociatedDarwin_Params* inParams);

    OSQueueElem     fQueueElem;
    UInt32          fID;
private:

    virtual SInt64  Run();

    bool            sIfConSucess;
    OSMutex         sMutex;
    redisContext*   redisContext_;

    char            fRedisIP[128];
    UInt16          fRedisPort;
    char            fRedisPasswd[256];

    bool RedisConnect();
    void RedisErrorHandler();
};

#endif //__EASY_REDIS_HANDLER_H__
#include "EasyRedisHandler.h"

#include "QTSSMemoryDeleter.h"
#include "Format.h"
#include "Resources.h"

static UInt32 sRedisHandlerID = 0;

EasyRedisHandler::EasyRedisHandler(const char* ip, UInt16 port, const char* passwd)
    : fQueueElem(),
    fID(sRedisHandlerID++),
    sIfConSucess(false),
    sMutex(),
    redisContext_(NULL)
{
    this->SetTaskName("EasyRedisHandler");

    fQueueElem.SetEnclosingObject(this);

    ::strcpy(fRedisIP, ip);
    fRedisPort = port;
    ::strcpy(fRedisPasswd, passwd);

    this->Signal(Task::kStartEvent);
}

EasyRedisHandler::~EasyRedisHandler()
{
    RedisErrorHandler();
}

SInt64 EasyRedisHandler::Run()
{
    OSMutexLocker locker(&sMutex);

    EventFlags theEvents = this->GetEvents();

    RedisConnect();

    return 0;
}

bool EasyRedisHandler::RedisConnect()
{
    if (sIfConSucess)
    {
        return true;
    }

    bool theRet = false;
    do
    {
        struct timeval timeout = { 2, 0 }; // 2 seconds
        redisContext_ = redisConnectWithTimeout(fRedisIP, fRedisPort, timeout);
        if (!redisContext_ || redisContext_->err)
        {
            if (redisContext_)
            {
                printf("Redis context connect error \n");
            }
            else
            {
                printf("Connection error: can't allocate redis context\n");
            }

            theRet = false;
            break;
        }

        string auth = Format("auth %s", string(fRedisPasswd));
        redisReply* reply = static_cast<redisReply*>(redisCommand(redisContext_, auth.c_str()));

        RedisReplyObjectDeleter replyDeleter(reply);
        if (!reply || string(reply->str) != string("OK"))
        {
            printf("Redis auth error\n");
            theRet = false;
            break;
        }

        theRet = true;
        sIfConSucess = true;

        printf("Connect Redis success\n");

    } while (0);

    if (!theRet && redisContext_)
    {
        RedisErrorHandler();
    }

    return theRet;
}

在外围链表管理上,一开始我们就初始化16个RedisHandler:

    for (UInt32 numPackets = 0; numPackets < 16; numPackets++)
    {
        EasyRedisHandler* handler = new EasyRedisHandler(sRedis_IP, sRedisPort, sRedisPassword);
        sFreeHandlerQueue.EnQueue(&handler->fQueueElem);//put this packet onto the free queue
    }

再各定义一个获取RedisHandler和回收RedisHandler的方法:

EasyRedisHandler* GetRedisHandler()
{
    OSMutexLocker locker(&sMutex);
    if (sFreeHandlerQueue.GetLength() == 0)
        //if the port number of this socket is odd, this packet is an RTCP packet.
        return new EasyRedisHandler(sRedis_IP, sRedisPort, sRedisPassword);
    else
        return (EasyRedisHandler*)sFreeHandlerQueue.DeQueue()->GetEnclosingObject();
}

void RedisHandlerReclaim(EasyRedisHandler* handler)
{
    if(handler)
    {
        printf("RedisHandlerReclaim ID:%d \n", handler->fID);
        if(sFreeHandlerQueue.GetLength() > sMaxRedisClientPoolSize)
            handler->Signal(Task::kKillEvent);
        else
            sFreeHandlerQueue.EnQueue(&handler->fQueueElem);
    }
}

于是,完整的redis操作池方法就实现了,基于这个方法实现的操作池,完全满足了项目上的需求;

请关注我们的EasyDarwin开源项目:https://github.com/EasyDarwin

获取更多信息

邮件:support@easydarwin.org

WEB:www.EasyDarwin.org

Copyright © EasyDarwin.org 2012-2017

EasyCMS在幼儿园视频直播项目实战中以redis操作池的方式应对高并发的redis操作问题的更多相关文章

  1. 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发

    一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...

  2. 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...

  3. 基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式

    在基于Vue的工作流项目模块中,我们在查看表单明细的时候,需要包含公用表单信息,特定表单信息两部分内容.前者表单数据可以统一呈现,而后者则是不同业务的表单数据不同.为了实现更好的维护性,把它们分开作为 ...

  4. 基于EasyDarwin云视频平台的幼儿园视频直播(手机直播/微信直播)解决方案

    一.方案介绍 1.1.方案背景 在2016年10月25日至28日的安博会上,我们看到了不少的幼教平台厂商,我们注意到大部分的幼教平台,为了追求极佳的用户体验,在微信或者APP端能够做到极快的打开速度, ...

  5. 视频直播:Windows中各类画面源的截取和合成方法总结

    当今,视频直播技术和实时音视频技术已经是很多行业必备,典型的应用场景有教育直播.远程视频会议.互联网娱乐等.在移动端发起直播,其画面源的种类是十分有限的,无非是取摄像头.截屏等.PC端由于其系统资源充 ...

  6. selenium3 web自动化测试框架 三:项目实战中PO模型的设计与封装

    po模型设计思想 Page Object 模式主要是将每个页面设计为一个class,其中包含页面中的需要测试的元素(按钮,输入框,标题等),这样在Selenium测试页面中可以通过调取页面类来获取页面 ...

  7. 【.NET Core项目实战-统一认证平台】第五章 网关篇-自定义缓存Redis

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我们介绍了2种网关配置信息更新的方法和扩展Mysql存储,本篇我们将介绍如何使用Redis来实现网关的所有缓存功能,用到的文档及源码 ...

  8. Java项目开发中实现分页的三种方式一篇包会

    前言   Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...

  9. gulp的使用(三)之把gulp运用到项目实战中

    在了解了上面的gulp(一)(二)以后,我们就可以开始在项目中具体使用了,具体使用流程如下: 1. 创建一个project文件夹,然后里面首先创建一个src文件夹,里面放置开发要用到的文件夹: 2. ...

随机推荐

  1. 学号20145322 《Java程序设计》第一周学习总结

    学号20145322 <Java程序设计>第一周学习总结 教材学习内容总结 Java诞生于Sun公司,于1998年12月4日发布J2SE,约以两年为一周期推出重大版本更新. 2010年Or ...

  2. nmap与Nessus扫描特定靶机分析

    打开装载Metasploitable2虚拟机的靶机,并获取靶机ip: 使用nmap+ip初步扫描靶机 PORT为端口,STATE为端口开放状态,SERVICE为端口的提供的服务.靶机的MAC地址为: ...

  3. Ubuntu 12.04下安装QQ 2012 Beta3

    Ubuntu 12.04下安装QQ 2012 Beta3   由于wine的发展非常迅速.现在网上的利用老版本的wine来安装QQ2012的教程已经有些过时了.实际上操作起来非常简单: 第一步:Ctr ...

  4. [CF1051F]The Shortest Statement

    题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路 $n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$. 首先看到$ ...

  5. Faster-rcnn 配置方法

    Faster-rcnn 在Linux下的配置方法 感谢@邓学长 建立过程: (下载库的时候要按照库readme 进行操作) opencv 的包下载安装,安装教程 用git命令将这个库下载到本地 fas ...

  6. HDU1698 just a Hook - 带有lazy标记的线段树

    2017-08-30 16:44:33 writer:pprp 上午刚刚复习了一下不带有lazy标记的线段树, 下午开始学带有lazy标记的线段树 这个是我看大佬代码敲的,但是出了很多问题, 这提醒我 ...

  7. hiho 有序01字符串 dp

    题目1 : 有序01字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于一个01字符串,你每次可以将一个0修改成1,或者将一个1修改成0.那么,你最少需要修改多少 ...

  8. pip 批量更新

    1. pip3 list --outdated >> requests  现将要更新的列表写入requests 2.对文件中的数据进行处理 Package        Version   ...

  9. 微信小程序------小程序初步学习

    1:学习微信小程序,首先的会一点前端的基础会比较容易上手,比如:HTML+CSS,JS,HTML5+CSS3: H5+CSS3中的弹性盒子在微信小程序中经常用到,这是必须掌握的.不会的可以去W3C文档 ...

  10. UVA-11865 Stream My Contest (朱-刘 算法+二分)

    题目大意:有一张n个顶点,m条边的有向图,根节点为0.每条边有两个权值,一个是费用c,一个是长度b.问在总费用不超过cost的情况下选出若干条边,使得n个点连通时的边的最短长度的最大值是多少. 题目分 ...