Changes between Initial Version and Version 1 of Intro


Ignore:
Timestamp:
04/07/2013 12:24:30 PM (13 years ago)
Author:
chenchongqi
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Intro

    v1 v1  
     1原文出处:http://bbs.pconline.cn/topic-2065.html 
     2 
     3R 系统白皮书 
     4============ 
     5 
     6本文介绍R 系统的各种使用方法和背后的原因,是使用R系统前必须看明白的一份文档, 
     7也是使用过程中的参考,同时也是HTTP调用各种问题的一个总结 
     8 
     9 
     10是什么? 
     11======= 
     12R 系统是系统之间进行HTTP调用的一个统一的接口,封装了调用网络路由,HTTP调用和 
     13结果缓存三大模块,是对于系统之间HTTP调用多年经验的一个整理总结的结果 
     14 
     15 
     16为什么? 
     17======= 
     18在日常的开发中,系统之间进行HTTP调用是经常遇到的情况,但是要用好它并不是一件容 
     19易的事情,因为实际情况中WEB 是一个[非可靠]的[分布式网络]系统,调用过程中要解决 
     20各种不可控的情况需要经过深思熟虑才能做到,R 系统就是经过深思熟虑的一个设计 
     21 
     22 
     23需求 
     24==== 
     25经过慎密的分析,R 系统要解决一下问题: 
     261.  端到端的调用路由和负载均衡,自动化的路由表更新 
     272.  方便的调用方式和超时及出错/响应过慢处理 
     283.  对结果的缓冲和并发及故障保护,支持过期缓存使用扩展 
     29下面的使用场景说明会一步一步的说明各需求的应对情况 
     30 
     31使用前准备 
     32========== 
     33R 系统需要JDK6的版本 
     34resin/lib下需要放r-route-1.2.jar 
     35 
     36应用的WEB-INF/lib下需要放r-1.2.jar 
     37还要: 
     38memcached客户端2.0.1以上 
     39log4j-1.2.x以上 
     40commons-codec-1.4以上 
     41commons-logging-1.1.1以上 
     42httpcore-4.1以上 
     43httpclient-4.1.1以上 
     44 
     45通常和spring一起使用 
     46 
     47 
     48使用场景 
     49======== 
     50 
     511.  路由配置 
     52------------ 
     53{{{ 
     54                            +----------+ 
     55                    +-------| server-1 | ip:port 
     56+--------+   domain |       +----------+ 
     57| client |----------+           ... 
     58+--------+          |       +----------+ 
     59                    +-------| server-n | ip:port 
     60                            +----------+ 
     61}}} 
     62 
     63上图是最基本的调用结构,需求1 主要解决基本的路由和负载均衡问题,R 系统使用 
     64route 模块来解决相关的问题,route 会将域名调用对应到相关的ip:port 并进行轮询 
     65来实现负载均衡,并采用扫描四层交换机的方式来自动更新路由表,对于用户来说,只要 
     66使用适当的配置就可以解决需求1 的问题,下面我们说明一下路由相关配置方法 
     67 
     68在resin 的配置文件中加入进行R 系统的生产环境路由配置: 
     69{{{ 
     70------------------------------------------------------------------------------ 
     71<resource jndi-name="jca/pc_route" type="cn.pconline.r.route.PcRouteJNDI" > 
     72    <init> 
     73        <dnsAddr>192.168.238.75</dnsAddr> 
     74        <routeUri>http://192.168.237.61/route.txt</routeUri> 
     75        <routeOverwrite> 
     76            private.pcauto.com.cn=192.168.74.5:8888 
     77        </routeOverwrite> 
     78    </init> 
     79</resource> 
     80------------------------------------------------------------------------------ 
     81}}} 
     82routeOverwrite用于指定特殊的路由映射,用于虚拟域名等星空 
     83 
     84 
     85在resin 的配置文件中加入进行R 系统的开发、测试环境路由配置: 
     86{{{ 
     87------------------------------------------------------------------------------ 
     88<resource jndi-name="jca/pc_route" type="cn.pconline.r.route.ProxyRoute" > 
     89    <init> 
     90        <proxy>192.168.11.90:8080</proxy> 
     91        <routes> 
     92            ks.pcauto.com.cn=192.168.74.10:8081,192.168.47.11:8081 
     93            bbs.pcauto.com.cn=192.168.74.5:8888 
     94        </routes> 
     95    </init> 
     96</resource> 
     97------------------------------------------------------------------------------ 
     98}}} 
     99proxy 可以将对于域名的调用代理到公网,方便开发测试环境 
     100routes用于指定要使用开发、测试环境的那些机器来进行测试 
     101 
     102 
     103spring applicationContext.xml 配置: 
     104{{{ 
     105------------------------------------------------------------------------------ 
     106<jee:jndi-lookup id="route" jndi-name="jca/pc_route"/> 
     107------------------------------------------------------------------------------ 
     108}}} 
     109 
     110 
     1112.  HTTP调用(无缓冲) 
     112--------------------- 
     113cn.pconline.r.client.SimpleHttpTemplate 是HTTP调用的核心类,以模版方法的模式方便 
     114的进行HTTP调用,通常需要配置为采用route 进行路由,有多种get 和post方法提供使用, 
     115本模块会对于超时和错误进行合理的处理,用户配置好就可以方便使用 
     116 
     117 
     118spring applicationContext.xml 配置: 
     119{{{ 
     120------------------------------------------------------------------------------ 
     121<bean id="simpleHttpTemplate" class="cn.pconline.r.client.SimpleHttpTemplate" 
     122    init-method="init" 
     123    destroy-method="shutdown" 
     124    p:clientUri="http://myapp.pconline.com.cn" 
     125    p:connectTimeout="10000" 
     126    p:readTimeout="60000" 
     127    p:maxTotalConnections="300" 
     128    p:maxPerRoute="3" 
     129    p:route-ref="route"/> 
     130------------------------------------------------------------------------------ 
     131}}} 
     132 
     133五种get 方法: 
     134{{{ 
     135public String get(String uri, String refererUri); 
     136public String get(String uri, String refererUri, int readTimeout); 
     137public <T>T get(String uri, String refererUri, 
     138            ResponseExtractor<T> responseExtractor); 
     139public <T>T get(String uri, String refererUri, 
     140            RequestCallback requestCallback, 
     141            ResponseExtractor<T> responseExtractor); 
     142public <T>T get(String uri, String refererUri, 
     143            RequestCallback requestCallback, 
     144            ResponseExtractor<T> responseExtractor, int readTimeout); 
     145}}} 
     146 
     147三种post方法: 
     148{{{ 
     149public <T>T post(String uri, String refererUri, 
     150            ResponseExtractor<T> responseExtractor, HttpEntity entity); 
     151public <T>T post(String uri, String refererUri, 
     152            RequestCallback requestCallback, 
     153            ResponseExtractor<T> responseExtractor, HttpEntity entity); 
     154public <T>T post(String uri, String refererUri, 
     155            RequestCallback requestCallback, 
     156            ResponseExtractor<T> responseExtractor, HttpEntity entity,  
     157            int readTimeout); 
     158}}} 
     159 
     1603.  RClient 缓冲get 调用结果 
     161{{{ 
     162---------------------------- 
     163 
     164                                +----------+ 
     165                        +-------| server-1 | Cache-Control: max-age=900 
     166+--------+       domain |       +----------+ 
     167| client |----+---------+           ... 
     168+--------+    |         |       +----------+ 
     169              |         +-------| server-n | Cache-Control: max-age=900 
     170              |                 +----------+ 
     171        +-----+-----+ 
     172        | memcached | 
     173        +-----------+ 
     174}}} 
     175 
     176服务端指定缓冲时间,RClient 按照缓冲时间用memcached 进行结果缓冲,并处理并发 
     177调用相同uri 的情况 
     178 
     179 
     180 
     181resin 配置:(注意线上环境) 
     182{{{ 
     183--------------------------------------------------------------------------- 
     184<env-entry> 
     185    <description>MemCahcedClient config</description> 
     186    <env-entry-name>memcachedConfig</env-entry-name> 
     187    <env-entry-type>java.lang.String</env-entry-type> 
     188    <env-entry-value> 
     189        servers=127.0.0.1:11211 
     190        initConn=20 
     191        minConn=10 
     192        maxConn=50 
     193        maintSleep=30 
     194        nagle=false 
     195        socketTO=3000 
     196    </env-entry-value> 
     197</env-entry> 
     198------------------------------------------------------------------------------ 
     199}}} 
     200 
     201spring applicationContext.xml 配置: 
     202{{{ 
     203------------------------------------------------------------------------------ 
     204<jee:jndi-lookup id="memcachedConfig"  
     205    jndi-name="java:comp/env/memcachedConfig"/> 
     206<bean id="memcachedConfigFactory"  
     207    class="cn.pconline.r.util.MemCachedClientFactory" 
     208    p:config-ref="memcachedConfig" 
     209    p:poolName="r-test" 
     210    init-method="init" 
     211    destroy-method="shutdown"/> 
     212<bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient" 
     213    factory-bean="memcachedConfigFactory" 
     214    factory-method="getInstance"/> 
     215 
     216<bean id="rClient" class="cn.pconline.r.client.RClient" 
     217    init-method="init" 
     218    destroy-method="shutdown" 
     219    p:clientUri="http://app.pconline.com.cn" 
     220    p:connectTimeout="10000" 
     221    p:soTimeout="60000" 
     222    p:cacheMillis="3600000" 
     223    p:errorCacheMillis="300000" 
     224    p:slowMillis="10000" 
     225    p:httpThreads="10" 
     226    p:maxPerRoute="3" 
     227    p:maxRetry="3" 
     228    p:route-ref="route" 
     229    p:memCachedClient-ref="memcachedClient"/> 
     230------------------------------------------------------------------------------ 
     231 
     232public String get(final String uri,  final String refererUri,  
     233                  final int timeout, final TimeUnit timeUnit); 
     234}}} 
     235 
     236 
     2374.  RClient 持久化缓冲(后端故障时使用过期缓冲内容) 
     238{{{ 
     239---------------------------------------------------- 
     240 
     241        +----------+ 
     242        | mongodb  | 持久化缓冲KV存储 
     243        +----------+ 
     244              |                 +----------+ 
     245              |         +-------| server-1 | 
     246+--------+    |  domain |       +----------+ 
     247| client |----+---------+           ... 
     248+--------+    |         |       +----------+ 
     249              |         +-------| server-n | 
     250              |                 +----------+ 
     251        +-----+-----+ 
     252        | memcached | 
     253        +-----------+ 
     254}}} 
     255 
     256对于某些比较重要的内容,当后端失败时需要采用最近的旧数据提供服务,可以使用持久 
     257化缓冲的方式进行 
     258 
     259 
     260实现RClientHelper 扩展进行持久化缓冲 
     261{{{ 
     262------------------------------------------------------------------------------ 
     263public interface RClientHelper { 
     264 
     265    void update(String uri, String key, String content, 
     266            long resourceTimeMillis, long cacheLifeMillis); 
     267 
     268    R get(String uri, String key); 
     269 
     270} 
     271------------------------------------------------------------------------------ 
     272}}} 
     273 
     274spring applicationContext.xml 配置: 
     275{{{ 
     276------------------------------------------------------------------------------ 
     277<bean id="rClientHelper" class="..."> 
     278    <!-- mongodb config --> 
     279    ... 
     280</bean> 
     281 
     282<bean id="rClient" class="cn.pconline.r.client.RClient" 
     283    ... 
     284    p:helper-ref="rClientHelper" 
     285    ...> 
     286</bean> 
     287------------------------------------------------------------------------------ 
     288}}} 
     289 
     290RClient 调用get 方法时指定persistence 参数为true表示采用持久缓冲: 
     291{{{ 
     292public String get(final String uri,  final String refererUri,  
     293                  final boolean persistence, 
     294                  final int timeout, final TimeUnit timeUnit); 
     295}}} 
     296 
     297 
     298故障情景分析 
     299============ 
     300以前我曾经将HTTP服务的状态分为四种情况:死、慢、错、对,只有第四种才是好的服务 
     301状态,前三种都属于故障,下面我们分析一下R 系统是怎么应对这三种故障状态的 
     302 
     303我们还是按照SimpleHttpTemplate和RClient 两种情况进行分析会清楚一点 
     304{{{ 
     305 
     306 
     307                            +----------+ 
     308                    +-------| server-1 | ip:port 
     309+--------+   domain |       +----------+ 
     310| client |----------+           ... 
     311+--------+          |       +----------+ 
     312                    +-------| server-n | ip:port 
     313                            +----------+ 
     314}}} 
     315 
     316对于SimpleHttpTemplate,当全部后端死掉时,将返回最后一台访问状态,否则,返回 
     317成功请求的结果 
     318 
     319 
     320情况表 
     321{{{ 
     322----------------------------+------+------+------+------+------+------+ 
     323                            | all  | some | all  | some | all  | some | 
     324         Back failed status | die  | die  | slow | slow | err  | err  | 
     325--------------------+-------+------+------+------+------+------+------+ 
     326                    | GET   | fail |  OK  | fail |  OK  | fail |  OK  |  
     327 SimpleHttpTemplate +-------+------+------+------+------+------+------+ 
     328                    | POST  | fail |  OK  | fail |  O/F | fail |  O/F | 
     329--------------------+-------+------+------+------+------+------+------+ 
     330}}} 
     331O/F:  轮询时如果碰到好的就OK,碰到有问题的就失败 
     332要和大家再集体商量一次,最终做个了断 
     333 
     334 
     335 
     336 
     337 
     338{{{ 
     339        +----------+ 
     340        | mongodb  | 持久化缓冲KV存储 
     341        +----------+ 
     342              |                 +----------+ 
     343              |         +-------| server-1 | 
     344+--------+    |  domain |       +----------+ 
     345| client |----+---------+           ... 
     346+--------+    |         |       +----------+ 
     347              |         +-------| server-n | 
     348              |                 +----------+ 
     349        +-----+-----+ 
     350        | memcached | 
     351        +-----------+ 
     352}}} 
     353对于RClient, 当后端全部死掉时,还要看缓存的情况,有没有持久缓存也不同 
     354 
     355情况表 
     356{{{ 
     357------------------------------------+-----------+-----------+ 
     358    Back server failed status       | all fail  | some fail | 
     359------------------------+-----------+-----------+-----------+ 
     360         memcached      |persistence|-----------------------|            
     361------------------------+-----------+-----------+-----------+ 
     362         mc valid       |           |    OK     |    OK     | 
     363------------------------+           +-----------+-----------+ 
     364         mc expiried    |    no     |    BLANK  |    OK     | 
     365------------------------+           +-----------+-----------+ 
     366         mc LRU out     |           |    BLANK  |    OK     | 
     367------------------------+-----------+-----------+-----------+ 
     368         mc valid       |           |    OK     |    OK     | 
     369------------------------+           +-----------+-----------+ 
     370         mc expiried    |    yes    |   OK/OLD  |    OK     |   
     371------------------------+           +-----------+-----------+ 
     372         mc LRU out     |           |   OK/OLD  |    OK     | 
     373------------------------+-----------+-----------+-----------+ 
     374}}} 
     375OK/OLD:  如果缓存没有过期就是OK,已经过期就是旧的 
     376 
     377 
     378 
     379内部流程 
     380======== 
     381 
     382分别说明SimpleHttpTemplate和RClient的内部流程 
     383 
     384SimpleHttpTemplate 
     385------------------ 
     386本模块是对Apache HttpClient 的简单封装,没有使用另外的线程进行异步处理,整个 
     387调用对于应用来说是同步的,下面的配置除了clientUri外,都是直接的设置 
     388{{{ 
     389    p:clientUri="http://myapp.pconline.com.cn" 
     390    p:connectTimeout="10000" 
     391    p:readTimeout="60000" 
     392    p:maxTotalConnections="300" 
     393    p:maxPerRoute="3" 
     394}}} 
     395实际的流程是: 
     3961 用户请求uri 
     3972 模块根据uri获得后端服务器的列表 
     3983 向一个轮询出的服务器请求 
     3994 请求成功返回结果 
     400  4.1 请求不成功,判断是否请求下一个服务器 
     401     4.1.1不需要请求下一个,则返回成功结果 
     402     4.1.2需要请求下一个,则从列表中拿出下一个,到第4布进行请求 
     403 
     404* 是否请求下一个服务器的标准按照前文的情况表决定 
     405 
     406 
     407RClient 
     408------- 
     409本模块采用异步的方式,有专门的线程进行异步的HTTP请求,对于请求的结果,采用 
     410memcached 进行缓冲,必要时采用mongodb 之类的KV存储对结果进行持久化存储, 
     411对于相同的uri 请求进行并发请求标志保护,同一个uri过期时理论上只有一个HTTP请求 
     412会到后端去请求,配置如下,前四与simpleHttpTemplate 相同,都是直接设置 
     413Apache HttpClient, 最后三个用于缓冲时间设置  
     414{{{ 
     415    p:clientUri="http://app.pconline.com.cn" 
     416    p:connectTimeout="10000" 
     417    p:soTimeout="60000" 
     418    p:maxPerRoute="3" 
     419    p:httpThreads="10" 
     420    p:maxRetry="3" 
     421    p:cacheMillis="3600000" 
     422    p:errorCacheMillis="300000" 
     423    p:slowMillis="10000" 
     424}}} 
     425流程: 
     426细节看代码好点... 
     4271 请求memcached,有结果返回 
     4282 请求mongodb,结果未过期返回,同时设置memcached 
     4293 异步请求后端,正常时返回,同时设置memcached和mongodb 
     430 
     431  后端访问为轮询(maxRetry会限制轮询的次数), 
     432  遇到正常结果终止轮询,或者返回最后的结果 
     433 
     434{{{ 
     435                +-------+ 
     436                |mongodb| 
     437                +---+---+ 
     438                    | 
     439                +---+-------------------------------+           +--------+ 
     440                |   |          RClient              |    +------|server-1| 
     441+------+        |   |   +------+                    |    |      +--------+ 
     442|client|--------+---+--$|Thread|      +----------+  |    |  
     443+------+        |   |   | Pool |------|HttpClient|--+----+      ... 
     444                |   |   +------+      +----------+  |    | 
     445                |   |                               |    |      +--------+ 
     446                +---+-------------------------------+    +------|server-n| 
     447                    |                                           +--------+ 
     448                +---+-----+ 
     449                |memcached| 
     450                +---------+ 
     451 
     452------------------------------------------------------------------------------ 
     453}}}