WebSphere eXtreme Scale 初探文档格式.docx
《WebSphere eXtreme Scale 初探文档格式.docx》由会员分享,可在线阅读,更多相关《WebSphere eXtreme Scale 初探文档格式.docx(10页珍藏版)》请在冰豆网上搜索。
分区数据以支持线性水平扩展
缓存
接下来的几节详细描述这些原理。
将数据放入内存
数据通常存储在磁盘(可能位于磁盘的数据库中)。
为了处理该数据,它必须放入计算机的内存供程序处理(图2)。
与访问已经在计算机内存中的数据相比,这种输入/输出(I/O)操作非常耗时。
例如,它需要20ms(或者说0.02秒,或20x103秒)才能从磁盘中读入数据块。
而访问已经位于内存中的数据只需要几十纳秒(或者说109秒)。
可见,访问内存中的数据要快一百万(或者说106)倍。
图2.内存层次结构
32位与64位JVM
32和64表示底层硬件地址空间的位数:
大部分机器都有32位硬件,这表示地址空间最大可以是232字节。
大部分机器都有64位硬件,这表示地址空间最大可以是264字节。
如果32位JVM中2GB不够,可以使用提供4ExaBytes(或者说4x1018字节)的64位JVM吗?
JVM内存是虚拟的。
64位JVM受到所运行服务器物理内存的限制。
当机器的物理内存都被占用时,您必须以低磁盘速度从磁盘获取数据。
机器物理内存的大小决定了您的性能,因此将所有数据放入64位JVM将创建一个服务器瓶颈,破坏了您尝试实现的水平扩大原则(见下一节)。
在Java™垃圾收集(GC)时间上也存在一些限制;
一般的经验是在一个64位JVM中数据保持在5-6GB以下,否则GC可能会占用掉大量处理能力。
最好使用更小的32位JVM进行扩大和分散负载,减少对64位JVM的使用。
最近的研究验证了这个选择,它表明64位JVM存储相同的对象数量时使用的实际内存比32位JVM多50%。
WebSphereeXtremeScale也支持64位JVM,您应该在合适的地方使用它们,但是必须谨慎使用以防损失。
64位JVM可能带来一定的额外开销,即使避免了GC的占用也是如此。
(如果对GC感兴趣,可以研究WebSphereRealTime)。
如果大部分数据位于磁盘,您应该如何扩展应用程序使其不用等待从较慢的磁盘中获取数据?
答案是将尽可能多的数据放入内存,以减少这些高成本的I/O操作。
更快的数据访问可以让应用程序运行的更快,因此能获得更好的用户响应时间,更好的应用程序吞吐量,更强大的支持更多用户的能力。
听起来很简单。
为什么大家不都这样做呢?
有两个原因:
通常,重要的数据必须具有持久性,比如银行账户记录。
计算机内存有一个问题,当关闭电源后,内存中的数据将丢失。
磁盘存储是持久的,因为在断电后数据不会丢失。
计算机内存装不下所有数据!
计算机内存和地址空间变得更大;
32位JVM表示2GB的可用内存。
这样的数据已经很大了,但是您的中间件和应用程序逻辑也必须共享该空间。
可以考虑将数据放入内存的另一个地方是其他机器。
从本地磁盘获取数据需要20-40ms,但通过高速网络从邻近机器获取数据只需要2ms。
使用其他机器的内存进行扩展非常合适。
除了放入数据之外,机器内存还可以用于操作系统、中间件和应用程序逻辑等。
使用远程机器直接存储数据,可以为数据提供更多的内存,使您能获取更快的速度(与磁盘相比)。
使用其他机器对于可用性也很合适。
如果在另一台机器上存储数据副本,您可以从第一台机器的失败中恢复。
分区数据以支持线性水平扩展
性能分析和调试的基本方法是发现并减少瓶颈。
假设处理器给您X吞吐量。
如图3所示的绿色线性扩展线,每当向解决方案添加一个处理器时,您会多得到X的吞吐量。
蓝色线显示非线性扩展,每添加一个处理器时多得的吞吐量少于X吞吐量。
红色的瓶颈线表示资源为最大容量时的情况(本例为数据库),无法再增加大小。
随着负载的增加,您的吞吐量保持不变,受限制的资源位于最高水平。
图3.性能、扩展和瓶颈
第一个解决该瓶颈的方法是用一个更大、更快的机器运行数据库。
这是垂直扩展(verticalscaling)方法;
就是让一个瓶颈机器更大、更高。
垂直扩展只能帮助您这么多(即带到更高的饱和点),此外获取一流硬件是一个昂贵的解决方案。
如果需要更多的扩展怎么办?
很明显应该使用更多的机器来解决问题。
这就是水平扩展(horizontalscale-out)。
但是这能够帮助数据库吗?
回答是大部分情况下不行。
图4显示了可行设置中情况:
应用服务器在水平方向上可以很好地扩展,因此可以很好地消除该层的瓶颈。
垂直扩展适用于数据库,但是不足以将数据库作为瓶颈移除,以实现想要的扩展。
图4.传统三层应用程序中的扩展选项
第二个原则是分区数据:
使用两台机器,每台机器放一半数据,将数据请求路由到包含数据的机器。
如果在两台机器上以这种方式分区数据,那么每台机器可以承担一半的负载,因此您的性能和一台机器的吞吐量就翻了一倍。
并非所有的数据和应用程序都是可以分区的。
有些可以很好地扩展,有些则无法扩展。
分区的好处是可以很好地扩展。
如果使用两台机器分摊负载很好,那么使用10、100甚至1,000台机器怎么样呢?
这就是WebSphereeXtremeScale提供的功能,这就是它提供的可扩展性。
分区支持线性扩展(图3中的绿线)。
请求可以有效地路由到寄存所需数据的机器。
没有分区,将当前数据放到可以处理的正确位置需要许多开销,这种开销是随着机器的增加呈指数(不是线性)增长的。
有了分区,您添加的每台机器都可以有效地处理自己的一部分,任何机器都不会产生额外的开销。
随着机器的增多,所有机器都相等地共享整个处理负载。
您可以根据需要添加任意数量的机器来处理工作负载。
在上例中,关键数据是用户配置文件,可以跨一组机器分布(分区)以进行并行处理。
要将响应时间加快10倍,可以使用10个服务器。
WebSphereeXtremeScale可以扩展到成千上万台机器,这意味着该解决方案可以扩展100到1,000倍,支持50到500百万用户,只需要6ms的响应时间。
内存中的数据和分区可以将响应时间从60ms减少到6ms,分区功能本身就能让支持的用户增加100到1,000倍,响应时间同样为6ms。
这就是所谓的线性扩展。
缓存
WebSphereeXtremeScale的关键功能是提供大型、可扩展、弹性的缓存。
缓存限制
缓存通常大小有限。
缓存被填满之后,必须移除一个项才能放下另一个。
通常的删除战略是删除最老以及最少使用的(LRU)项。
缓存是用来保存数据的内存块。
第一个查询项的位置就是缓存。
如果存在数据,您就得到一次缓存命中(cachehit),并以内存速度获取项(几十纳秒)。
如果缓存中没有数据,那么就是缓存未命中(cachemiss),必须从磁盘中以磁盘速度(几十毫秒)获取项。
从磁盘中获取项之后,将其放入缓存然后返回。
基本的缓存用法在图5中的缓存演示。
正如后文所讨论的,应用程序可以与sidecache和磁盘对话。
图5.缓存
缓存的有效性与命中率成正比关系,命中率是缓存中的项能满足请求的比例。
如果所有数据都在缓存中,那么只需从磁盘读取一次数据;
毕竟,所有的请求都可以用内存速度从缓存中得到满足。
使用缓存有两个主要好处:
第一个好处是处理缓存中的数据请求。
处理速度将大大提升,因为数据是以内存速度交付的。
任何缓存命中都意味着不再需要从磁盘中获取数据的读取操作。
因此,减少了磁盘上的负载。
减少了磁盘负载是缓存的另一个好处。
磁盘现在支持对其他数据的更多请求。
在上例中,关键数据访问时间从60ms减少到6ms是该缓存带来的直接好处,同时还减少了后端数据库的负载。
命中率与缓存大小、底层数据的数量和数据访问模式有关。
如果应用程序的访问模式是持续的顺序读取所有缓存的数据,那么缓存将无法提供太多帮助,除非所有数据都位于缓存中。
当缓存填满之后,在应用程序再次访问前数据将被删除。
在这种情况下,缓存不但没有帮助,反而会更糟;
因为它将数据放入缓存需要更多的开销,与没有缓存的情况相比,这种应用程序的性能更加糟糕。
在许多情况下,缓存与需要使用数据的处理位于同一个地址空间。
这种做法提高了速度但是限制了缓存的大小。
WebSphereeXtremeScale可以使用其他JVM用于缓存。
这些JVM可以专门用作缓存JVM,以便JVM的大部分内存可以用于应用程序数据——不与中间件、基础结构、应用程序代码或内存共享。
这些JVM可以位于同一个机器上。
本地JVM提供对内存的快速访问,但是物理内存和CPU周期最终都必须共享机器上的操作系统、其他应用程序以及JVM。
因此,为了获得更大的缓存、平衡和并行访问负载,您应该在远程机器上使用JVM以访问更多的物理内存。
物理内存是加快访问的关键。
远程JVM提供更大的缓存,更具可扩展性。
缓存中的数据更改时会发生什么?
写入时如果有缓存会让事情变得更加复杂。
确定缓存什么数据的重要因素是写入读取率。
当数据没有变化(即没有写入,因而写入读取率为零)或者不经常变化(例如,如果缓存用户配置文件,它们将不会经常更改,因而写入读取率很低),缓存的效果最好。
提到写入时,最好考虑内联缓存(in-linecache)(图6)。
我们将在下文介绍,应用程序仅与缓存对话,缓存则与磁盘对话。
图6.内联缓存
有两个主要的写入用例:
使用缓存更改数据的过程。
不使用缓存更改数据的过程。
在第一个用例中,有两种选择:
在write-throughcache模式下,在返回到写入流程并继续之前,数据将写入到缓存然后再写到磁盘。
在这种情况下,写入以磁盘速度进行,这很糟糕。
好消息是磁盘上的数据与缓存中的数据保持一致,这是好的方面。
在write-behindcache模式下,当数据位于缓存中时,请求将返回,并且处理继续进行。
在这种情况下,写入过程以内存速度而不是磁盘速度进行,这是好的方面。
但是磁盘上的数据暂时会过时,这是坏的方面。
如果新的缓存副本没有在关机或缓存失败前写入磁盘,更新将丢失,这非常糟糕。
但是,WebSphereeXtremeScale可以在其他机器上保存更多的缓存副本,以提供可靠的write-behindcache。
因此,write-behind缓存在访问所有写入数据以及所有缓存命中读取时都能提供内存速度,而且还有一些其他好处,我们将在下文介绍。
如果另一个过程没有通过缓存而更改了底层数据,那么会出现问题。
如果您无法让所有的过程都使用缓存,那么您将得到过时数据(暂时)。
许多用户使用数据库的影子副本(图4)支持基于操作数据的大型专用查询。
这些影子副本很快就会过时,但这是可以理解和接受的。
解决缓存过时问题有两种方法:
让所有缓存项过时。
例如,在用户定义的间隔(如10分钟)过后,每个项都自动从缓存中删除。
这将强迫缓存从磁盘重新加载数据,因此缓存数据的过时不会超过10分钟。
检测底层数据的更改,然后从缓存删除更改的数据(使其根据需要重新加载),或者将更新的数据重新加载到缓存。
WebSphereeXtremeScale支持这两种方法。
图7展示了缓存如何满足图4中所描述的整个画面。
实现详情
WebSphereeXtremeScale是非侵入式中间件。
它打包为一个15MB的JAR文件,不依赖WebSphereApplicationServerNetworkDeployment,并且可以当前和较旧版本的WebSphereApplicationServerNetworkDeployment、WebSphereApplicationServerCommunityEdition,以及一些非IBM应用服务器一起使用,比如JBoss和WebLogic。
WebSphereeXtremeScale还支持J2SE™Sun™、IBMJVM和Spring。
由于这种独立性,一个缓冲或缓存网格可以扩展多个WebSphereApplicationServer单元格(如果必要)。
尽管WebSphereeXtremeScale是自含的,它需要外部框架来安装应用程序和启动/停止JVM寄存这些应用程序——除非您希望通过命令行完成这些,如WebSphereApplicationServer(也支持WebLogic和JBoss框架)。
WebSphereeXtremeScale可以由IBMTivoli®
Monitoring以及HypericHQ和WilyIntroscope管理和监控。
WebSphereeXtremeScale使用TCP进行通信,没有多播或UDP。
不需要特殊的网络技术(共享子网)或类似的先决条件。
缓存副本可以使用地理上远程的节点。
分区
WebSphereeXtremeScale使用分区的概念扩展缓存。
数据(Java对象)存储在缓存中。
每个数据都有一个独特的键。
数据基于其键放入缓存及从中检索。
考虑这个简单(可能有点怪)的在文件柜中存储邮件的示例:
键是名称,姓氏的首字母。
可以想象一个带有两个抽屉的文件柜,一个标签为A-L,另一个标签为M-Z。
每个抽屉都是一个分区。
您可以添加一个文件柜来扩展邮件缓存。
您将抽屉重新标记为A-F、G-L、M-R、S-Z,然后必须重新整理邮件,将其放入合适的抽屉。
您可以将邮件缓存的大小扩大一倍,可以继续扩展。
邮件缓存有一个问题,人名的分布是不均匀的。
与Q、X、Y抽屉相比,您的M、R和S抽屉可能很快就填满了。
这将在内存和处理上导致缓存负载的不均匀。
分区的工作方式是对键计算散列码。
散列码是一个整数,应该对每个键返回唯一的数字。
(例如,如果键是整数,该值应该作为散列码。
在Java中,String散列码方法将字符串视为base-31数字,以此计算其散列码)。
在WebSphereeXtremeScale中,您首先确定缓存分区的数字。
要将项放入缓存,WebSphereeXtremeScale计算键的散列码,除以分区的编号,余数标识存储项的分区。
例如,如果您有3个分区,键的散列码为7,7除以3得2余1,所以项应该位于分区1。
分区数量是从0开始的。
散列码应该在键空间上提供均匀的值分布,以便分区负载平衡。
(WebSphereeXtremeScale自动为键计算散列码。
如果需要可以提供自己的散列码)。
线性扩展的键是在分区上均匀分布的数据。
这使您能选择足够多的分区数量,以便每个服务器节点都能稳定地处理每个分区上的负载。
WebSphereeXtremeScale如何扩展其缓存?
在上例中邮件缓存,抽屉为分区,您使用具有两个抽屉的文件柜。
每个抽屉和文件柜的大小都是固定的。
如果将这种类比应用到WebSphereeXtremeScale,您可以将文件柜看做在JVM中运行的容器服务器。
这意味着文件柜可以保存最多2GB的项(如果使用64位JVM则更大)。
在WebSphereeXtremeScale中,文件柜(容器服务器)可以保存许多抽屉(分区)。
分区可以保存最多2GB的项(假设是32位而不是64位JVM)。
(如果您的对象在每个存储器中使用n字节,那么每个分区最多可以包含2GB/n个项)。
在WebSphereeXtremeScale中,分区的数量在包含项数量之前设置。
假设您使用许多分区,例如101。
这意味着您的邮件缓存可以存储仅202GB(101个分区*每个分区2GB)的项。
容器服务区可以在多个远程机器上分布,有些可以共享同一个机器。
在具有一个容器服务器的简单示例中(对应于一个文件柜的情况),所有101个分区将位于一个容器服务器中,因此您只能保存2GB的项。
若要扩展,您只需要启动另一个容器服务器,最好在另一个机器上,以分担负载。
有了另一个可用的容器服务器,WebSphereeXtremeScale将自动在两个容器服务器之间平衡邮件缓存负载,101个分区中有一半将移动到第二个容器服务器上。
如果在第三台机器上添加第三个容器服务器,负载将会重新平衡——从第一个容器服务器移动17个分区,从第二个容器服务器移动16个分区,一起放到新的容器服务器。
新的服务器将有33个分区,前两个服务器各34个分区。
通过这种方式,WebSphereeXtremeScale提供线性扩展。
在101个分区和一个容器服务器的情况下,最多能包含2GB的项。
在101个分区,101个容器服务器的情况下,您以供可以保存202GB的项。
这些容器服务器应该分布在多台机器上。
基本思想是,负载平均分布在分区上,WebSphereeXtremeScale在可用的机器上平均分布分区。
因此,您可以获得线性扩展。
如果同时运行WebSphereApplicationServer,WebSphereeXtremeScale将随着容量和负载的变化,自动在不同的机器上启动和停止容器服务器。
因此,您可以获得动态(自动管理)、弹性的缓存。
复制
扩展很好,但要是机器失败和服务器失败时怎么办?
WebSphereeXtremeScale在失败时提供可用性,因为它允许数据复制。
缓存分区存储在一个或多个碎片中。
第一个碎片称为主碎片(primaryshard)。
定义WebSphereeXtremeScale缓存时,您通过指定复制碎片(replicashard)缓存指定复制水平。
复制碎片是主碎片中所有数据的备份副本,它们的主要目的是从主碎片失败中恢复,提供高可用性。
在某些情况下,它们可以用来满足读取请求卸载主碎片。
分区和碎片之间的不同一开始可能很容易混淆:
分区是一个逻辑概念。
它表示缓存数据的1/nth,其中缓存被分为n个部分或分区。
碎片是一个实际的物理内存块,它存储分区的内容。
为了确保容错和高可用性,WebSphereeXtremeScale碎片分布算法确保主碎片和复制碎片绝不会位于同一个容器中。
当主碎片失败时,复制碎片将提升为主碎片,同时在另一个容器中创建一个新的复制碎片。
复制可以是同步或异步的;
将数据写入WebSphereeXtremeScale缓存时区别很重要。
事务用于所有的WebSphereeXtremeScale缓存读取和写入。
在所有同步复制碎片确定新数据的接收之后,写入事务才算完成。
异步复制碎片在事务完成之后更新,因此它们提供更快的事务性能(至少6倍),但是增加了失败时丢失数据的风险。
根据应用程序的性能和可用性需求选择同步和移除复制的数量。
例如,您可以在同一个数据中心的另一台机器上选择同步复制,而在另一个数据中心的机器上选择异步复制。
在WebSphereeXtremeScale中,使用区域定义数据中心的概念,WebSphereeXtremeScale自动处理这一点。
通过选择同步和异步复制的数量及其区域放置,您可以在失败时平衡性能、可用性和弹性。
让我们重新看看带有A-L和M-Z邮件抽屉的文件柜示例。
这一次,假设您定义一个复制碎片。
图8展示了一个示例,尽管只有3个分区。
最初,在一个容器中有101个主碎片,没有任何复制碎片。
(复制碎片位于一个容器中是没有意义的)。
添加第二个容器时,将50个主碎片移动到第二个容器。
另外51个复制碎片也移动到第二个容器以便平衡,对于每个碎片,它的主碎片和复制碎片都位于不同的容器中。
添加第三个容器时也是一样。
因此,每个机器有33或34个主碎片,以及33或34个不同的复制碎片