• 高并发服务的优化经验


    一:向关系型数据库sayno

           一个真正的大型互联网面向c端的服务都不会直接使用数据库作为自己的存储系统,无论你是采用的是分库分表还是底层用了各种优秀的连接池等,mysql/oracle在面对大型在线服务是存在天然的劣势,再如何优化,也难以抵挡qps大于50万流量带来的冲击。所以换个思路,我们必须使用nosql类缓存系统,比如redis/mermCache等作为自己的"数据库",而mysql等关系型数据库只是一种兜底,用于异步去写作为数据查询的备份系统。

    二:多级缓存

              都知道缓存是高并发提高性能的利器之一。而如何使用好缓存进而利用好多级缓存,是需要我们去思考的问题。redis目前是缓存的第一首选.单机可达6-8万的qps,在面对高并发的情况下,我们可以手动的水平扩容,以达到应对qps可能无线增长的场景。但是这种做法也存在弊端,因为redis是单线程的,并且会存在热点问题。虽然redis内部用crc16算法做了hash打散,但是同一个key还是会落到一个单独的机器上,就会使机器的负载增加,redis典型的存在缓存击穿和缓存穿透两个问题,尤其在秒杀这个场景中,如果要解决热点问题,就变的比较棘手。这个时候多级缓存就必须要考虑了,典型的在秒杀的场景中,单sku商品在售卖开始的瞬间,qps会急剧上升.而我们这时候需要用memeryCache来挡一层,memeryCache是多线程的,比redis拥有更好的并发能力,并且它是天然可以解决热点问题的。有了memeryCache,我们还需要localCache,本地缓存,这是一种以内存换速度的方式。本地缓存会接入用户的第一层请求,如果它找不到,接下来走memeryCache,然后走redis,这套流程下来可以挡住百万的qps

    三:多线程

            使用多线层一定要做好监控,你需要随时知道线程的状态,如果线程数和queueSize设置的不恰当,将会严重影响业务~ 当然多线程也要分场景,如果为了多线程而多线程反而是一种浪费,因为多线程调度的时候会造成线程在内核态和用户态之间来回切换,如果使用不当反而会有反作用。

    四: 降级和熔断

             面对不可控的巨大流量请求很有可能会击垮服务器的数据库或者redis,使服务器宕机或者瘫痪造成不可挽回的损失。因为我们服务的本身需要有防御机制,以抵挡外部服务对于自身的侵入导致服务受损引起连带反应。降级和熔断有所不同,两者的区别在于降级是将一些线上主链路的功能关闭,不影响到主链路.熔断的话,是指A请求B,B检测到服务流量多大启动了熔断,那么请求会直接进入熔断池,直接返回失败。

    五: 优化IO

    很多人都会忽视IO这个问题,频繁的建联和断联都是对系统的重负。在并发请求中,如果存在单个请求的放大效那么将会使io呈指数倍增加。

    六: 慎用重试

    重试作为对临时异常的一种处理的常见手法,常见应对的方式是请求某个服务失败或者写数据库了重新再试,使用重试一定要注意以下几点①控制好重试次数②重试的间隔时间得衡量好③是否重试要做到配置化。

    七:边界case的判断和兜底

    空数组进行判空  等等

    八:学会优雅的打印日志

    如果全量打印日志对于线上来说就是一种灾难,有以下缺点①严重占用磁盘,估算以下,如果接口的qps在20万左右,日志一秒就几千兆,一天下来就是上千GB ②大量的日志需要输出,占用了程序IO,增加了接口的RT(响应时间) 如果需要解决这个问题,①我们可以利用限流组件来实现一个基于限流的日志组件,令牌桶算法可以限制打印日志的流量,比如一秒只允许打印一条日志 ②基于白名单的日志打印,线上配置了白名单用户才可以打印出来,节省了大量了无效日志输出

  • 相关阅读:
    Spring IOC之容器概述
    SQL Server之记录筛选(top、ties、offset)汇总
    [译]Java 设计模式之单例
    [译]Java 设计模式之适配器
    [译]Java 设计模式之桥接
    [译]Java 设计模式之装饰器
    [译]Java 设计模式 之模板方法
    [译]Java 设计模式之抽象工厂
    [译]Java 设计模式之工厂
    传入两个字符串,确认其中一个字符串重新排序后能否变为另一个字符串(也就是两个字符串相等)
  • 原文地址:https://www.cnblogs.com/KL2016/p/16290708.html
Copyright © 2020-2023  润新知