注:以下内容摘自:http://www.jianshu.com/p/bde93f9d1469
一、什么是可伸缩性
可伸缩性是一种对软件系统计算处理能力的设计指标,高可伸缩性代表一种弹性,在系统扩展成长的过程中,软件能够保证旺盛的生命力,通过很少的改动甚至只是硬件设置的添置,就能实现整个系统能力的线性增长,实现高吞吐量和低延迟性能。
二、可伸缩性和纯粹性能调优是有区别的:
可伸缩性是高性能、低成本和可维护性等诸多因素的综合考量和平衡,可伸缩性讲究平滑线性的性能提升,更侧重于系统的水平伸缩,通过廉价的服务器实现分布式计算;
而普通性能优化只是单台机器的性能指标优化。他们共同点都是根据应用系统特点在吞吐量和延迟之间进行一个侧重选择,当水平伸缩分区后会带来CAP定理约束
三、软件的可扩展性设计注意
软件的可扩展性设计非常重要,但又比较难以掌握,业界试图通过云计算或高并发语言等方式节省开发者精力,但是,无论采用什么技术,如果应用系统内部是铁板一块,例如 严重依赖数据库, 系统达到一定访问规模,负载都集中到一两台数据库服务器上,这是进行分区扩展伸缩就比较困难。
关系数据库是最不可扩展的。
四、性能和扩展性
什么是性能问题?如果你的系统对于一个用户访问还很慢,那就是性能问题。
什么是扩展性问题?如果你的系统对于一个用户来说很快的,但是在用户不断增长的高访问量下就慢了。
五、可扩展性的目的
延迟和吞吐量是衡量可扩展性的一对指标,我们希望获得低延迟和高吞吐量的系统架构。所谓低延迟,也就是用户能感受到的系统响应时间,比如一个网页在几秒内打开,越短表示延迟越低,而吞吐量表示同时有多少用户能够享受到这种低延迟,如果并发用户量很大时,用户感觉网页的打开速度很慢,这意味着系统架构的吞吐量有待提高。
扩展性的目标是用可接受的延迟获得最大的吞吐量。可靠性(可用性)目标:用可接受的延迟获得数据更新的一致性
六、缓存的可扩展性
缓存层的伸缩性,最简单粗暴的方式是什么呢?
趁着半夜量比较低的时候,把整个缓存层全部下线,然后上线新的缓存层。新的缓存层启动起来之后,再等这些缓存慢慢预热。当然这里一个要求,你的数据库能抗住低估期的请求量。如果扛不住呢?取决于缓存类型,下面我们先可以将缓存的类型区分一下。
强一致性缓存:无法接受从缓存拿到错误的数据 (比如用户余额,或者会被下游继续缓存这种情形)
弱一致性缓存:能接受在一段时间内从缓存拿到错误的数据 (比如微博的转发数)。
不变型缓存:缓存key对应的value不会变更 (比如从SHA1推出来的密码, 或者其他复杂公式的计算结果)
那什么缓存类型伸缩性比较好呢?
弱一致性和不变型缓存的扩容很方便,用一致性Hash即可;
使用一致性Hash,而不用简单Hash的原因是缓存的失效率。如果缓存从9台扩容到10台,简单Hash 情况下90%的缓存会马上失效,而如果使用一致性Hash情况,只有10%的缓存会失效。
强一致性缓存会有什么问题?
第一个问题是,缓存客户端的配置更新时间会有微小的差异,在这个时间窗内有可能会拿到过期的数据。
第二个问题是,如果扩容之后再裁撤节点,会拿到脏数据。比如 a 这个key之前在机器1,扩容后在机器2,数据更新了,但裁撤节点后key回到机器1,这时候就会拿到脏数据。
要解决问题二比较简单,要么保持永不减少节点,要么节点调整间隔大于数据的有效时间。
问题一可以用如下的步骤来解决:
1、两套hash配置都更新到客户端,但仍然使用旧配置;
2、逐个客户端改为只有两台Hash结果一致的情况下会适用缓存,其余情况从数据库读,但写入缓存;
3、逐个客户端通知使用新配置;
Memcache 设计得比较早,导致在伸缩性高可用方面的考虑得不太周到。Redis 在这方面有不少改进,特别是 @ngaut 团队基于 redis 开发了 codis 这个软件,一次性地解决了缓存层的绝大部分问题。推荐大家考察一下。
八、缓存穿透,缓存雪崩
缓存穿透:查询一个必然不存在的数据。比如文字表,查询一个不存在的id,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成影响。解决办法:对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合直接丢弃
缓存失效:如果缓存在一段时间内失效,DB的压力凸显。这个没有完美的解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。
缓存雪崩:当发生大量的缓存穿透,例如对某个失效的缓存的大并发访问就造成了缓存雪崩。比如前端的Cache挂掉,或者比较极端的整个机房断电了,那么在机器重启后,原来Cache机器在内存中的缓存会全部清空,在客户端访问过程中,会百分之百的不命中,这样数据库会在瞬间接受巨大的读压力。
试想如果一个64GB的缓存失效了,在其重建时,假设与数据库连接的千兆网卡,假设其以极限速度100M每秒从数据库取数据过来重建缓存,那么也需要10分钟才能建完。更何况这是理想情况,对于客户端触发式的随机缓存重建,可能会花掉更长的时间。这还是在数据库能提供100M每秒的数据读请求的前提下。
我们经常看到一些网站挂掉后又恢复,恢复后又挂掉,如此反复几次才能真正恢复,原因就在于其第一次Cache倒了,数据库无法承受相应的读压力,在缓存重建了一小部分后被压死。相当于数据库每重启一次,可以恢复部分缓存,直到缓存的非命中率到达数据库可承受的压力时,才能够真正恢复服务。
九、如何解决缓存雪崩
第一种方式
概述: 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
oschina首页使用了缓存,假设我们前面举的例子中所使用的缓存region(region1),设置了自动失效时间为5分钟,相等于说每5分钟就会发现首页很卡。因此引入第二个缓存region(region2),这个缓存的对象不会自动失效,也就说该区域的数据长期有效。
引入了第二个长效的region后,数据的读取流程这样的:
从 region1 读取数据,有则直接返回
region1 没数据则启动数据更新线程,然后从 region2 读数据,有则返回
region2 也没有数据
针对第3种,这种情况属于系统刚刚启动,缓存还没有填充数据的情况,没办法,这时候肯定会卡,或者你应该在系统启动的时候,自行填充一下数据,很简单,我一般在tomcat启动后,用命令访问下首页就有了缓存数据。
这样做的目的是为了正常的缓存失效后,无需等待重新从数据库中获取数据,而是直接在 region2 中获取数据并返回。因此对用户来讲,不会感觉请求被堵塞。
就这么简单,其实也可以工作,但会有一个问题:假设缓存失效的时候,同时来了100个请求,那么这100个请求会同时启动100个数据更新线程,这100个数据更新线程会到数据库执行同样的SQL语句获得同样的结果,因此这种做法对数据库的压力并没有降低。
所以缓存失效的情况下,保证有且只有一个线程去更新缓存数据。
其他方式
对查询结果为空的情况也进行缓存,缓存时间设置短一些,或者该key对应的数据insert了之后清理缓存。
不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
可以用一些可以提供持久化功能的缓存来实现,比如Redis,在未开启aof的情况下,其定期dump出来的rdb文件出能自动恢复出绝大部分数据,当然,在有的时候这可能导致缓存和数据库数据不一致的情况,需要根据应用场景选择性的使用。
十、缓存重建
上面是对分布式Cache的问题,而对于很多数据库存储,实际上也几乎都是将热数据尽量放在内存中的。但很多数据库在实现上是自己在内存中实现了Cache机制,这样在数据库重启(非操作系统重启)时,这些Cache可能也就随之被清空了,对于数据库来说,也需要重建缓存,而数据库这时所有的操作可能都落在磁盘IO上,带来了同样的问题。
而MongoDB与上面的方式不太一样,MongoDB采用mmap来将数据文件映射到内存中,所以当MongoDB重启时,这些映射的内存并不会清掉,因为它们是由操作系统维护的(所以当操作系统重启时,MongoDB才会有相同问题)。相对于其它一些自己维护Cache的数据库,MongoDB在重启后并不需要进行缓存重建与预热。
另外,新浪微博的timyang也曾经提出过一种缓存重建加锁的方式,也能部分解决此问题。简单来说就是缓存重建时,当多个客户端对同一个缓存数据发起请求时,会在客户端采用加锁等待的方式,对同一个Cache的重建需要获取到相应的锁才行,只有一个客户端能拿到锁,并且只有拿到锁的客户端才能访问数据库重建缓存,其它的客户端都需要等待这个拿到锁的客户端重建好缓存后直接读缓存,其结果是对同一个缓存数据,只进行一次数据库重建访问。但是如果访问分散比较严重,还是会瞬间对数据库造成非常大的压力。
下面是几点比较实用的知识:
无论使用哪个存储,都最好先搞清楚其缓存重建的过程,如果一次重启就可能导致数据库崩溃,还是小心为好,最好把重启时间选在访问量比较小的时候
重启MongoDB不会导致MongoDB的缓存失效(除非重启服务器)
当你重新mount磁盘时,文件系统的缓存会失效,这和重启机器时一样,MongoDB也无法避免
一个使用MongoDB的小技巧,当MongoDB服务器刚启动时,你可以将其所有文件copy到/dev/null中,这会触发操作系统对这些文件的读操作,从而在内存允许的条件下,会将尽可能多的MongoDB数据文件映射到物理内存中。当然,如果在MongoDB运行过程中,你能够判断哪些文件保存的数据是热数据,也可以将这些文件copy到/dev/null 来为其争取更多的物理内存。
十一、缓存一致性
缓存系统与底层数据的一致性。这点在底层系统是“可读可写”时,写得尤为重要。
有继承关系的缓存之间一致性。为了尽量提高缓存命中率,缓存也是分层:全局缓存,二级缓存。他们是存在继承关系的。全局缓存可以有二级缓存来组成。
多个缓存副本之间的一致性。为了保证系统的高可用,缓存系统背后往往会接两套存储系统(如memcache,redis等)
十二、缓存数据的淘汰
定时去清理过期的缓存。
当有用户请求过来时,在判断这个请求所用到的缓存是佛过期,过期的话就去底层得到新数据并更新缓存。
两者各有优劣:
第一种的缺点是维护大量缓存的key是比较麻烦的
第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂,具体哪种方案,大家可以根据自己的应用场景来权衡。
缓存淘汰的几种会用到的技巧
预估失效时间。
版本号(必须单调递增,时间戳是最好的选择)。
提供手动清理缓存的接口。
十三、高手说可扩展
衡量架构伸缩性的主要标准就是是否可以用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差异的服务。集群中可容纳的总的服务器数量是否有限制。
对于应用服务器集群,只要服务器上不保存数据,所有服务器都是对等的,通过使用合适的负载均衡设备就可以向集群中不断加入服务器。
对于缓存服务器集群,加入新的服务器可能会导致缓存路由失效,进而导致集群中大部分缓存数据都无法访问。虽然缓存的数据可以通过数据库重新加载,但是如果应用已经严重依赖缓存,可能会导致整个网站崩溃。需要改进缓存路由算法保证缓存数据的可访问性。
关系型数据库虽然支持数据复制,主从热备机制,但是很难做到大规模集群的可伸缩性,因此关系数据库的集群伸缩性方案必须在数据库之外实现,通过路由分区等手段将部署有多个数据库的服务器组成一个集群。
至于大部分NoSQL数据库产品,由于其先天就是为海量数据而生,因此其对伸缩性的支持通常都非常好,可以做到在较少运维参与的情况下实现集群规模的线性绳索。
《大型网站技术架构核心原理与案例分析》
十四、总结
1. 缓存均匀分布,均匀失效。
2. 二级缓存解决缓存雪崩
3. 缓存很重要,但是数据库的查询优化也很重要
4. 情况允许,扩大MySQL临时表的空间,以防缓存雪崩瞬间巨大访问,导致MySQL崩溃
5. 需要在流量少的情况下,切换缓存,切换完毕之后。需要缓存预热
6. 多看书,多试验
相关推荐
"基于可伸缩性设计的教育平台数据缓存方法及系统"就是一个针对这一挑战的解决方案。这个压缩包文件包含了对这一主题的深入探讨,主要涉及以下几个关键知识点: 1. **可伸缩性设计**:可伸缩性是指系统在面临负载...
- **分层架构**有助于隔离不同层次的变更,提高系统的可维护性和可扩展性。 - **微服务架构**通过将系统分解成小型、独立的服务,提高了系统的灵活性和可伸缩性。 - **容器化**技术进一步增强了微服务架构的优势,...
在构建高效可伸缩的缓存系统中,我们需要考虑的关键因素包括性能、容错性、扩展性和资源管理。本demo提供了实现这些目标的实例代码和测试案例,让我们深入探讨其中涉及的技术点。 首先,缓存的主要目的是提高数据...
【标题】:“Demo缓存伸缩” 在计算机科学与信息技术领域,缓存伸缩是针对高并发场景下,为了...通过对DemoProject的深入研究,我们可以学习到如何在实际项目中应用这些理论知识,以实现高效且可扩展的缓存解决方案。
构建可伸缩的系统是现代IT架构设计中的关键议题,特别是在面对互联网应用、大数据处理以及云计算等场景时,系统的可伸缩性成为了决定其成功与否的重要因素。在“可伸缩的系统技术方案”这一主题下,我们探讨了一系列...
**VB.NET可伸缩性技术手册(PDG)** 在软件开发中,可伸缩性(Scalability)是一项至关重要的特性,它关乎程序在面对负载增加、数据增长或用户需求变化时,能否有效地扩展和适应。VB.NET作为.NET框架的一部分,提供了...
这项工作对于推动分布式缓存技术的发展具有重要的参考价值,它为设计和实现可扩展、高性能的分布式缓存系统提供了理论基础和实践指导。通过动态扩展技术,使得分布式缓存能够更加灵活地应对各种不同的应用负载变化,...
**PHP实例开发源码——Wikka高速可伸缩性软件** Wikka Wiki是一款基于PHP的开源wiki系统,它以其高效能和高度可扩展性而受到开发者们的青睐。在这个压缩包中,你将找到用于理解PHP编程语言以及如何构建可伸缩的Web...
这些文档涵盖了广泛的IT架构主题,特别是集中在搜索引擎技术和系统可伸缩性的实现上。让我们逐一探讨这些文件所代表的知识点。 1. **大型网站架构演变和知识体系**:这个文档可能详细介绍了互联网公司如何随着用户...
标题中的“网络游戏-具有基于内容的信息转向器用于可伸缩性的级联网络装置”揭示了本文档主要讨论的是网络游戏领域中的一种技术方案,涉及到信息转向和级联网络装置的可伸缩性。这个主题涵盖了互联网技术和游戏...
- **入口层**:在入口层实现可伸缩性的一种常见做法是使用负载均衡器(如Nginx),通过增加更多的服务器,并通过DNS轮询或一致性哈希算法分配请求。 - **注意事项**:避免客户端只使用少数几个IP地址的问题,可以...
4. **可伸缩性**:该软件能够随着用户数量和数据增长而扩展,支持大型网站的需求。这得益于其模块化设计和数据库优化策略,使其能够处理大量页面和用户请求。 5. **源码分析**:解压后的文件132699042764655194可能...
5. **可扩展性指标**:衡量系统扩展能力的关键指标,如线性可扩展性、负载均衡能力和弹性伸缩能力等。 6. **容错性设计**:包括数据冗余、故障检测与恢复机制、一致性维护等方面的设计,旨在确保数据的完整性和系统...
基于空间数据面向对象存储思想和云存储可扩展架构,将控制信息集中在元数据服务器集群中管理,而实际的空间数据基于对象存储分布到存储设备集群中,实现控制信息路径与数据传输路径的分离,并缓存热点空间数据对象...
总结来说,淘宝网的高性能可伸缩架构通过实现应用无状态、充分利用缓存和智能应用拆分,确保了系统的高可用性和可扩展性,适应了大规模电商系统的需求。这些技术对于其他大型互联网企业也有很高的参考价值。
总结来说,构建高伸缩性的社交APP交互系统涉及到以下几个关键步骤:优化基础架构,构建私有网络,引入负载均衡和缓存,实现服务的水平扩展和SOA,以及数据库的优化如复制和分片。这些策略确保了在面对大规模用户增长...
软件可扩展性主要体现在两个方面:扩展性和伸缩性。 **扩展性**强调的是系统在不改变现有基础设施和减少依赖的前提下,能够应对需求变化的能力。它鼓励设计对扩展开放,对修改关闭,即添加新功能时无需大幅度修改...
在单个缓存存储能力和服务能力有限且可扩展性较差的背景下,分布式缓存的出现解决了这些问题。通过将数据分布到多个节点上,分布式缓存能够有效减少对中心数据库的依赖,降低系统的延迟,提升用户的响应速率,同时还...