基于线程池、消息队列和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/ ...
随机推荐
- How2J学习java-1、环境配置
JDK环境变量配置分下载,配置,验证三个步骤. 一.首先需要到JDK下载网站下载所需的JDK版本可根据更新来定.主流的开发工具Idear下载. 1.首先看配置成功后的效果 点WIN键->运行(或 ...
- uniGUI之通过URL控制参数(25)
通过URL代入参数,在代码中读取,如: http://localhost:8077/?ServerPort=212&&ServerIP=192.168.31.12 procedure ...
- shell coding about mac ox
1, mac path---http://blog.csdn.net/playstudy/article/details/50149021 Mac系统的环境变量,加载顺序为:/etc/profile ...
- cin和cout输⼊输出
写再最前面:摘录于柳神的笔记: 就如同 scanf 和 printf 在 stdio.h 头⽂件中⼀样, cin 和 cout 在头⽂件 iostream ⾥⾯,看名字就知 道, io 是输⼊输出 ...
- LPS(最长回文子序列)
(注意:我发现最长回文子序列(Longest Palindromic Subsequence)问题与最长回文子串(Longest Palindromic Substring)不一样,子序列不要求下标一 ...
- [zlib] CMake + VS2015 下编译zlib,及使用小例
下载与解压 可以到zlib官网 http://zlib.net/ 下载,这个没有被墙的,如果下载,试一下换个网络再访问.因为我在公司的网络是访问不了的. 我当前使用的是 zlib1.2.11版本. 下 ...
- Xcode Edit Schemes
关于本文:有关“Xcode Edit Schemes”的设置,还是有很大的学问的.由于时间关系,我一点一点的补充. 1.在开发的时候,至少将Run的Build Configuration设置为Debu ...
- Python中安装框架如何换源以及升级
想安装tornado框架,但总是有奇怪错误,如下: 如果按照默认的下载源,就会死活不成功,出现 Traceback (most recent call last): File "e:\pyt ...
- OPC DA通讯 KEP6.4 DCOM 配置脚本
在OPC DA通讯测试时总是避免不了要配置DCOM,我习惯是在虚拟机中装这些通讯测试软件,每次安装都需要再次手动配置,感觉很是麻烦 因此,查找资料,了解到可以用dcomperm这个软件来在命令行下进行 ...
- 一 注册功能&登录功能,权限拦截
注册功能: 前端JSP:提供表单注册信息以及访问路径,发送请求到Strus2. Struts2 : 通过模型驱动接收并封装User对象,Spring依赖注入(无参构造+setter方法)获取业务层Us ...