EasyCMS在幼儿园视频直播项目实战中以redis操作池的方式应对高并发的redis操作问题
在之前的博客《 EasyDarwin幼教云视频平台在幼教平台领域大放异彩!》中我们也介绍到,EasyCMS+EasyDarwin+redis形成的EasyDarwin云平台方案,在幼教平台领域中稳定运营,收到了用户的良好口碑;
随着幼儿园平台用户和接入幼儿园的数量不断增加,EasyCMS的redis操作也越来越频繁,我们在运维中发现EasyCMS的cpu占用非常高,通过线程分析,发现大家都在等待一个redis操作对象,redis操作对象锁造成了资源竞争,于是,我们决定采用redis操作池,我们的基本思路是:
- 初始化建立16个redis操作对象RedisHandler,并保持连接redis server;
- 采用链表的方式管理RedisHandler,先进先出的方式从链表获取RedisHandler;
- 当从链表获取不到RedisHandler,表示资源不足,动态new一个RedisHandler;
- 每一次操作Redis完成后,将RedisHandler插入回链表;
- 限定一个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
获取更多信息
Copyright © EasyDarwin.org 2012-2017

EasyCMS在幼儿园视频直播项目实战中以redis操作池的方式应对高并发的redis操作问题的更多相关文章
- 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发
一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...
- 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...
- 基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式
在基于Vue的工作流项目模块中,我们在查看表单明细的时候,需要包含公用表单信息,特定表单信息两部分内容.前者表单数据可以统一呈现,而后者则是不同业务的表单数据不同.为了实现更好的维护性,把它们分开作为 ...
- 基于EasyDarwin云视频平台的幼儿园视频直播(手机直播/微信直播)解决方案
一.方案介绍 1.1.方案背景 在2016年10月25日至28日的安博会上,我们看到了不少的幼教平台厂商,我们注意到大部分的幼教平台,为了追求极佳的用户体验,在微信或者APP端能够做到极快的打开速度, ...
- 视频直播:Windows中各类画面源的截取和合成方法总结
当今,视频直播技术和实时音视频技术已经是很多行业必备,典型的应用场景有教育直播.远程视频会议.互联网娱乐等.在移动端发起直播,其画面源的种类是十分有限的,无非是取摄像头.截屏等.PC端由于其系统资源充 ...
- selenium3 web自动化测试框架 三:项目实战中PO模型的设计与封装
po模型设计思想 Page Object 模式主要是将每个页面设计为一个class,其中包含页面中的需要测试的元素(按钮,输入框,标题等),这样在Selenium测试页面中可以通过调取页面类来获取页面 ...
- 【.NET Core项目实战-统一认证平台】第五章 网关篇-自定义缓存Redis
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我们介绍了2种网关配置信息更新的方法和扩展Mysql存储,本篇我们将介绍如何使用Redis来实现网关的所有缓存功能,用到的文档及源码 ...
- Java项目开发中实现分页的三种方式一篇包会
前言 Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...
- gulp的使用(三)之把gulp运用到项目实战中
在了解了上面的gulp(一)(二)以后,我们就可以开始在项目中具体使用了,具体使用流程如下: 1. 创建一个project文件夹,然后里面首先创建一个src文件夹,里面放置开发要用到的文件夹: 2. ...
随机推荐
- unicode下数据之间的转换
首先mfc下字符串只有两种数据:char(一个字节)和wchar_t(两个字节),很多其他数据类型如TCHAR,WCHAR等都是这个两个基本类型的宏定义,BYTE是uchar 1.对话框打印char* ...
- Job流程:决定map个数的因素
此文紧接Job流程:提交MR-Job过程.上一篇分析可以看出,MR-Job提交过程的核心代码在于 JobSubmitter 类的 submitJobInternal()方法.本文就由此方法的这一句代码 ...
- 感觉Google要搞事情
- [BZOJ2109]Plane 航空管制
Description 世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频 发生.最近,小X就因为航空管制,连续两次在机场被延误超过了两小时.对此, 小X表示很不满意. 在这次来烟台的 ...
- Flink快速入门
文章目录 1 安装:下载并启动 1.1 下载 1.2 启动一个local模式的Flink集群 2 运行例子 3 集群模式安装 4 Flink on YARN 安装:下载并启动 Flink可以在Linu ...
- Excel_To_DataTable
/// <summary> /// Read data in excel file to datatable /// </summary> /// <param name ...
- Android--------工具类StatusBarUtil实现完美状态栏
很早就想写这篇博客了,直到前几天有人问我这方面的问题才想起. 沉浸式状态栏是从android Kitkat(Android 4.4)开始出现的,顶部状态栏的颜色可以根据开发需求改变,使得APP风格更加 ...
- 51nod-1103-抽屉原理
1103 N的倍数 题目来源: Ural 1302 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 一个长度为N的数组A,从A中选出若干个数,使得 ...
- OC与JS的交互详解
事情的起因还是因为项目需求驱动.折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾. 我要实现这样一个需求:按照本地的CSS ...
- Using Oracle Database In-Memory with Oracle E-Business Suite
Database In-Memory is one of a number of options that can be deployed to address Oracle E-Business S ...