分享

高并发系统设计总结

 印度阿三17 2020-11-30

设计方法

  • Scale-out(横向扩展):分而治之是一种常见的高并发系统设计方法,采用分布式部署的方式把流量分流开,让每个服务器都承担一部分并发和流量。

  • 缓存:使用缓存来提高系统的性能,就好比用“拓宽河道”的方式抵抗高并发大流量的冲击。

  • 异步:在某些场景下,未处理完成之前我们可以让请求先返回,在数据准备好之后再通知请求方,这样可以在单位时间内处理更多的请求。

如何实现高性能

高并发系统设计的三大目标:高性能、高可用、可扩展

提高性能

  1. 提高系统的处理核心数

  2. 减少单次任务的响应时间

高可用

评判标准

  • MTBF(Mean Time Between Failure)是平均故障间隔的意思,代表两次故障的间隔时间,也就是系统正常运转的平均时间

  • MTTR(Mean Time To Repair)表示故障的平均恢复时间,也可以理解为平均故障时间。

设计思路

系统设计

  • failover(故障转移):主从转移,水平节点间转移。例如zookeeper的节点间的转移以及主机宕机后的,从机选举主机算法(ZAB)协议。通用的协议有Paxos,Raft等。

  • 超时控制:调用其他系统的时候,做好超时控制,避免其他系统宕机导致当前服务阻塞。

  • 降级:服务降级,腾出系统资源。比如在大促期间,将历史订单和物流查询服务降级,腾出必要的系统资源给下单功能。

  • 限流:限制过大的流量对系统的冲击,从而拖垮系统。制定策略,响应符合策略的请求,对不符合策略的请求直接返回错误。

系统运维

  • 系统灰度发布,提前演练

分布式数据库

数据库架构

  • 主从同步

  • 读写分离

数据库设计

  • 分表分库

  • 生成数据库唯一id:发号器(基于雪花算法);设计数据库自增id的初始值和自增步距;UUID(可以生成唯一ID,但是不建议做数据的唯一ID)

缓存

缓存种类

  • 静态缓存:指将热点查询数据,例如秒杀商品的商品详情页生成静态页面,然后缓存在Nginx服务器上,减少服务器端压力。

  • 分布式缓存:例如Redis。通过集群部署,一致性hash做负载均衡,突破单机限制,实现海量数据的缓存;满足静态缓存无法缓存动态数据的问题。

  • 热点本地缓存:将热点数据缓存在后端应用服务器上,减少数据库交互,提高响应速度。例如商城首页的推荐商品,可以缓存在本地热点数据中,每隔30s重新拉取一次最新数据。响应的组件有Guava Cache等。

缓存读写策略

  • Cache Aside(旁路缓存策略):当有数据更新时,在更新完数据库后,删除缓存中的对应数据。下次请求到的时候,再去装载。

  • Read/Write Through(读穿 / 写穿)策略:这个策略的核心原则是用户只与缓存打交道,由缓存和数据库通信,写入或者读取数据。

  • Write Back(写回)策略:这个策略的核心思想是在写入数据时只写入缓存,并且把缓存块儿标记为“脏”的。而脏块儿只有被再次使用时才会将其中的数据写入到后端存储中。即存放脏数据的缓存被再次用来load数据时,先将脏数据提交

缓存高可用

通过部署多个节点,同时设计一些方案让这些节点互为备份。这样,当某个节点故障时,它的备份节点可以顶替它继续提供服务。分布式缓存的高可用方案一般有:客户端方案,中间代理层方案和服务端方案。

  • 客户端方案就是在客户端配置多个缓存的节点,通过缓存写入和读取算法策略来实现分布式,从而提高缓存的可用性。通过数据分片,将数据分配到多个缓存主机上。分片算法可以采用一致性hash算法。单个缓存节点可采用主从集群的方式来保证缓存的可用性。

  • 中间代理层方案是在应用代码和缓存节点之间增加代理层,客户端所有的写入和读取的请求都通过代理层,而代理层中会内置高可用策略,帮助提升缓存系统的高可用。

  • 服务端方案就是 Redis 2.4 版本后提出的 Redis Sentinel 方案。

缓存穿透

缓存穿透其实是指从缓存中没有查到数据,而不得不从后端系统(比如数据库)中查询的情况。

缓存穿透的解决方案

  • 回种空值:从数据库中查询到空值或者发生异常时,我们可以向缓存中回种一个空值,避免缓存穿透。但是因为空值并不是准确的业务数据,并且会占用缓存的空间,所以我们会给这个空值加一个比较短的过期时间,让空值在短时间之内能够快速过期淘汰。

  • 使用布隆过滤器:我们把集合中的每一个值按照提供的 Hash 算法算出对应的 Hash 值,然后将 Hash 值对数组长度取模后得到需要计入数组的索引值,并且将数组这个位置的值从 0 改成 1。在判断一个元素是否存在于这个集合中时,你只需要将这个元素按照相同的算法计算出索引值,如果这个位置的值为 1 就认为这个元素在集合中,否则则认为不在集合中。
    缺陷: 1,存在hash冲突,数据标志位有可能是错误的;2,不支持删除元素。
    使用建议: 1,选择多个 Hash 函数计算多个 Hash 值,这样可以减少误判的几率;2,布隆过滤器会消耗一定的内存空间,所以在使用时需要评估你的业务场景下需要多大的内存,存储的成本是否可以接受。

分布式锁

分布式锁的方式也比较简单,比方说 ID 为 1 的用户是一个热点用户,当他的用户信息缓存失效后,我们需要从数据库中重新加载数据时,先向 Memcached 中写入一个 Key 为"lock.1"的缓存项,然后去数据库里面加载数据,当数据加载完成后再把这个 Key 删掉。这时,如果另外一个线程也要请求这个用户的数据,它发现缓存中有 Key 为“lock.1”的缓存,就认为目前已经有线程在加载数据库中的值到缓存中了,它就可以重新去缓存中查询数据,不再穿透数据库了。

来源:https://www./content-4-769401.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多