首页 文章 精选 留言 我的

精选列表

搜索[单机],共4013篇文章
优秀的个人博客,低调大师

Go 自带的 http/server.go 的连接解析 与 如何结合 master-worker 并发模式,提高单机并发能力

作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguanh/ GitHub : https://github.com/af913337456/ 腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities 关于 server.go 源码的解析可以去搜下,已经有很多且还不错的文章。 正文: 从我们启动http.ListenAndServe(port,router)开始,server.go 内部最终在一个for 循环中的 accept 方法中不停地等待客户端的连接到来。 每接收到一个accept 就启动一个 gorutine 去处理当前ip的连接。也就是源码里的go c.serve(ctx)。这一个步骤在 c.serve(ctx) 它并不是简单的形式: 请求-->处理请求-->返回结果-->断开这个连接-->结束当前的 gorutine 根据我的调试结果与源码分析显示,正确的形式是下面这样的: 为每一个连接的用户启动了一个长连接,serve 方法内部有个超时的设置是c.rwc.SetReadDeadline(time.Time{}),这样子的情况,如果内部不出错,当前的连接断开的条件是客户端自己断开,或nat超时。 这个连接建立后,以ip为单位,当前的客户端,此时它的所有http请求,例如get,post,它们都会在这个启动的gorutine 内进行分发与被处理。 也就是说,同一个ip,多个不同的请求,这里不会触发另一个 accept,不会再去启动一个go c.serve(ctx) 上述我们得出结论: 如果有 100万个 accept,就证明有100万个连接,100万个ip与当前server连接。即是我们说的百万连接 百万连接 不是百万请求 每一个连接,它可以进行多个http请求,它的请求都在当前启动这个连接的gorutine里面进行。 c.serve(...) 源码中的for 死循环就是负责读取每个请求再分发 for { w, err := c.readRequest(ctx) // 读取一个 http 请求 //... ServeHTTP(...) } 我们的100万 连接里面,有可能并发更多的请求,例如几百万请求,一个客户端快速调用多个请求api 图解总结 结合 master-worker 并发模式 根据我们上面的分析,每一个新连接到来,go 就会启动一个 gorutine,在源码里面也没有看到有一个量级的限制,也就是达到多少连接就不再接收。我们也知道,服务器是有处理瓶颈的。 所以,在这里插播一个优化点,就是在server.go 内部做一个连接数目的限制。 master-worker 模式本身是启动多个worker 线程,去并发读取有界队列里面的任务,并执行。 我自身已经实现了一个go版本的master-worker,做过下面的尝试: 在 go c.serve(ctx) 处做修改,如下。 if srv.masterWorkerModel { // lgh --- way to execute PoolMaster.AddJob( masterworker.Job{ Tag:" http server ", Handler: func() { c.serve(ctx) fmt.Println("finish job") // 这一句在当前 ip 断开连接后才会输出 }, }) }else{ go c.serve(ctx) } func (m Master) AddJob(job Job) { fmt.Println("add a job ") m.JobQueue <- job // jobQueue 是具备缓冲的 } // worker func (w Worker) startWork(master *Master) { go func() { for { select { case job := <-master.JobQueue: job.doJob(master) } } }() } // job func (j Job) doJob(master *Master) { go func() { fmt.Println(j.Tag+" --- doing job...") j.Handler() }() } 不难理解它的模式。 现在我们使用生产者--消费者模式进行假设,连接的产生是生产者,<-master.JobQueue 是消费者,因为每一次消费就是启动一个处理的gorutine。 因为我们在accept 一个请求到<-master.JobQueue,管道输出一个的这个过程中,可以说是没有耗时操作的,这个job,它很快就被输出了管道。也就是说,消费很快,那么实际的生产环境中,我们的worker工作协程启动5~10个就有余了。 考虑如果出现了消费跟不上的情况,那么多出来的job将会被缓冲到channel里面。这种情况可能出现的情景是: 短时间十万+级别连接的建立,就会导致worker读取不过来。不过,即使发生了,也是很快就取完的。因为间中的耗时几乎可以忽略不计! 也就说,短时间大量连接的建立,它的瓶颈在队列的缓冲数。但是即使瓶颈发生了,它又能很快被分发处理掉。所以说: 我的这个第一点的尝试的意义事实上没有多大的。只不过是换了一种方式去分发go c.serve(ctx)。 这个是第二种结合方式,把master-worker放置到ServeHTTP的分发阶段。例如下面代码,是常见的http handler写法,我们就可以嵌套进去。 func (x XHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { //... if x.MasterWorker { poolMaster.AddJob(master_worker.Job{ Tag:"normal", XContext:xc, Handler: func(context model.XContext) { x.HandleFunc(w,r) }, }) return } x.HandleFunc(w,r) //... } 这样的话,我们就能控制所有连接的并发请求最大数。超出的将会进行排队,等待被执行,而不会因为短时间 http 请求数目不受控暴增 而导致服务器挂掉。 此外上述第二种还存在一个:读,过早关闭问题,这个留给读者尝试解决。 如果您认为这篇文章还不错或者有所收获,您可以通过扫描一下下面的支付宝二维码 打赏我一杯咖啡【物质支持】,也可以点击右下角的【推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力、

优秀的个人博客,低调大师

Spark技术在京东智能供应链预测的应用——按照业务进行划分,然后利用scikit learn进行单机训练并预测

3.3 Spark在预测核心层的应用 我们使用Spark SQL和Spark RDD相结合的方式来编写程序,对于一般的数据处理,我们使用Spark的方式与其他无异,但是对于模型训练、预测这些需要调用算法接口的逻辑就需要考虑一下并行化的问题了。我们平均一个训练任务在一天处理的数据量大约在500G左右,虽然数据规模不是特别的庞大,但是Python算法包提供的算法都是单进程执行。我们计算过,如果使用一台机器训练全部品类数据需要一个星期的时间,这是无法接收的,所以我们需要借助Spark这种分布式并行计算框架来将计算分摊到多个节点上实现并行化处理。 我们实现的方法很简单,首先需要在集群的每个节点上安装所需的全部Python包,然后在编写Spark程序时考虑通过某种规则将数据分区,比如按品类维度,通过groupByKey操作将数据重新分区,每一个分区是一个样本集合并进行独立的训练,以此达到并行化。流程如下图所示: 伪码如下: repartitionBy方法即设置一个重分区的逻辑返回(K,V)结构RDD,train方法是训练数据,在train方法里面会调用Python算法包接口。saveAsPickleFile是Spark Python独有的一个Action操作,支持将RDD保存成序列化后的sequnceFile格式的文件,在序列化过程中会以10个一批的方式进行处理,保存模型文件非常适合。 虽然原理简单,但存在着一个难点,即以什么样的规则进行分区,key应该如何设置。为了解决这个问题我们需要考虑几个方面,第一就是哪些数据应该被聚合到一起进行训练,第二就是如何避免数据倾斜。 针对第一个问题我们做了如下几点考虑: 被分在一个分区的数据要有一定的相似性,这样训练的效果才会更好,比如按品类分区就是个典型例子。 分析商品的特性,根据特性的不同选择不同的模型,例如高销商品和低销商品的预测模型是不一样的,即使是同一模型使用的特征也可能不同,比如对促销敏感的商品就需要更多与促销相关特征,相同模型相同特征的商品应倾向于分在一个分区中。 针对第二个问题我们采用了如下的方式解决: 对于数据量过大的分区进行随机抽样选取。 对于数据量过大的分区还可以做二次拆分,比如图书小说这个品类数据量明显大于其他品类,于是就可以分析小说品类下的子品类数据量分布情况,并将子品类合并成新的几个分区。 对于数据量过小这种情况则需要考虑进行几个分区数据的合并处理。 总之对于后两种处理方式可以单独通过一个Spark任务定期运行,并将这种分区规则保存。 摘自:http://www.infoq.com/cn/articles/application-of-spark--in-jingdong-supply-chain-forecasting 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/7349702.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册