基于线程池、消息队列和epoll模型实现并发服务器架构
引言
并发是什么?企业在进行产品开发过程中为什么需要考虑这个问题?想象一下天猫的双11和京东的618活动,一秒的点击量就有几十万甚至上百万,这么多请求一下子涌入到服务器,服务器需要对这么多的请求逐个进行消化掉,假如服务器一秒的处理能力就几万,那么剩下的不能及时得到处理的这些请求作何处理?总不能让用户界面一直等着,因此消息队列应运而生,所有的请求都统一放入消息队列,工作线程从消息队列不断的消费,消息队列相当于一个缓冲区,可达到解藕、异步和削峰的目的。
Kafka、ActiveMQ、RabbitMQ和RockerMQ都是消息队列的典型,每一种都有其自身的优势和劣势。本文我用自己编写的Buffer类模拟消息队列,如果是企业级需要上线的应用,一般都是基于业界已有的MQ框架上开发。
需求原型
- N个Client从标准输入接收数据,然后连续不断的发送到Server端;
- Server端接收来自每个Client的数据,将数据中的小写字母全部转换成大写字母,其他字符保持不变,最后把转换结果发送给对应的Client。
需求分解
- 拿到需求,第一步要做的就是分析需求并选择合适的设计架构,考虑到Server需要和Client进行通信,Client来自四面八方,端对端通信自然选择TCP,因此Server端需要能够监听新的连接请求和已有连接的业务请求;
- 又由于Server需要响应多个Client的业务请求,我们希望把业务处理交给Server端的工作线程(消费者)来做;
- 同时还需要一个IO线程负责监听Socket描述符,当IO线程监听到已有连接的业务请求时,立即把请求内容封装成一个任务推入消息队列尾;
- IO线程与工作线程互斥访问消息队列,当然工作线程消费一个任务或者IO线程添加一个任务都需要通知对方,也就是同步;
- 工作线程处理完毕后,把处理结果交给IO线程,由IO线程负责把结果发送给对应的Client,也就是IO线程与工作线程的分离,这里工作线程通知IO线程的方式我用eventfd来实现;
- 我们希望引入Log4cpp记录服务端的日志,并能够保存到文件中;
- 分析完这些,一个整体架构和大体的样子在脑海中就已经形成了,接着就需要编写设计文档和画流程图、类图和时序图了。
详细设计文档
1.UML静态类图:

2.UML动态时序图:

效果
1.如图,开了三个Client,运行结果正确:

2.Server端通过Log4cpp把日志写到文件中:

源码获取
https://github.com/icoty/cs_threadpool_epoll_mq
目录结构
.
├── client // 客户端Demo
│ ├── Client.cc
│ ├── Client.exe
│ ├── client.sh // 进入该目录下启动Client Demo: sh client.sh
│ ├── Log4func.cc // 引入日志模块重新疯转
│ ├── Log4func.h
│ └── Makefile // 编译方式:make
├── conf
│ └── my.conf // IP,Port配置文件, 从这里进行修改
├── include // 头文件
│ ├── Configuration.hpp // 配置文件,单例类,my.conf的内存化
│ ├── FileName.hpp // 全局定义,Configuration会用到
│ ├── log // 日志模块头文件
│ │ └── Log4func.hpp
│ ├── net // 网络框架模块头文件
│ │ ├── EpollPoller.hpp
│ │ ├── InetAddress.hpp
│ │ ├── Socket.hpp
│ │ ├── SockIO.hpp
│ │ ├── TcpConnection.hpp
│ │ └── TcpServer.hpp
│ ├── String2Upper.hpp // 工作线程转换成大写实际走的这里面的接口
│ ├── String2UpperServer.hpp // Server端的整个工厂
│ └── threadpool // 线程池、锁、条件变量和消息队列的封装
│ ├── Buffer.hpp
│ ├── Condition.hpp
│ ├── MutexLock.hpp
│ ├── Noncopyable.hpp
│ ├── Pthread.hpp
│ ├── Task.hpp
│ └── Threadpool.hpp
├── log // Server端的日志通过Log4cpp记录到这个文件中
│ └── log4test.log
├── Makefile // 编译方式:make
├── README.md
├── server // server端Demo
│ ├── server.exe
│ └── server.sh // 进入该目录下启动Server Demo:sh server.sh
└── src // 源文件
├── Configuration.cpp
├── log
│ └── Log4func.cpp
├── main.cpp
├── net
│ ├── EpollPoller.cpp
│ ├── InetAddress.cpp
│ ├── Socket.cpp
│ ├── SockIO.cpp
│ ├── TcpConnection.cpp
│ └── TcpServer.cpp
├── String2Upper.cpp
├── String2UpperServer.cpp
└── threadpool
├── Buffer.cpp
├── Condition.cpp
├── MutexLock.cpp // MutexLockGuard封装
├── Pthread.cpp
└── Threadpool.cpp
参考文献
[1] UNIX环境高级编程第3版
[2] cpp reference
[3] UML时序图
[4] Log4cpp官网下载
[5] Log4cpp安装
基于线程池、消息队列和epoll模型实现并发服务器架构的更多相关文章
- HQueue:基于HBase的消息队列
HQueue:基于HBase的消息队列 凌柏 1. HQueue简介 HQueue是一淘搜索网页抓取离线系统团队基于HBase开发的一套分布式.持久化消息队列.它利用HTable存储消息数据 ...
- 设计模式:基于线程池的并发Visitor模式
1.前言 第二篇设计模式的文章我们谈谈Visitor模式. 当然,不是简单的列个的demo,我们以电商网站中的购物车功能为背景,使用线程池实现并发的Visitor模式,并聊聊其中的几个关键点. 一,基 ...
- 基于线程池的多并发Socket程序的实现
Socket“服务器-客户端”模型的多线程并发实现效果的大体思路是:首先,在Server端建立“链接循环”,每一个链接都开启一个“线程”,使得每一个Client端都能通过已经建立好的线程来同时与Ser ...
- 【Java TCP/IP Socket】基于线程池的TCP服务器(含代码)
了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...
- Windows 消息以及消息处理算法--线程和消息队列详解
Windows以消息驱动的方式,使得线程能够通过处理消息来响应外界. Windows 为每个需要接受消息和处理消息的线程建立消息队列(包括发送消息队列,登记消息队列,输入消息队列,响应消息队列),其中 ...
- 深入浅出Win32多线程设计之MFC的多线程-线程与消息队列(经典)
1.创建和终止线程 在MFC程序中创建一个线程,宜调用AfxBeginThread函数.该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程. 工作者线程 CWinThread ...
- 基于线程池的多线程售票demo2.0(原创)
继上回基于线程池的多线程售票demo,具体链接: http://www.cnblogs.com/xifenglou/p/8807323.html以上算是单机版的实现,特别使用了redis 实现分布式锁 ...
- 基于线程池的多线程售票demo(原创)
废话不多说,直接就开撸import org.springframework.util.StopWatch;import java.util.concurrent.*;/** * 基于线程池实现的多线程 ...
- requests模块session处理cookie 与基于线程池的数据爬取
引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不到我们想要的目的,例如: #!/usr/bin/ ...
随机推荐
- Python 之并发编程之线程中
四.线程锁lock(线程的数据安全) 在数据量较大的时候,线程中的数据会被并发,所有数据会不同步,以至于数据会异常. 下面还介绍了两种的上锁方法. 例: from threading import T ...
- 学习 Python,怎能不懂点PEP 呢?
或许你是一个初入门 Python 的小白,完全不知道 PEP 是什么.又或许你是个学会了 Python 的熟手,见过几个 PEP,却不知道这玩意背后是什么.那正好,本文将系统性地介绍一下 PEP,与大 ...
- 神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程
问题背景 对于 MySQL 的 JOIN,不知道大家有没有去想过他的执行流程,亦或有没有怀疑过自己的理解(自信满满的自我认为!):如果大家不知道怎么检验,可以试着回答如下的问题 驱动表的选择 MySQ ...
- Preparing for the interview of FLAG and USDA
7,Dynamic Programming 1,Unique Paths A robot is located at the top-left corner of a m x n grid (mark ...
- LoadRunner的Capture Level
场景:录制loadrunner的web站点 问题:录制的过程中发现除了页面正常的请求外还有些看不懂的请求(包含乱码),脚本如下: web_url("WebTours", " ...
- 【剑指Offer面试编程题】题目1506:求1+2+3+...+n--九度OJ
题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 输入: 输入可能包含多个测试样例. 对于每个 ...
- css height VS min-height
height:容器高度固定(值是百分比时除外): min-height:容器高度小于该值时取该值,大于该值时按实际的值.应用:页面中页脚置底.
- c++中的Exceptions异常处理(翁恺c++公开课[36])
Exceptions用于处理Run-time Error: //文件读取的异常捕获伪代码 try{ open the file; determine its size; allocate that m ...
- 帆软FineReport报表使用小技巧
1.IF函数写法: =IF(E3=0 && F3=0 && G3=0,1,0)
- C++ class without pointer members
写在前面 Object Oriented class 的分类:带指针的class和不带指针的class, class 的声明 这里有一个inline的概念,写在类里面的默认为inl ...