软件各类架构图2

Spring MVC 核心架构图html

 

 

架构图对应的DispatcherServlet核心代码以下:前端

复制代码
//前端控制器分派方法 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; try { ModelAndView mv; boolean errorView = false; try { //检查是不是请求是不是multipart(如文件上传),若是是将经过MultipartResolver解析 processedRequest = checkMultipart(request); //步骤二、请求处处理器(页面控制器)的映射,经过HandlerMapping进行映射 mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } //步骤三、处理器适配,即将咱们的处理器包装成相应的适配器(从而支持多种类型的处理器) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 304 Not Modified缓存支持 //此处省略具体代码 // 执行处理器相关的拦截器的预处理(HandlerInterceptor.preHandle) //此处省略具体代码 // 步骤四、由适配器执行处理器(调用处理器相应功能处理方法) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } // 执行处理器相关的拦截器的后处理(HandlerInterceptor.postHandle) //此处省略具体代码  } catch (ModelAndViewDefiningException ex) { logger.debug("ModelAndViewDefiningException encountered", ex); mv = ex.getModelAndView(); } catch (Exception ex) { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(processedRequest, response, handler, ex); errorView = (mv != null); } //步骤5 步骤六、解析视图并进行视图的渲染 //步骤5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale)) //步骤6 视图在渲染时会把Model传入(view.render(mv.getModelInternal(), request, response);) if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } // 执行处理器相关的拦截器的完成后处理(HandlerInterceptor.afterCompletion) //此处省略具体代码 catch (Exception ex) { // Trigger after-completion for thrown exception.  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } catch (Error err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception.  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } finally { // Clean up any resources used by a multipart request. if (processedRequest != request) { cleanupMultipart(processedRequest); } } }
复制代码

 

核心架构的具体流程步骤以下:node

一、  首先用户发送请求——>DispatcherServlet,前端控制器收到请求后本身不进行处理,而是委托给其余的解析器进行处理,做为统一访问点,进行全局的流程控制;web

二、  DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,经过这种策略模式,很容易添加新的映射策略;算法

三、  DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持不少类型的处理器;数据库

四、  HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);设计模式

五、  ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,经过这种策略模式,很容易更换其余视图技术;缓存

六、  View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,所以很容易支持其余视图技术;服务器

七、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。网络

 

此处咱们只是讲了核心流程,没有考虑拦截器、本地解析、文件上传解析等,后边再细述。

 

    近段时间以来,经过接触有关海量数据处理和搜索引擎的诸多技术,经常见识到很多精妙绝伦的架构图。除了往往感叹于每幅图表面上的绘制的精细以外,更为架构 图背后所隐藏的设计思想所叹服。我的这两天一直在搜集各大型网站的架构设计图,一为了一饱眼福,领略各种大型网站架构设计的精彩以外,二来也可供闲时反复 琢磨体会,何乐而不为呢?特此,总结整理了诸如国外wikipedia,Facebook,Yahoo!,YouTube,MySpace,Twitter,国内如优酷网等大型网站的技术架构(本文重点分析优酷网的技术架构),以飨读者。

    本文着重凸显每一幅图的精彩之处与其背后含义,而图的说明性文字则从简从略。ok,好好享受此番架构盛宴吧。固然,如有任何建议或问题,欢迎不吝指正。谢谢。

  • 一、WikiPedia 技术架构

                                             WikiPedia 技术架构图Copy @Mark Bergsma

  1. 来自wikipedia的数据:峰值每秒钟3万个 HTTP 请求 每秒钟 3G bit 流量, 近乎 375MB 350 台 PC 服务器。
  2. GeoDNSA  :40-line patch for BIND to add geographical filters support to the  existent views in BIND", 把用户带到最近的服务器。GeoDNS 在 WikiPedia 架构中担当重任固然是由  WikiPedia 的内容性质决定的--面向各个国家,各个地域。
  3. 负载均衡:LVS,请看下图:

  • 二、Facebook 架构

                                    Facebook 搜索功能的架构示意图

    细心的读者必定能发现,上副架构图以前出如今此文之中:从几幅架构图中偷得半点海里数据处理经验。本文与前文最大的不一样是,前文只有几幅,此文系列将有上百幅架构图,任您尽情观赏。

  • 三、Yahoo! Mail 架构

                                               Yahoo! Mail 架构

    Yahoo! Mail 架构部署了 Oracle RAC,用来存储 Mail 服务相关的 Meta 数据。

  • 四、twitter技术架构

                                                     twitter的总体架构设计图

    twitter平台大体由twitter.com、手机以及第三方应用构成,以下图所示(其中流量主要以手机和第三方为主要来源):

    缓存在大型web项目中起到了举足轻重的做用,毕竟数据越靠近CPU存取速度越快。下图是twitter的缓存架构图:

    关于缓存系统,还能够看看下幅图:

  • 五、Google App Engine技术架构

                                            GAE的架构图

    简单而言,上述GAE的架构分为如图所示的三个部分:前端,Datastore和服务群。

  1. 前端包括4个模块:Front End,Static Files,App Server,App Master。
  2. Datastore是基于BigTable技术的分布式数据库,虽然其也能够被理解成为一个服务,可是因为其是整个App Engine惟一存储持久化数据的地方,因此其是App Engine中一个很是核心的模块。其具体细节将在下篇和你们讨论。

  3. 整个服务群包括不少服务供App Server调用,好比Memcache,图形,用户,URL抓取和任务队列等。

  • 六、Amazon技术架构

                                    Amazon的Dynamo Key-Value存储架构图

    可能有读者并不熟悉Amazon,它如今已是全球商品品种最多的网上零售商和全球第2大互联网公司。而以前它仅仅是一个小小的网上书店。ok,下面,我们来见识下它的架构。

      Dynamo是亚马逊的key-value模式的存储平台,可用性和扩展性都很好,性能也不错:读写访问中99.9%的响应时间都在300ms内。按分布 式系统经常使用的哈希算法切分数据,分放在不一样的node上。Read操做时,也是根据key的哈希值寻找对应的node。Dynamo使用了  Consistent  Hashing算法,node对应的再也不是一个肯定的hash值,而是一个hash值范围,key的hash值落在这个范围内,则顺时针沿ring找,碰 到的第一个node即为所需。

    Dynamo对Consistent Hashing算法的改进在于:它放在环上做为一个node的是一组机器(而不是memcached把一台机器做为node),这一组机器是经过同步机制保证数据一致的。

    下图是分布式存储系统的示意图,读者可观摩之:

    Amazon的云架构图以下:

                                           Amazon的云架构图

  • 七、优酷网的技术架构

    从一开始,优酷网就自建了一套CMS来解决前端的页面显示,各个模块之间分离得比较恰当,前端可扩展性很好,UI的分离,让开发与维护变得十分简单和灵活,下图是优酷前端的模块调用关系:

    这样,就根据module、method及params来肯定调用相对独立的模块,显得很是简洁。下图是优酷的前端局部架构图:

    优酷的数据库架构也是经历了许多波折,从一开始的单台MySQL服务器(Just Running)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库。

  1. 简单的MySQL主从复制。 MySQL的主从复制解决了数据库的读写分离,并很好的提高了读的性能,其原来图以下:

    其主从复制的过程以下图所示:

    可是,主从复制也带来其余一系列性能瓶颈问题:

    1. 写入没法扩展
    2. 写入没法缓存
    3. 复制延时
    4. 锁表率上升
    5. 表变大,缓存率降低

    那问题产生总得解决的,这就产生下面的优化方案。

  2.  MySQL垂直分区

        若是把业务切割得足够独立,那把不一样业务的数据放到不一样的数据库服务器将是一个不错的方案,并且万一其中一个业务崩溃了也不会影响其余业务的正常进行,而且也起到了负载分流的做用,大大提高了数据库的吞吐能力。通过垂直分区后的数据库架构图以下:

        然而,尽管业务之间已经足够独立了,可是有些业务之间或多或少总会有点联系,如用户,基本上都会和每一个业务相关联,何况这种分区方式,也不能解决单张表数据量暴涨的问题,所以为什么不试试水平sharding呢?

  3.  MySQL水平分片(Sharding)

        这是一个很是好的思路,将用户按必定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增长,只要简单地配置一台服务器便可,原理图以下:

      如何来肯定某个用户所在的shard呢,能够建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,以下图所示:    可是,优酷是如何解决跨shard的查询呢,这个是个难点,据介绍优酷是尽可能不跨shard查询,实在不行经过多维分片索引、分布式搜索引擎,下策是分布式数据库查询(这个很是麻烦并且耗性能)。

  4.  缓存策略

    貌似大的系统都对“缓存”情有独钟,从http缓存到memcached内存数据缓存,但优酷表示没有用内存缓存,理由以下:

    1. 避免内存拷贝,避免内存锁
    2. 如接到老大哥通知要把某个视频撤下来,若是在缓存里是比较麻烦的

    并且Squid 的 write() 用户进程空间有消耗,Lighttpd 1.5 的 AIO(异步I/O) 读取文件到用户内存致使效率也比较低下。

    但 为什么咱们访问优酷会如此流畅,与土豆相比优酷的视频加载速度略胜一筹?这个要归功于优酷创建的比较完善的内容分发网络(CDN),它经过多种方式保证分布 在全国各地的用户进行就近访问——用户点击视频请求后,优酷网将根据用户所处地区位置,将离用户最近、服务情况最好的视频服务器地址传送给用户,从而保证 用户能够获得快速的视频体验。这就是CDN带来的优点,就近访问。

    附注:一、此段优酷网的技术架构整理于此处:http://www.itivy.com/ivy/archive/2011/8/13/the-architecture-of-youku.html;二、同时推荐一个很是好的站点:http://www.dbanotes.net/)。从上百幅架构图中学得半点大型网站建设经验(上),完。

后记

      此篇文章终于写完了,从昨日有整理此文的动机后,到今日上午找电脑上网而不得,再到此刻在网吧完成此文。着实也体味了一把什么叫作为技术狂热的感受。大型 网站架构是一个实战性很强的东西,而你我或许如今暂时还只是一个在外看热闹的门外汉而已。不过,不要紧,小鱼小虾照样能畅游汪汪大洋,更况且往后亦能成长 为大鱼大鲨。

相关文章
相关标签/搜索