加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 电商 > 正文

Web服务端性能提升实践

发布时间:2021-01-20 21:08:01 所属栏目:电商 来源:网络整理
导读:《Web服务端性能提升实践》要点: 本文介绍了Web服务端性能提升实践,希望对您有用。如果有疑问,可以联系我们。 随着互联网的不断发展,日常生活中越来越多的需求通过网络来实现,从衣食住行到金融教育,从口袋到身份,人们无时无刻不依赖着网络,而且越来越多的

在Go语言中,应用程序并发处理的部分被称作 goroutines(协程),它可以进行更有效的并发运算.在协程和操作系统线程之间并无一对一的关系:协程是根据一个或多个线程的可用性,映射(多路复用,执行于)在他们之上的;协程调度器在 Go?运行时很好的完成了这个工作.协程是轻量的,比线程更轻.它们痕迹非常不明显(使用少量的内存和资源):使用 4K 的栈内存就可以在堆中创建它们.因为创建非常廉价,必要的时候可以轻松创建并运行大量的协程(在同一个地址空间中 100,000 个连续的协程).并且它们对栈进行了分割,从而动态的增加(或缩减)内存的使用;栈的管理是自动的,但不是由垃圾回收器管理的,而是在协程退出后自动释放.协程可以运行在多个操作系统线程之间,也可以运行在线程之内,让你可以很小的内存占用就可以处理大量的任务.由于操作系统线程上的协程时间片,你可以使用少量的操作系统线程就能拥有任意多个提供服务的协程,而且 Go?运行时可以聪明地意识到哪些协程被阻塞了,暂时搁置它们并处理其他协程.甚至,程序可以在不同的处理器和计算机上同时执行不同的代码段.

我们通常想将一个长计算过程切分成几块,然后让每个goroutine各自负责一块工作,这样对于单一请求的响应时间有成倍的提升.

举个例子,有一个任务分3个阶段,a阶段去数据库a中取数据,b阶段去数据库b中取数据,c阶段合并数据返回.我们启动goroutine以后a、b阶段可以一起进行,极大地缩短了响应时间.

说白了就是部分计算过程由串行转换为并行,一个任务不需要等待其他无关的任务执行完在执行,实际计算中程序的并行执行会更有用处.

关于这部分佐证的数据就不在这边过多叙述了,感兴趣的同学可以自己看一下这方面的资料.比如Web服务端由Ruby切换为Go性能提升15倍的老故事(Ruby使用的是绿色线程,即只有一个CPU得到利用).虽然这个故事可能有点夸大,但是并行带来的性能提升是毫无疑问的.(Ruby切换为Go:http://www.vaikan.com/how-we-went-from-30-servers-to-2-go/).

3. 磁盘I/O对性能的影响

(1) 问题

磁盘读取数据靠的是机械运动,每次读取数据花费的时间可以分为寻道时间、旋转延迟、传输时间三个部分,寻道时间指的是磁臂移动到指定磁道所需要的时间,主流磁盘一般在5ms以下;旋转延迟就是我们经常听说的磁盘转速,比如一个磁盘7200转,表示每分钟能转7200次,也就是说1秒钟能转120次,旋转延迟就是1/120/2 = 4.17ms;传输时间指的是从磁盘读出或将数据写入磁盘的时间,一般在零点几毫秒,相对于前两个时间可以忽略不计.那么访问一次磁盘的时间,即一次磁盘I/O的时间约等于9ms(5ms+4.17ms)左右,听起来还挺不错的,但要知道一台500 -MIPS的机器每秒可以执行5亿条指令,因为指令依靠的是电的性质,换句话说执行一次I/O的时间可以执行40万条指令,数据库动辄十万百万乃至千万级数据,每次9毫秒的时间,显然是个灾难.

(2) 解决办法

磁盘I/O对服务器性能的影响没有根本的解决办法,除非你把磁盘扔掉,换成别的东西.我们能在网上搜到各种存储介质的响应速度与价格,如果你有钱,你就可以任性的更换存储介质.

在不更换存储介质的条件下,我们可以减少应用程序对磁盘的访问次数,比如设置缓存,还可以把部分磁盘I/O放到请求周期外,比如用队列和栈来处理数据的I/O等.

4. 优化数据库查询

随着业务开发模式的变化,敏捷式开发被越来越多的团队采用,周期越来越短,很多数据库查询语句都是按照业务逻辑来写,时间久了常常就忽略了SQL查询的格式问题,造成数据库压力的增加,使数据库查询的响应变慢.这里简单介绍MySQL数据库中,几条被我们忽略的常见问题和优化方式:

  1. 最左前缀匹配原则,非常重要的原则,MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,d,c)的索引则都可以用到,a,d的顺序可以任意调整.
  2. 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录.
  3. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销.这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了.
  4. 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大.所以语句应该写成create_time = unix_timestamp(’2014-05-29’);应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用.
  5. 索引而进行全表扫描,如:

    select id from t where num is null

    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

    select id from t where num=0

  6. 应尽量避免在 where 子句中使用 or 来链接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
    select id from t where num=10 or num=20
    可以这样查询:

    select id from t where num=10 union all select id from t where num=20?

  7. 下面的查询也将导致全表扫描(不能前置百分号):
    select id from t where name like ‘%abc%’
    若要提高效率,可以考虑全文检索.
  8. in 和 not in 也要慎用,否则会导致全表扫描,如:
    select id from t where num in(1,2,3)
    对于连续的数值,能用 between 就不要用 in 了:
    select id from t where num between 1 and 3

文章来自微信公众号:互联网架构师

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读