MySpace做为.NET架构在互联网平台最为成功的案例之一,其中很是重要的系统datarelay分布式数据缓存也开源了,DataRelay提供了高性能的缓存系统和消息处理机制,并支持自定义计算Component组件,支持Cluster,有完整的Replication和负载均衡机制,组件都是以windows服务的形式,能够很是灵活的进行部署,客户端与服务端使用Socket进行通讯通信,另外还能够很方便的扩展各类自定义组件,譬如缓存部分可使用Memcached,还有最近比较流行Redis。html
MySpace虽然开源出来datarelay,可是没有很好的文档帮助你们学习,下面将对整套代码分析,让你们从全局认识DataRelay这套在.net平台上少有的精品。程序员
CodePlex代码下载地址:http://datarelay.codeplex.com算法
MIX 10上的演讲:Robots at MySpace: Massive Scaling a .NET Website with the Microsoft Robotic Studiohttp://ecn.channel9.msdn.com/o9/mix/10/pptx/EX04.pptx数据库
主要分析DataRelay的架构,分别从DataRelay的特色,系统的物理部署架构,以及系统的内部结构和基于组件规范接口分析,详细地介绍了DataRelay系统的构架思想以及实现方案。编程
DataRelay在参考各类数据缓存功能和设计理念基础上,在.NET平台体系下设计并实现的一套分布式缓存体系,具备如下特色:windows
<!--[if !supportLists]-->1) <!--[endif]-->利用现有的Cache解决方案来完成本地Cache功能。现有的Berkeley DB、Memcached、 本地Cache模块均可以做为插件,接入该系统中,做为本地Cache机制。数组
<!--[if !supportLists]-->2) <!--[endif]-->自定义序列化和反序列接口,减小存储空间,提供网络传输效率。缓存
<!--[if !supportLists]-->3) <!--[endif]-->服务部署简单,对服务节点支持热插拔。服务器
<!--[if !supportLists]-->4) <!--[endif]-->对符合DataRelay组件接口定义的模块,经过统一的组件接口管理模块,对服务端组件支持动态更新。网络
<!--[if !supportLists]-->5) <!--[endif]-->规范的组件开发接口,大大简化了组件开发,提升扩展性。
<!--[if !supportLists]-->6) <!--[endif]-->网络消息分发与同步结合了Replicated Cache和Distributed Cache模式,保证了系统的可靠行。
<!--[if !supportLists]-->7) <!--[endif]-->利用微软CCR组件(并发与协调运行时(Concurrency and Coordination Runtime))很好的管理消息的异步、并发、协调和失败处理,保证了系统的高效,稳定。
DataRelay的物理架构图如图1所示,标明了DataRelay在整个网站系统中所处的地位。DataRelay处于整个网站体系中的中间层,不一样于通常中间层设计,Web服务器即链接数据库服务器,也同时链接中间层,这样设计能够防止单点,若是Web服务器只链接中间层,一旦中间层服务器荡机,整个网站将不能工做,而采用图中设计方案,一旦中间层服务器当机,Web服务器一样能够直接访问数据库服务器,不至于不工做。当Web服务器请求被Cache的业务对象时,首先请求DataRelay系统,若是该数据在DataRelay系统中存在,将直接返回给Web服务器,当不存在DataRelay系统中,系统将请求转向数据库请求,请求到数据首先将数据保存到DataRelay系统中,事后返回给Web服务器。
图1 网站物理架构图
整个DataRelay集群部署如图2所示,对于DataRelay的服务器的组织结构,主要有如下三点定义:
<!--[if !supportLists]-->1) <!--[endif]-->Groups
<!--[if !supportLists]-->l <!--[endif]-->不一样的组存储不一样的数据,在DataRelay系统中,能够定义多个组,能够针对组进行访问模式设置。
<!--[if !supportLists]-->2) <!--[endif]-->Clusters
<!--[if !supportLists]-->l <!--[endif]-->多个集群存在一个组中,缓存业务的数据对象根据Distributed Cache模式分配选择须要保存的集群地址。
<!--[if !supportLists]-->3) <!--[endif]-->Servers
<!--[if !supportLists]-->l <!--[endif]-->DataRelay集群中的服务器,每一个集群中服务器之间采用Replicated Cache模式同步保存数据。
图2 DataRelay集群部署图
在此结构中,每一组Cluster中的服务器之间会同步数据,保存一样的数据备份,当Web服务器请求数据,获取数据服务器节点的算法:
Cluster Index = ObjectID %(# Cluster)
Server Node = Random (Cluster Index)
注:ObjectID 表示存储数据的类型ID,# Cluster 表示一个Group中有多少个Cluster
当肯定了Cluster Index事后,就随机从该Cluster中取出一台可用的节点服务器处理数据请求。
DataRelay各个模块之间协调工做,保障了系统的正常运行,各个模块的设计有各自的责任,DataRelay的内部模块组成如图3所示,主要职责以下:
<!--[if !supportLists]-->1) <!--[endif]-->DataRelay.Client:是整个体系提供给客户端使用的接口,客户端经过该接口完成数据操做。
<!--[if !supportLists]-->2) <!--[endif]-->DataRelay.Server:服务端的管理组件,控制服务的生命周期,以及扩展组件的热插拔。
图3 DataRelay的内部模块结构图
<!--[if !supportLists]-->3) <!--[endif]-->DataRelay.Transports.Socket:管理客户端和服务端的TCP链接池管理。
<!--[if !supportLists]-->4) <!--[endif]-->DataRelay.Common:主要封装了DataRelay体系中通用操做以及接口定义,主要包括:
<!--[if !supportLists]-->a) <!--[endif]-->RelayComponent.Interface 定义DataRelay的组件接口规范,扩展组件必须实现该接口。
<!--[if !supportLists]-->b) <!--[endif]-->RelayMessage 定义了服务端和客户端交互的消息类型,是整个体系通讯的基础。
<!--[if !supportLists]-->c) <!--[endif]-->RelayConfiguration Schemas 对体系中的配置文件进行格式验证,保证配置的准确性。
<!--[if !supportLists]-->5) <!--[endif]-->DataRelay.Components:组件模块,包含了基本模块,以及扩展模块
<!--[if !supportLists]-->a) <!--[endif]-->Storage是真正存放Cache的地方,对于存放的介质有多种,采用Berkeley DB用来持久化存储数据,也能够为了高性能,采用内存保存Cache。这部分采用DataRelay组件设计规范,能够根据缓存的数据类型以及数据操做方式,扩展合适的存储组件模块。
<!--[if !supportLists]-->b) <!--[endif]-->Forwarding :网络消息分发组件,该组件模块是整个DataRelay的核心组件,它负责RelayMessage的传递,以及消息的处理,它的组成包含如下几个核心模块:
<!--[if !supportLists]-->l <!--[endif]-->CCR 是微软提供的异步编程组件,在Forwarding中它负责管理消息的异步、并发、协调和失败处理。
<!--[if !supportLists]-->l <!--[endif]-->NodeManager 对DataRelay服务器节点的管理,Forwarding经过它很好的对节点进行分配以及调用,完成网络消息的分发与同步。
<!--[if !supportLists]-->l <!--[endif]-->PerfCounter 性能计数器[10]主要职责是监控服务器各个节点的服务状态。
<!--[if !supportLists]-->6) <!--[endif]-->DataRelay.Logging:负责记录DataRelay的日志。
DataRelay为了提高序列化效率,对业务缓存对象进行了自定义序列化和反序列化的实现,自定义的序列化数据结构很是紧凑,如图4自定义序列化数据结构图所示,32位整型(int32)只占用4个字节,布尔型(bool)占用1个字节,一个长度为2的16位的整型数组(int16[2])占用总共8个字节,数组长度占4个字节,每位16位数占用2个字节。能够看出,DataRelay自行编码的序列化数据结构至关的紧凑。
图4 自定义序列化数据结构
经过对序列化和反序列化的实现,作了对比测试,在包含一系列System.Int32类型的数据对象中,使用.NET序列化体系,作序列化生成的字节流是190 KB,若是使用自定义序列化实现,将生成仅仅14 KB,字节流减小超过85%,而且序列化的时间减小14.4s,减小了字节流就减小了网络的传输量以及序列化时间缩短,网络传输性能显著提升。
RelayMessage是DataRelay框架的通讯数据基础,它负责承载须要缓存的数据在服务端和客户端之间交互。RelayMessage设计具备如下特色:
<!--[if !supportLists]-->1) <!--[endif]-->规范消息的类型定义,包括get,update,save,delete 等等,随着框架的扩展,添加扩展的类型。
<!--[if !supportLists]-->2) <!--[endif]-->为了提供传输性能,减小网络传输量,消息被序列化成Byte数组存放到服务端,客户端获取到数据事后须要反序列。
<!--[if !supportLists]-->3) <!--[endif]-->每一个消息具备惟一的ID,若是ID不能肯定惟一性,还有ExtendedID 组合使用。
<!--[if !supportLists]-->4) <!--[endif]-->消息TypeID, 针对每种类型的消息都将分配一个TypeID,用来定位缓存的数据位置。
DataRelay是一套基于组件的体系架构,网络消息分发是个组件,持久化存储是个组件,内存存储是个组件,在DataRelay中任何功能的开发都是一个组件,这样能很好的提供了系统的扩展性。
固然对与设计组件自己,还具备很强的自主性,每一个组件能够定义本身的配置文件,在配置文件中经过反射生成处理自身配置信息的实例,如DataRelay设计的Berkeley DB存储组件,因为Berkeley DB自己配置就至关复杂,因此DataRelay在设计该组件时,单独对Berkeley DB配置进行管理,
在DataRelay组件接口定义中,主要是定义了组件要处理消息的接口以及组件自身运行时的信息。特色以下:
<!--[if !supportLists]-->1) <!--[endif]-->服务框架依赖组件的接口操做RelayMessage。
<!--[if !supportLists]-->2) <!--[endif]-->组件能够自定义的配置文件,服务框架经过反射,获取组件配置信息。
<!--[if !supportLists]-->3) <!--[endif]-->当组件配置文件变更,服务框架会自动读取从新读取配置信息。
DataRelay体系是基于组件模块的,对于组件的运行须要一个环境,DataRelay提供组件容器,组件容器的主要职责就是维护组件的生命周期,以及调度消息在组件中传输。该类实现两个接口,分别是IRelayNode和IDataHandler。
<!--[if !supportLists]-->1) <!--[endif]-->IRelayNode:该接口定义容器中组件节点的生命周期,以及配置信息,经过该接口,咱们能够获取到容器中各个组件当前的运行情况,以及相关配置信息。
<!--[if !supportLists]-->2) <!--[endif]-->IDataHandler:该接口是传输消息的接口定义,一样在组件接口定义中也须要集成该接口,该接口定义在整个体系中消息的传输。
服务端消息将接收到消息所有传输到组件容器中,有组件容器进行消息分发,因此在RelayNode类的设计上,对大量高并发的消息,也采用CCR组件管理。
8 DataRelay 网络消息分发机制
网络消息分发在DataRelay中是由Forwarding组件模块完成的,Forwarding是DataRelay的一个核心模块,在服务端和客户端都要使用。它完成DataRelay分布式缓存系统的网络消息分发与同步。它对消息分发与同步机制分红两种方式,一种是要实时操做消息,一种是异步操做消息。对于获取Cache数据,须要实时操做,对于更新、保存、删除Cache数据能够根据业务场景选择异步操做。
DataRelay在系统中实现的分布式Cache是Replicated Cache和Distributed Cache相结合的作法:
<!--[if !supportLists]-->1) <!--[endif]-->在对于同一个组下缓存对象的选择放在某个集群中存储是采用Distributed Cache方式,根据Mod运算定位存放的集群位置。
<!--[if !supportLists]-->2) <!--[endif]-->对于在同一个组下同一个集群中节点机器上的Cache数据分布采用的是Replicated Cache,便是指在同一个组中的同一个集群下的每一个节点所包含的Cache数据是一致的。
Forwarding组件模块处理Cache数据主要分为2个方面,一方面是获取数据,另外一个方面是更新数据。如图10示意了在保存和获取的逻辑过程。假设当前DataRelay系统4台服务器节点,分红2个集群,在同一App组中,须要处理的缓存业务对象数据有2个,2个数据对象的ID分别是120和121。下面分别说明数据在获取和保存的逻辑过程。
<!--[if !supportLists]-->1) <!--[endif]-->获取对象Id为121的缓存数据:
<!--[if !supportLists]-->a) <!--[endif]-->获取对象Id为121配置描述中设置的组名称:App。
<!--[if !supportLists]-->b) <!--[endif]-->选择Cluster Index:首先根据Cluster Index 算法,计算得出 Cluster Index = 1 ( 121 % 2 = 1 ) mod ( 业务对象ID,集群数量 )。
<!--[if !supportLists]-->c) <!--[endif]-->从该Cluster中随机选择一台服务节点,获取数据。
<!--[if !supportLists]-->2) <!--[endif]-->保存对象Id为120的缓存数据:
<!--[if !supportLists]-->a) <!--[endif]-->获取对象Id为120配置描述中设置的组名称:App。
<!--[if !supportLists]-->b) <!--[endif]-->选择Cluster Index: 首先根据Cluster Index算法,计算得出 Cluster Index = 0 ( 120 % 2 )。
<!--[if !supportLists]-->c) <!--[endif]-->从该Cluster中随机选择一台服务器节点,保存数据
<!--[if !supportLists]-->d) <!--[endif]-->该服务器节点会异步发送网络消息,同步该缓存数据到该Cluster的其余节点中。
图10 网络消息分发模型
DataRelay在Forwarding的设计上具备如下几个特色:
<!--[if !supportLists]-->1) <!--[endif]-->结合了Replicated Cache 和Distributed Cache各自特色,很好的处理了Cache数据在集群上的数据分布与同步。
<!--[if !supportLists]-->2) <!--[endif]-->CCR组件模块的集成,使得网络消息处理具备高效行,可靠性。
<!--[if !supportLists]-->3) <!--[endif]-->经过配置能够对消息批量打包,一次性提交,减小网络通讯。
在服务部署这块,datarelay也有独特之处,利用了.net appdomain这个特性,作到可热插拔,在设计这部分功能时,采用DataRelay系统框架和组件模块使用不一样的AppDomain来加载,将在一个独立的 AppDomain将全部组件模块程序集加载到组件容器中,这样当添加或者更新组件dll和配置文件时,DataRelay将能够动态卸载 AppDomain,事后在重新建立新的 AppDomain,而后将当前组件加载到其中。
这样就能够不用重新启动DataRelay服务管理组件更新,在线上运维仍是很是方便的,设想一下若是有几十台Relay服务器须要更新组件,这样部署很便利很高效。
《程序员2012.11期》 做者:张庆化
原文:http://www.tita.com/blog/tech/myspace-datarelay-分布式数据缓存源码分析