让程序的性能提升10倍

公司有一个Web Service,访问量不大, 但也不算小, 每天几百万的量级。正常情况下, 平均每个请求响应的时间在200毫秒左右。

每天几百万的访问量, 那么程序每秒请求处理数量在几十个左右, 高峰期也就上百, 而服务器上php处理请求的进程数是大于这个数的,因此, 服务器的处理能力勉强能满足当前量级的请求, 除了少数时候高峰期会出现不稳定的状况, 大多数时候也算是相安无事, 但是从服务器失败请求的数量来看应该离服务器处理能力极限的临界点不远了。

这个Web Service有一个特点, 它并不是面向终端的 , 而是为另一套Web Service提供底层数据用, 那套Web Service会进行数据缓存,不会把所有数据请求转发到我们这里,它替我们挡掉了大部份压力。然而, 天有不测风云,某一天高峰期那套Web Service的缓存机制坏掉了, 所有数据请求全都转发到我们的Web Service上, 结果, 我们Web Service访问量成倍增长,服务器超出了承受能力的范围而无法正常响应,然后用户各种投诉,领导各种不满,压力自然而然就到了我的身上。

我分析了一下问题的原因,Web Service 每个请求的响应时间为200毫秒上下, 服务器的并发处理能力并不是很高, 也就是说在每个200毫秒内,服务器处理请求数量是有极限的, 当每200毫秒的请求量大于这个极限的时候, 后面进来的请求就不能被及时处理, 只能排队等待,这就跟堵车一下,车的数量远大于马路的吞吐量时,自然是越堵越多。堵车没有时间限制, 反正迟早能开走, 只是花点时间等待而已。 而服务器处理请求就不一样了,如果指定的时间范围内无法及时处理请求,那么这些请求就会坏掉, 也就是我们通常看到的502或者504。我们的服务器也是因为这个原因而出现了大量的坏掉的请求,导致业务受到影响。

整个Web Service大约有百分之八十流量是流向其中五个接口(页面)的,因此我只要集中优化这五个接口,将它们的响应时间降下来,那么服务器并发请求的处理能力将会得到提升。

这个Web Service是由php实现,近一年内也不断的在优化其性能,但总是无法彻底解决问题, 虽然服务器的并发处理能力得到了一定程度的提升, 但是, 每个请求的响应时长总是降不下去。 被逼无奈, 我决定以换技术重新实现的方式尝试着解决问题,毕竟高性能服务器的编写并非php所擅长的, 而golang似乎更加适合做这件事。

我仔细的看过这个Web Service的每一行php代码, 发现存在以下影响性能的问题

  1. 没有数据库连接池, 也没有单例, 每一次读写数据库都会简单粗暴的执行openconnection和close connection
  2. 使用memcached。我觉得memcached也影响性能,因为会有网络开销,如果不是多个程序共享内存需要, 根本没有必要使用, 但在php中却无法避免,因为php无法直接操作内存
  3. 没有多线程,没有办法并行处理问题, 如只能通过串行的方式从多个数据库中读取数据
  4. 编写代码时没有考虑到时间复杂度问题, 各种无意义的foreach太多

除了代码中存在的问题, php技术本身也有性能痛点存在, 如

  1. 解释执行代码, 但也没有像java一样的即时编译机制
  2. 请求必须通过apache和phpfpm服务器中转, 然后再交由php自身

而golang正好克服了这些问题

  1. 非常方便的使用数据库连接池
  2. 直接操纵内存, 不使用第三方缓存软件
  3. goroutine, 多线程中的战斗机
  4. 纯编译型语言, 跟C类似编译出来的就是最低层的机器码
  5. 程序本身就有Web服务器的功能, 不依赖第三方Web服务器

因此, 从理论上来讲, golang在性能方面完胜php。

因为只需要重写Web Service中的5个接口, 工作量并不算太大, 总共大概只花了2天的工作量就完全成了重写的工作,并且将旧的php版本中存在的问题全都避免掉。

将程序部署至生产环境后,我对两个版本的程序在性能上做了大致的对比

php

golang

php

golang

从图中可以看出,同样的功能, 同样的数据, 但是在请求的时间上却确差了许多倍。

在并发量处理方面, 我写了一段Java程序,开100个线程去请求测试环境下的接口, 代码大概长这个样子

php实现的版本, 在这段程序运行20秒左右的时间后,服务器就出现无法响应的状况,大致情况应该与之前线上服务事故原因相同,车太多, 路太小, 堵住了。

而golang的版本, 不管程序开多久, 都一直稳定的运行着, 程序的进程对于服务器资源也没有太大的消耗,因此可以断定,在真实的生产环境下golang写的版本的表现肯定将优于php版本。

现在, 使用golang新实现的版本还在测试当中, 需要确保接口返回的数据与php版本接口的返回的数据没有一毫偏差才可以正式切换服务。

系统还没有真式使用, 重写所带来的效果也还没有体现, 但是我还是义无反顾将这件事提前发在公众号上, 这充分的说明了, 我对于这次重写有足够的自信,对golang的表现也有充足的信心,让程序性能提升10是可以实现的。

原文发布于微信公众号 - 带你撸出一手好代码(gh_afab56b37671)

原文发表时间:2017-04-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏搜云库

分布式和集群区别?什么是云计算平台?分布式的应用场景?

分布式是指将一个业务拆分不同的子业务,分布在不同的机器上执行,集群是指多台服务器集中在一起,实现同一业务,可以视为一台计算机,一个云计算平台,就是通过一套软件系...

2855
来自专栏杨建荣的学习笔记

运维平台的建设思考-元数据管理(r7笔记第57天)

之前也写过一篇比较基本的文章,也算是自己对运维平台的一个基本思考。运维平台的建设思考(r6笔记第20天) 当然想法简单,而且缺乏实践,但是朝着这个方向迈进是没有...

4625
来自专栏社区的朋友们

漫谈分布式集群的负载均衡—口水篇

为了理解分布式集群这个概念,我们先说说这两个概念:“集群”和“分布式”。艺术来源于生活,计算机科学亦是如此。

1.2K0
来自专栏蓝天

测试 Linux 的可靠性

IBM Linux Technology Center (LTC) 成立于 1999 年 8 月,想让 Linux 成功的共同梦想使其与 Linux 开发团体直...

1693
来自专栏编程软文

小程序二维码和小程序带参数二维码生成

1.3K4
来自专栏杨建荣的学习笔记

数据库无响应问题的紧急处理和分析 (r10笔记第42天)

黄金周里处理了一起紧急的问题,在外面幸亏有同事帮忙协助,等我赶回家去,赶紧继续处理。 首先问题是在晚饭时间左右开始发生,但是过了没多久又恢复了,所以这个问题暂时...

33412
来自专栏WeTest质量开放平台团队的专栏

浅谈服务器性能测试的全生命周期——从测试、结果分析到优化策略

服务器性能测试是一项非常重要而且必要的工作,本文是作者Micheal在对服务器进行性能测试的过程中不断摸索出来的一些实用策略,通过定位问题,分析原因以及解决问题...

2674
来自专栏张戈的专栏

教你如何查看Linux的CPU负载

记得博主以前被问到 CPU 负载如何才算高的时候,出过一次糗,具体就不记录了。。。在网上找了一篇比较详细的 Linux 下的 CPU 负载算法教程,科普一下。不...

6196
来自专栏程序员的SOD蜜

探寻背后的机制化繁为简:网站程序升级不过是文件同步

苹果落到地上而不是天上,这是重力的作用; 树叶从树枝上飘落的样子谁也无法预测,这是混沌过程; 热恋中的恋人总是难分难舍,这是荷尔蒙等激素作用于下丘脑的结果; 。...

2305
来自专栏我是极客人

电脑技巧| 使用电脑的经验分享

由于你懂得的原因,我们无法去官网下载androidSDK,后来QT下载也要翻墙。下面是解决因“墙”无法下载资料的镜像站网址: 1.教育网主要镜像站 东北地区: ...

1642

扫码关注云+社区

领取腾讯云代金券