go-channel处理高并发请求
go-channel处理高并发请求
最近看了一篇文章讲解怎样使用go-channel的,周末就花了点时间学习了一下,文章原文地址:
http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/ ,然后自己进行了一个简单的性能测试。
一、Channel简介
下面是go by example中的 一个简单的channel使用的例子:
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
通道 是连接多个 Go 协程的管道。你可以从一个 Go 协程将值发送到通道,然后在别的 Go 协程中接收。使用 make(chan val-type) 创建一个新的通道。通道类型就是他们需要传递值的类型。使用 channel <- 语法 发送 一个新的值到通道中。这里我们在一个新的 Go 协程中发送 "ping" 到上面创建的messages 通道中。使用 <-channel 语法从通道中 接收 一个值。这里将接收我们在上面发送的 "ping" 消息并打印出来。我们运行程序时,通过通道,消息 "ping" 成功的从一个 Go 协程传到另一个中。
$ go run channels.go
ping
默认发送和接收操作是阻塞的,直到发送方和接收方都准备完毕。这个特性允许我们,不使用任何其它的同步操作,来在程序结尾等待消息 "ping"。channel也有带缓冲的可以不阻塞直接写到缓冲去(在缓冲没有满的情况下)。更多例子请参考: https://books.studygolang.com/gobyexample/channels/
二、处理包并发请求
上面那篇作者写的分钟处理百万请求文章,代码摘抄了一部分进行分析。下面是关键的几个数据结构:
- 任务,用来需要表示一个需要处理的逻辑
// Job代表一个任务,根据自己需求定义
type Job struct {
Id string
Payload string
}
- worker, 用来处理任务的实例
// Worker用来处理job的实例
type Worker struct {
WorkerPool chan chan Job //需要注册到的worker池
JobChannel chan Job //用来接受任务的通道
quit chan bool
}
- Dispatcher, 用来分发job的实例
type Dispatcher struct {
WorkerPool chan chan Job //用来注册worker的池
MaxWorkers int //worker最大个数
}
初始化逻辑
func NewDispatcher(maxWorkers int) *Dispatcher {
pool := make(chan chan Job, maxWorkers)
return &Dispatcher{
WorkerPool: pool, //初始化worker池
MaxWorkers: maxWorkers,
}
}
func (d *Dispatcher) Run() {
for i := 0; i < d.MaxWorkers; i++ {
//对每一个worker进行初始化,也就是将worker注册到池中,更直接点就是将每个worker的jobChannel放入到池中
worker := NewWorker(d.WorkerPool)
worker.Start()
}
go d.dispatch()
}
func NewWorker(workerPool chan chan Job) *Worker {
return &Worker{
WorkerPool: workerPool,
JobChannel: make(chan Job),
quit: make(chan bool),
}
}
//Start函数,启一个goroutine, 启动的时候将自己注册到worker池当中,然后就等待job被放到自己的jobChannel中
//一旦jobChannel中有job放入的时候,就开始处理这个job
//同时加入了一个quit channel可以用来控制销毁这个worker
func (w *Worker) Start() {
go func() {
for {
w.WorkerPool <- w.JobChannel //注册当前这个worker到worker池中,
// 也就是将自己的jobChannel放入到池中,用来接收job
select {
case job := <-w.JobChannel:
//channel中放入了一个job
if _, err := job.Done(); err != nil {
//处理这个job
}
case <-w.quit:
// 收到停止的信号,销毁这个worker
return
}
}
}()
}
任务分发逻辑
func (d *Dispatcher) dispatch() {
for {
select {
case job := <-JobQueue:
// 收到一个job
go func(job Job) {
// 从worker池中,选取一个worker的jobChannel,如果worker池中是空的,则会阻塞在这里
jobChannel := <-d.WorkerPool
// 将job放入到其中一个worker的jobChannel中,等待这个worker进行处理
jobChannel <- job
}(job)
}
}
}
三、测试
1、测试工具
ab, 下载地址: https://www.apachehaus.com/cgi-bin/download.plx
2、测试结果
$ ./abs -n 100000 -c 1000 "http://127.0.0.1:8080/job"
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8080
Document Path: /job
Document Length: 0 bytes
Concurrency Level: 1000
Time taken for tests: 51.913 seconds
Complete requests: 100000
Failed requests: 1
(Connect: 1, Receive: 0, Length: 0, Exceptions: 0)
Total transferred: 7500000 bytes
HTML transferred: 0 bytes
Requests per second: 1926.28 [#/sec] (mean)
Time per request: 519.134 [ms] (mean)
Time per request: 0.519 [ms] (mean, across all concurrent requests)
Transfer rate: 141.09 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 7.2 0 1007
Processing: 58 497 187.4 429 1448
Waiting: 6 348 195.3 315 1113
Total: 58 497 187.5 430 1449
Percentage of the requests served within a certain time (ms)
50% 430
66% 435
75% 441
80% 446
90% 901
95% 970
98% 1014
99% 1076
100% 1449 (longest request)
测试结果感觉有点不太理想,不知道是不是因为电脑性能的原因还是参数设置的问题。在不用go-channel的测试和这个性能差不多,大家可以把这个代码下载下来自己测试一下,比对一下结果看看有没有优化的空间。
完整代码下载地址: https://gitee.com/ncuzhangben/GoStudy/tree/master/go-channel
go-channel处理高并发请求的更多相关文章
- Web大规模高并发请求和抢购的解决方案
电商的秒杀和抢购,对我们来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要.这次我们 ...
- 达达O2O后台架构演进实践:从0到4000高并发请求背后的努力
1.引言 达达创立于2014年5月,业务覆盖全国37个城市,拥有130万注册众包配送员,日均配送百万单,是全国领先的最后三公里物流配送平台. 达达的业务模式与滴滴以及Uber很相似,以众包的方式利 ...
- Jexus 高并发请求的优化技巧 笔记
Jexus web server 5.1 每个工作进程的最大并发数固定为1万,最多可以同时开启4个工作进程,因此,每台Jexus V5.1服务器最多可以到支持4万个并发连接.但是,按照linux系统的 ...
- Thinkphp5 用ab压力测试工具测试高并发请求
上篇文章[Thinkphp5实现悲观锁]已介绍过thinkphp5使用悲观锁实现高并发的场景,这篇文章将实际测试下. 在shell里进入到apache的bin目录,输入以下url: ab -n 100 ...
- nginx处理高并发请求强于apache
ginx 不同于 Apache2 的一点就是,Nginx 采用单线程,非阻塞,异步 IO 的工作模型. Apache2 对于每一个请求,都会创建一个新进程或线程,会浪费很多内存和 CPU 时间,而 N ...
- 支持10W高并发请求的IIS Web服务器常用设置
支持高并发的IIS Web服务器常用设置 适用的IIS版本:IIS 7.0, IIS 7.5, IIS 8.0 适用的Windows版本:Windows Server 2008, Windows ...
- asp.net c# 通过消息队列处理高并发请求(以抢小米手机为例)
网站面对高并发的情况下,除了增加硬件, 优化程序提高以响应速度外,还可以通过并行改串行的思路来解决.这种思想常见的实践方式就是数据库锁和消息队列的方式.这种方式的缺点是需要排队,响应速度慢,优点是节省 ...
- 【apache】apache模拟高并发请求
目的:测试程序的性能 运用的工具是apache的ab工具,装有apache服务器的一般都有ab工具. lamp命令: ab -c 10 -n 100 "http://a.ilanni.com ...
- PHP中利用redis实现消息队列处理高并发请求
将请求存入redis 为了模拟多个用户的请求,使用一个for循环替代 //redis数据入队操作 $redis = new Redis(); $redis->connect('127.0.0.1 ...
随机推荐
- Spark性能优化指南——基础篇(转)
[转]Spark性能优化指南——基础篇 http://mp.weixin.qq.com/s?__biz=MjM5NDMwNjMzNA==&mid=2651805828&idx=1&am ...
- 爬虫多线程模板,xpath,etree
class QuiShi: def __init__(self): self.temp_url = "http://www.lovehhy.net/Joke/Detail/QSBK/{0}& ...
- 力扣(LeetCode)猜数字大小 个人题解
我们正在玩一个猜数字游戏. 游戏规则如下:我从 1 到 n 选择一个数字. 你需要猜我选择了哪个数字.每次你猜错了,我会告诉你这个数字是大了还是小了.你调用一个预先定义好的接口 guess(int n ...
- vim编辑中断后,重新编辑的警告删除
使用vim 编辑,遇到突然中断,比如ssh远程时断网了. 如果再次ssh连接,重新vim 打开之前在编辑的文件,会有类似如下的警告 这是因为vim会在被编辑的目录下新建一个名为.filename.sw ...
- python进程概要
进程 狭义:正在运行的程序实例. 广义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,他是操作系统动态执行的基本单元. python的进程都是并行的. 并行:两个进程同时执行一起走. ...
- PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)
前文讲述了怎么用ArcMap制作了测试数据,并导入了PostGIS,接下来我们需要结合PgRouting插件,对入库的数据再进行一下处理. 1.在pgAdmin中,执行下面的sql语句 --添加起点字 ...
- Android加载大量图片内存溢出解决办法
当我们在做项目过程中,一遇到显示图片时,就要考虑图片的大小,所占内存的大小,原因就是Android分配给Bitmap的大小只有8M,试想想我们用手机拍照,普通的一张照片不也得1M以上,所以androi ...
- Java描述设计模式(24):备忘录模式
本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 常见的视频播放软件都具备这样一个功能:假设在播放视频西游记,如果这时候切换播放视频红楼梦,当再次切回播放西游记时, ...
- Java从零开始(前篇)
前篇 自述 本人大三通信专业,咸鱼一枚,对专业所学傅里叶变换等实在提不起兴趣. 幸好略学过c系列语言,但也浅尝辄止,浑浑噩噩,深入之后被指针弄地晕头转向. 想在毕业后转行计算机,于是我下定决心从零开始 ...
- Maven入门【小白千万别点进】
曾经有个女孩问我为什么要学Maven,我吧唧嘴就怼:Maven项目没有jar包它不香嘛,照样运行它不香嘛?如果让我一句话形容Maven,我会这样形容:"妈妈再也不用担心小明拿U盘去小红电脑里 ...