在之前的博客《 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类:

  1. #ifndef __EASY_REDIS_HANDLER_H__
  2. #define __EASY_REDIS_HANDLER_H__
  3. #include "OSHeaders.h"
  4. #include "QTSServerInterface.h"
  5. #ifdef WIN32
  6. #include "Windows/hiredis.h"
  7. #else
  8. #include "hiredis.h"
  9. #endif //WIN32
  10. #include "Task.h"
  11. class RedisReplyObjectDeleter
  12. {
  13. public:
  14. RedisReplyObjectDeleter() : fReply(NULL) {}
  15. explicit RedisReplyObjectDeleter(redisReply* reply) : fReply(reply) {}
  16. ~RedisReplyObjectDeleter()
  17. {
  18. if (fReply)
  19. {
  20. freeReplyObject(fReply);
  21. }
  22. }
  23. void ClearObject() { fReply = NULL; }
  24. void SetObject(redisReply* reply)
  25. {
  26. fReply = reply;
  27. }
  28. redisReply* GetObject() const { return fReply; }
  29. private:
  30. redisReply* fReply;
  31. };
  32. class EasyRedisHandler : public Task
  33. {
  34. public:
  35. EasyRedisHandler(const char* ip, UInt16 port, const char* passwd);
  36. virtual ~EasyRedisHandler();
  37. QTSS_Error RedisTTL();
  38. QTSS_Error RedisSetDevice(Easy_DeviceInfo_Params* inParams);
  39. QTSS_Error RedisDelDevice(Easy_DeviceInfo_Params* inParams);
  40. QTSS_Error RedisGetAssociatedDarwin(QTSS_GetAssociatedDarwin_Params* inParams);
  41. OSQueueElem fQueueElem;
  42. UInt32 fID;
  43. private:
  44. virtual SInt64 Run();
  45. bool sIfConSucess;
  46. OSMutex sMutex;
  47. redisContext* redisContext_;
  48. char fRedisIP[128];
  49. UInt16 fRedisPort;
  50. char fRedisPasswd[256];
  51. bool RedisConnect();
  52. void RedisErrorHandler();
  53. };
  54. #endif //__EASY_REDIS_HANDLER_H__
  1. #include "EasyRedisHandler.h"
  2. #include "QTSSMemoryDeleter.h"
  3. #include "Format.h"
  4. #include "Resources.h"
  5. static UInt32 sRedisHandlerID = 0;
  6. EasyRedisHandler::EasyRedisHandler(const char* ip, UInt16 port, const char* passwd)
  7. : fQueueElem(),
  8. fID(sRedisHandlerID++),
  9. sIfConSucess(false),
  10. sMutex(),
  11. redisContext_(NULL)
  12. {
  13. this->SetTaskName("EasyRedisHandler");
  14. fQueueElem.SetEnclosingObject(this);
  15. ::strcpy(fRedisIP, ip);
  16. fRedisPort = port;
  17. ::strcpy(fRedisPasswd, passwd);
  18. this->Signal(Task::kStartEvent);
  19. }
  20. EasyRedisHandler::~EasyRedisHandler()
  21. {
  22. RedisErrorHandler();
  23. }
  24. SInt64 EasyRedisHandler::Run()
  25. {
  26. OSMutexLocker locker(&sMutex);
  27. EventFlags theEvents = this->GetEvents();
  28. RedisConnect();
  29. return 0;
  30. }
  31. bool EasyRedisHandler::RedisConnect()
  32. {
  33. if (sIfConSucess)
  34. {
  35. return true;
  36. }
  37. bool theRet = false;
  38. do
  39. {
  40. struct timeval timeout = { 2, 0 }; // 2 seconds
  41. redisContext_ = redisConnectWithTimeout(fRedisIP, fRedisPort, timeout);
  42. if (!redisContext_ || redisContext_->err)
  43. {
  44. if (redisContext_)
  45. {
  46. printf("Redis context connect error \n");
  47. }
  48. else
  49. {
  50. printf("Connection error: can't allocate redis context\n");
  51. }
  52. theRet = false;
  53. break;
  54. }
  55. string auth = Format("auth %s", string(fRedisPasswd));
  56. redisReply* reply = static_cast<redisReply*>(redisCommand(redisContext_, auth.c_str()));
  57. RedisReplyObjectDeleter replyDeleter(reply);
  58. if (!reply || string(reply->str) != string("OK"))
  59. {
  60. printf("Redis auth error\n");
  61. theRet = false;
  62. break;
  63. }
  64. theRet = true;
  65. sIfConSucess = true;
  66. printf("Connect Redis success\n");
  67. } while (0);
  68. if (!theRet && redisContext_)
  69. {
  70. RedisErrorHandler();
  71. }
  72. return theRet;
  73. }

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

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

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

  1. EasyRedisHandler* GetRedisHandler()
  2. {
  3. OSMutexLocker locker(&sMutex);
  4. if (sFreeHandlerQueue.GetLength() == 0)
  5. //if the port number of this socket is odd, this packet is an RTCP packet.
  6. return new EasyRedisHandler(sRedis_IP, sRedisPort, sRedisPassword);
  7. else
  8. return (EasyRedisHandler*)sFreeHandlerQueue.DeQueue()->GetEnclosingObject();
  9. }
  10. void RedisHandlerReclaim(EasyRedisHandler* handler)
  11. {
  12. if(handler)
  13. {
  14. printf("RedisHandlerReclaim ID:%d \n", handler->fID);
  15. if(sFreeHandlerQueue.GetLength() > sMaxRedisClientPoolSize)
  16. handler->Signal(Task::kKillEvent);
  17. else
  18. sFreeHandlerQueue.EnQueue(&handler->fQueueElem);
  19. }
  20. }

于是,完整的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. 20145324 Java实验五

    1.运行教材上TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成代码,一人加密后通过TCP发送: 注:加密使用AES或者DES/AES或 ...

  2. python3执行js之pyexecjs

    执行js的三种方法:1.阅读js代码,将之转成python2.找到js代码,用python第三方库执行相关代码 python2-pyv8 python3-pyexecjs3.用selenium驱动浏览 ...

  3. Python解析JSON数据的基本方法

    转自:http://www.jb51.net/article/73450.htm JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScri ...

  4. 【Swift实现代码】iOS架构模式之MVP

    1.什么是MVP? MVP是模型(Model).视图(View).主持人(Presenter)的缩写,分别代表项目中3个不同的模块. 1.1 模型 (Model):负责处理数据的加载或存储 1.2 视 ...

  5. ELK出现unassigned_shards查看及删除

    问题 用3台服务器搭建了ELK系统,有一天出现有几个索引一直无法同步,重启了elasticsearch也不行 如下图:elk-cluster一直处于red状态 解决方法 一,查看elasticsear ...

  6. GDOI2017 五一游玩记

    GDOI2017 到辣! 在五一比赛,成功躲了两天文化课. Day 0 早上睡到挺晚,想着同学在上课,我在睡觉,暗爽... 动车上,拿起电脑就是颓废,打模板!(然而真相是打了两个模板就开始颓了) 一天 ...

  7. Java实习二

    链表(java实现) Link.java public class Link{ private Node first; public Link(){ this.first = null; } //判断 ...

  8. Adobe HTTP Dynamic Streaming (HDS) manifest 文件 f4m bootstrap属性解析

    首先介绍一下应用背景,我们使用的很多浏览器都依赖Adobe Flash Player 播放视频文件.Flash Player是一个播放的客户端,客户端和服务端之间的流通信有几套实现的标准.包括这里介绍 ...

  9. centos cgroup配置

    centOS 6:1. 启用cgroup    查看内核是否支持cgroup功能:cat /boot/config-`uname -r` | grep -i rt_group    查看支持的子系统: ...

  10. ItemsControl的ItemContainerStyle属性

    ItemsControl:ListBox,ComboBox,TreeView ItemContainerStyle是用来设置每一个集合控件的Item的样式的属性(即设置每一个项的样式).   使用It ...