paulwong

          #

          優(yōu)化程序之前,可用Jamon來監(jiān)測(cè)你的Spring應(yīng)用

          /**
          *作者:張榮華(ahuaxuan)
          *2007-8-15
          *轉(zhuǎn)載請(qǐng)注明出處及作者
          */

          前兩天在看Spring內(nèi)置的攔截器的時(shí)候,發(fā)現(xiàn)了一個(gè)之前沒有注意的類:org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor,好奇心促使我上網(wǎng)查了一下這個(gè)jamon。大概看了一下之后發(fā)現(xiàn)這個(gè)玩意還真挺好用的而且挺重要的,而且現(xiàn)在國內(nèi)對(duì)它的介紹也很少,所以寫了一篇文章和大家分享。

          一,Jamon簡(jiǎn)介:
          Jamon的全名是:Java Application Monitor。它是一個(gè)小巧的,免費(fèi)的,高性能的,線程安全的性能監(jiān)測(cè)工具。它可以用來測(cè)定系統(tǒng)的性能瓶頸,也可以用來監(jiān)視用戶和應(yīng)用程序之間的交互情況。 Jamon主要是用來檢測(cè)jee的應(yīng)用程序。它最新的版本是2.1,可以用在1.4以上的jdk上。

          二,將jamon導(dǎo)入到你的應(yīng)用程序中去
          首先下載jamon的開發(fā)包,見我的附件,同時(shí)你也可以去Sourceforge上自己下載。Sourceforge的下載地址為http://jamonapi.sourceforge.net。解壓之后可以得到一個(gè)jar包和一個(gè)war包。jar包是自己會(huì)用到的,而war包是一個(gè)例子(不要小看這個(gè)例子,待會(huì)也要把它導(dǎo)入到項(xiàng)目中)。把war包之間丟到服務(wù)器上,訪問:localhost:8080/jamon就可以看到這個(gè)例子了,這個(gè)例子是一個(gè)簡(jiǎn)單的性能監(jiān)控系統(tǒng)。

          接著把例子中的所有的包都導(dǎo)入到項(xiàng)目中,并把war包中的jsp和images還有css都考到項(xiàng)目中,比如新建一個(gè)目錄叫monitor(它和WEB-INF是同級(jí)目錄)。

          三,正確配置自己的應(yīng)用
          我們?cè)谛阅鼙O(jiān)測(cè)的時(shí)候最監(jiān)測(cè)的就是頁面的訪問率和類中方法的訪問率。所以在這一部分主要講解一下如何監(jiān)測(cè)自己的頁面和類中方法的訪問。

          1, 檢測(cè)自己的頁面訪問率
          首先我們需要在web.xml中添加一個(gè)filter,這個(gè)filter就是用來判斷哪些頁面需要被監(jiān)視的,如下所示:
          <filter>
                  
          <filter-name>JAMonFilter</filter-name>
                  
          <filter-class>com.easywebwork.filter.EasyPageMonFilter</filter-class>
              
          </filter>
              
          <filter-mapping>
                  
          <filter-name>JAMonFilter</filter-name>
                  
          <url-pattern>/*</url-pattern>
              
          </filter-mapping>

          接下來我們看看這個(gè)filter的寫法:

          /**
          *
          @author 張榮華(ahuaxuan)
          *
          *
          @since 2007-8-13
          */

          public class PageMonFilter extends JAMonFilter{

          private static final long serialVersionUID = 5746197114960908454L;

          public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
          Monitor allPages
          = MonitorFactory.start(new MonKeyImp("org.easywebwork.allPages",getURI(request),"ms."));
          //這里就是我們要監(jiān)視的所有的頁面的配置
          Monitor monitor = MonitorFactory.start(getURI(request));
          //這里就是我們要監(jiān)視的某個(gè)頁面的配置
          try {
          filterChain.doFilter(request, response);
          }
          finally {
          monitor.stop();
          allPages.stop();
          }

          }


          protected String getURI(ServletRequest request) {
          if (request instanceof HttpServletRequest) {
          return ((HttpServletRequest) request).getRequestURI();
          }
          else {
          return "Not an HttpServletRequest";
          }

          }


          private FilterConfig filterConfig = null;

          }
          }

          這個(gè)類看上去很簡(jiǎn)單,其實(shí)也挺簡(jiǎn)單的,就是得到uri,然后把它注冊(cè)到MonitorFactory類中。這樣只要我們?nèi)ピL問剛才創(chuàng)建的monitor目錄下的jsp就可以看到性能監(jiān)測(cè)頁面了。

          2, 接下來我們看看在使用spring的情況下如何監(jiān)測(cè)一個(gè)bean的方法調(diào)用。
          Spring也提供了對(duì)Jamon的支持(spring支持的東西還真多啊),也就是文章開頭提出的那個(gè)攔截器,為了給我們的bean加上攔截器,我們?cè)趕pring的applicationcontext配置文件中加入如下語句:

          <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
          <list>
          <value>userService</value>
          </list>
          </property>
          <property name="interceptorNames">
          <list>
          <value>jamonInterceptor</value>
          </list>
          </property>
          </bean>

          <bean id="jamonInterceptor" class="org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor">
          </bean>

          上面這個(gè)是典型的spring的aop的配置,如果對(duì)spring的aop配置不了解的可以去看一下spring中文文檔,當(dāng)然如果不想了解的話即使直接把這段配置拷到自己的項(xiàng)目中也是可以直接使用的。

          還有一個(gè)步驟就是在你的log4j.properties中加入這句代碼:

          log4j.logger.org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor = TRACE


          如果沒有這一行,那么這個(gè)攔截器是不會(huì)把方法調(diào)用的信息向MonitorFactory注冊(cè)的。

          只需要這些步驟,userservice中的方法在調(diào)用的時(shí)候就可以被攔截,然后將其注冊(cè)到MonitorFactory中去了。

          所有的配置完成之后我們來看一下效果吧:
          http://www.iteye.com/topics/download/b2bac96e-6c18-4340-b7e0-f84c7bb6adca從這個(gè)圖上我們可以看到,所有頁面被訪問的次數(shù),UserService中的getAllUsers被調(diào)用的次數(shù),最右邊的是訪問時(shí)間。這只是整個(gè)圖的一部分,當(dāng)然這個(gè)頁面中也包括每一個(gè)頁面被訪問的次數(shù)和第一次訪問的時(shí)間等等。下載附件運(yùn)行,就可以看到所有的頁面了。

          三,總結(jié)
          根據(jù)以上的步驟,我們就可以監(jiān)測(cè)我們的程序了,應(yīng)用程序中哪些頁面被訪問的多,哪些頁面被訪問的少,哪些方法被訪問的多,哪些方法被訪問的少,以及訪問高峰期集中在什么時(shí)間等等,有了這些參數(shù),我們更可以有針對(duì)性的對(duì)應(yīng)用程序進(jìn)行優(yōu)化了,比如說某個(gè)頁面訪問比較頻繁,我就可以用ehcache或oscache給這個(gè)頁面做一個(gè)緩存。如果某個(gè)方法的訪問比較頻繁那就看看這個(gè)方法能否進(jìn)一步優(yōu)化,是需要異步,還是需要緩存,還是需要其他等等,總之有了jamon可以給我們帶來更多的便捷,既可以讓我們知道我們的客戶的行為,也可以讓我們知道我們開發(fā)的程序的“能力”。

          其實(shí)本文提供的只是對(duì)頁面和方法調(diào)用的監(jiān)控,但是jamon可以提供更多功能,比如說sql語句的監(jiān)控等等,這就需要我們共同去發(fā)掘了。

          附件中包括了一個(gè)easywebwork的例子,我把jamon導(dǎo)入到這個(gè)例子工程中去,大家可以直接下載運(yùn)行觀看效果。Easywebwork是一個(gè)旨在減少webwork2.2.x系列的xml配置文件的項(xiàng)目。

        1. JamonSample.rar (3.7 MB)
        2. 描述: 由于上傳文件大小有限制,所以需要同學(xué)們自己添加一下jar包: spring,common-logging,log4j,common-collections activation, common-lang

           

        3. lib.rar (3.3 MB)
        4. 描述: 第二組包包括 spring,common-logging,log4j,common-collections activation, common-lang

           

        5. posted @ 2012-01-25 16:32 paulwong 閱讀(761) | 評(píng)論 (0)編輯 收藏

          memcache-client-forjava

          http://code.google.com/p/memcache-client-forjava/
          http://marc.iteye.com/blog/28700
          http://www.jayxu.com/2010/06/09/2342/
          http://www.iteye.com/topic/128458
          http://code.google.com/p/xmemcached/wiki/User_Guide_zh

          posted @ 2012-01-24 20:34 paulwong 閱讀(403) | 評(píng)論 (0)編輯 收藏

          EhCache 緩存系統(tǒng)簡(jiǎn)介

               摘要: EhCache 是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、精干等特點(diǎn),是Hibernate中默認(rèn)的CacheProvider。 下圖是 EhCache 在應(yīng)用程序中的位置: EhCache 的主要特性有: 1. 快速.2. 簡(jiǎn)單.3. 多種緩存策略4. 緩存數(shù)據(jù)有兩級(jí):內(nèi)存和磁盤,因此無需擔(dān)心容量問題5. 緩存數(shù)據(jù)會(huì)在虛擬機(jī)重啟的過程中寫入磁盤6. 可以通過RMI、可插入API...  閱讀全文

          posted @ 2012-01-24 20:32 paulwong 閱讀(1443) | 評(píng)論 (0)編輯 收藏

          ehcache configuration (cluster env)

           <ehcache>

              
          <!-- Sets the path to the directory where cache .data files are created.

                   If the path is a Java System Property it is replaced by
                   its value in the running VM.

                   The following properties are translated:
                   user.home - User's home directory
                   user.dir - User's current working directory
                   java.io.tmpdir - Default temp file path 
          -->
              
          <diskStore path="java.io.tmpdir/service"/>

              
          <cacheManagerPeerProviderFactory
                  
          class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
                  properties
          ="peerDiscovery=automatic, multicastGroupAddress=230.0.0.3,
                  multicastGroupPort=4446, timeToLive=0"
          />
             
              
          <cacheManagerPeerListenerFactory
                  
          class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
                  properties
          ="hostName=, port=40003,
                  socketTimeoutMillis=12000"
          />
                             
              
          <!--Default Cache configuration. These will applied to caches programmatically created through
                  the CacheManager.

                  The following attributes are required:

                  maxInMemory
                    - Sets the maximum number of objects that will be created in memory

                  eternal
                    - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element is never expired.
                  
                    overflowToDisk
                    - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit.

                  The following attributes are optional:
                  timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                                   i.e. The maximum amount of time between accesses before an element expires
                                                   Is only used if the element is not eternal.
                                                   Optional attribute. A value of 0 means that an Element can idle for infinity.
                                                   The default value is 0.
                  timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                                   i.e. The maximum time between creation time and when an element expires.
                                                   Is only used if the element is not eternal.
                                                   Optional attribute. A value of 0 means that and Element can live for infinity.
                                                   The default value is 0.
                  diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                                   The default value is false.
                  diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                                   is 120 seconds.
                  
          -->
             
              
          <defaultCache
                  
          maxElementsInMemory="1000000000"
                  eternal
          ="true"
                  overflowToDisk
          ="false"
                  diskPersistent
          ="false"
                  memoryStoreEvictionPolicy
          ="LRU">
                  
          <cacheEventListenerFactory
                      
          class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
                      properties
          ="replicateAsynchronously=true, replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=true replicateRemovals=true asynchronousReplicationIntervalMillis=1000"/>
              
          </defaultCache>
             
              
          <cache name="com.ubs.swidGLK.METHOD_CACHE"
                  maxElementsInMemory
          ="10000"
                  eternal
          ="true"
                  overflowToDisk
          ="false"
                  diskPersistent
          ="false"
                  memoryStoreEvictionPolicy
          ="LRU">
                  
          <cacheEventListenerFactory
                      
          class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
              
          </cache>
          </ehcache>

          http://www.oschina.net/question/12_3984

          posted @ 2012-01-23 23:22 paulwong 閱讀(339) | 評(píng)論 (0)編輯 收藏

          由12306.cn談?wù)劸W(wǎng)站性能技術(shù)

          12306.cn網(wǎng)站掛了,被全國人民罵了。我這兩天也在思考這個(gè)事,我想以這個(gè)事來粗略地和大家討論一下網(wǎng)站性能的問題。因?yàn)閭}促,而且完全基于 本人有限的經(jīng)驗(yàn)和了解,所以,如果有什么問題還請(qǐng)大家一起討論和指正。(這又是一篇長(zhǎng)文,只討論性能問題,不討論那些UI,用戶體驗(yàn),或是是否把支付和購 票下單環(huán)節(jié)分開的功能性的東西)

          業(yè)務(wù)

          任何技術(shù)都離不開業(yè)務(wù)需求,所以,要說明性能問題,首先還是想先說說業(yè)務(wù)問題。
          • 其一有人可能把這個(gè)東西和QQ或是網(wǎng)游相比。但我覺得這兩者是不一樣的,網(wǎng)游和QQ在線或是登錄時(shí)訪問的更多的是用戶自己的數(shù)據(jù),而訂票系統(tǒng)訪問的是中心的票量數(shù)據(jù),這是不一樣的。不要覺得網(wǎng)游或是QQ能行你就以為這是一樣的。網(wǎng)游和QQ 的后端負(fù)載相對(duì)于電子商務(wù)的系統(tǒng)還是簡(jiǎn)單。
          • 其二有人說春節(jié)期間訂火車的這個(gè)事好像網(wǎng)站的秒殺活動(dòng)。的確很相似, 但 是如果你的思考不在表面的話,你會(huì)發(fā)現(xiàn)這也有些不一樣。火車票這個(gè)事,還有很多查詢操作,查時(shí)間,查座位,查鋪位,一個(gè)車次不 行,又查另一個(gè)車次,其伴隨著大量的查詢操作,下單的時(shí)候需要對(duì)數(shù)據(jù)庫操作。而秒殺,直接殺就好了。另外,關(guān)于秒殺,完全可以做成只接受前N個(gè)用戶的請(qǐng)求 (完全不操作后端的任何數(shù)據(jù), 僅僅只是對(duì)用戶的下單操作log),這種業(yè)務(wù),只要把各個(gè)服務(wù)器的時(shí)間精確同步了就可以了,無需在當(dāng)時(shí)操作任何數(shù)據(jù)庫。可以訂單數(shù)夠后,停止秒殺,然后批 量寫數(shù)據(jù)庫。火車票這個(gè)豈止是秒殺那么簡(jiǎn)單。能不能買到票得當(dāng)時(shí)告訴用戶啊。
          • 其三有人拿這個(gè)系統(tǒng)和奧運(yùn)會(huì)的票務(wù)系統(tǒng)比較。我覺得還是不一樣。雖然奧運(yùn)會(huì)的票務(wù)系統(tǒng)當(dāng)年也一上線就廢了。但是奧運(yùn)會(huì)用的是抽獎(jiǎng)的方式,也就是說不存在先來先得的搶的方式,而且,是事后抽獎(jiǎng),事前只需要收信息,事前不需要保證數(shù)據(jù)一致性,沒有鎖,很容易水平擴(kuò)展。
          • 其四訂票系統(tǒng)應(yīng)該和電子商務(wù)的訂單系統(tǒng)很相似,都是需要對(duì)庫存進(jìn) 行:1)占住庫存,2)支付(可選),3)扣除庫存的操作。這個(gè)是需要有一致性的檢查的,也就是在并發(fā)時(shí)需要對(duì)數(shù)據(jù)加鎖的。B2C的電商基本上都會(huì)把這個(gè) 事干成異步的,也就是說,你下的訂單并不是馬上處理的,而是延時(shí)處理的,只有成功處理了,系統(tǒng)才會(huì)給你一封確認(rèn)郵件說是訂單成功。我相信有很多朋友都收到 認(rèn)單不成功的郵件。這就是說,數(shù)據(jù)一致性在并發(fā)下是一個(gè)瓶頸
          • 其五鐵路的票務(wù)業(yè)務(wù)很變態(tài),其采用的是突然放票,而有的票又遠(yuǎn)遠(yuǎn)不夠 大家分,所以,大家才會(huì)有搶票這種有中國特色的業(yè)務(wù)的做法。于是當(dāng)票放出來的時(shí)候,就會(huì)有幾百萬人甚至上千萬人殺上去,查詢,下單。幾十分鐘內(nèi),一個(gè)網(wǎng)站 能接受幾千萬的訪問量,這個(gè)是很恐怖的事情。據(jù)說12306的高峰訪問是10億PV,集中在早8點(diǎn)到10點(diǎn),每秒PV在高峰時(shí)上千萬。
          多說幾句:
          • 庫存是B2C的惡夢(mèng),庫存管理相當(dāng)?shù)膹?fù)雜。不信,你可以問問所有傳統(tǒng)和電務(wù)零售業(yè)的企業(yè),看看他們管理庫存是多么難的一件事。不然,就不會(huì)有那么多人在問凡客的庫存問題了。(你還可以看看《喬布斯傳》,你就知道為什么Tim會(huì)接任Apple的CEO了,因?yàn)樗愣颂O果的庫存問題)
          • 對(duì)于一個(gè)網(wǎng)站來說,瀏覽網(wǎng)頁的高負(fù)載很容易搞定,查詢的負(fù)載有一定的難度去處理,不過還是可以通過緩存查詢結(jié)果來搞定,最難的就是下單的負(fù)載。因?yàn)橐L問庫存啊,對(duì)于下單,基本上是用異步來搞定的。去年雙11節(jié),淘寶的每小時(shí)的訂單數(shù)大約在60萬左右,京東一天也才能支持40萬(居然比12306還差),亞馬遜5年前一小時(shí)可支持70萬訂單量。可見,下訂單的操作并沒有我們相像的那么性能高。
          • 淘寶要比B2C的網(wǎng)站要簡(jiǎn)單得多,因?yàn)闆]有倉庫,所以,不存在像B2C這樣有N個(gè)倉庫對(duì)同一商品庫存更新和 查 詢的操作。下單的時(shí)候,B2C的 網(wǎng)站要去找一個(gè)倉庫,又要離用戶近,又要有庫存,這需要很多計(jì)算。試想,你在北京買了一本書,北京的倉庫沒貨了,就要從周邊的倉庫調(diào),那就要去看看沈陽或 是西安的倉庫有沒有貨,如果沒有,又得看看江蘇的倉庫,等等。淘寶的就沒有那么多事了,每個(gè)商戶有自己的庫存,庫存分到商戶頭上了,反而有利于性能。
          • 數(shù)據(jù)一致性才是真正的性能瓶頸。有 人說nginx可以搞定每秒10萬的靜態(tài)請(qǐng)求,我不懷疑。但這只是靜態(tài)請(qǐng)求,理論值,只要帶寬、I/O夠強(qiáng),服務(wù)器計(jì)算能力夠,并支持的并發(fā)連接數(shù)頂?shù)米?10萬TCP鏈接的建立 的話,那沒有問題。但在數(shù)據(jù)一致性面前,這10萬就完完全全成了一個(gè)可望不可及的理論值了。
          我說那么多,我只是想從業(yè)務(wù)上告訴大家,我們需要從業(yè)務(wù)上真正了解春運(yùn)鐵路訂票這樣業(yè)務(wù)的變態(tài)之處。

          前端性能優(yōu)化技術(shù)

          要解決性能的問題,有很多種常用的方法,我在下面列舉一下,我相信12306這個(gè)網(wǎng)站使用下面的這些技術(shù)會(huì)讓其性能有質(zhì)的飛躍。
          一、前端負(fù)載均衡
          通過DNS的負(fù)載均衡器(一般在路由器上根據(jù)路由的負(fù)載重定向)可以把用戶的訪問均勻地分散在多個(gè)Web服務(wù)器上。這樣可以減少Web服務(wù)器的請(qǐng)求 負(fù)載。因?yàn)閔ttp的請(qǐng)求都是短作業(yè),所以,可以通過很簡(jiǎn)單的負(fù)載均衡器來完成這一功能。最好是有CDN網(wǎng)絡(luò)讓用戶連接與其最近的服務(wù)器(CDN通常伴隨 著分布式存儲(chǔ))。(關(guān)于負(fù)載均衡更為詳細(xì)的說明見“后端的負(fù)載均衡”)
          二、減少前端鏈接數(shù)
          我看了一下12306.cn,打開主頁需要建60多個(gè)HTTP連接,車票預(yù)訂頁面則有70多個(gè)HTTP請(qǐng)求,現(xiàn)在的瀏覽器都是并發(fā)請(qǐng)求的。所以,只 要有100萬個(gè)用戶,就會(huì)有6000萬個(gè)鏈接,太多了。一個(gè)登錄查詢頁面就好了。把js打成一個(gè)文件,把css也打成一個(gè)文件,把圖標(biāo)也打成一個(gè)文件,用 css分塊展示。把鏈接數(shù)減到最低。
          三、減少網(wǎng)頁大小增加帶寬
          這個(gè)世界不是哪個(gè)公司都敢做圖片服務(wù)的,因?yàn)閳D片太耗帶寬了。現(xiàn)在寬帶時(shí)代很難有人能體會(huì)到當(dāng)撥號(hào)時(shí)代做個(gè)圖頁都不敢用圖片的情形(現(xiàn)在在手機(jī)端瀏 覽也是這個(gè)情形)。我查看了一下12306首頁的需要下載的總文件大小大約在900KB左右,如果你訪問過了,瀏覽器會(huì)幫你緩存很多,只需下載10K左右 的文件。但是我們可以想像一個(gè)極端一點(diǎn)的案例,1百萬用戶同時(shí)訪問,且都是第一次訪問,每人下載量需要1M,如果需要在120秒內(nèi)返回,那么就需要,1M * 1M /120 * 8 = 66Gbps的帶寬。很驚人吧。所以,我估計(jì)在當(dāng)天,12306的阻塞基本上應(yīng)該是網(wǎng)絡(luò)帶寬,所以,你可能看到的是沒有響應(yīng)。后面隨著瀏覽器的緩存幫助 12306減少很多帶寬占用,于是負(fù)載一下就到了后端,后端的數(shù)據(jù)處理瓶頸一下就出來。于是你會(huì)看到很多http 500之類的錯(cuò)誤。這說明服務(wù)器垮了。
          四、前端頁面靜態(tài)化
          靜態(tài)化一些不覺變的頁面和數(shù)據(jù),并gzip一下。還有一個(gè)并態(tài)的方法是把這些靜態(tài)頁面放在/dev/shm下,這個(gè)目錄就是內(nèi)存,直接從內(nèi)存中把文件讀出來返回,這樣可以減少昂貴的磁盤I/O。
          五、優(yōu)化查詢
          很多人查詢都是在查一樣的,完全可以用反向代理合并這些并發(fā)的相同的查詢。這樣的技術(shù)主要用查詢結(jié)果緩存來實(shí)現(xiàn),第一次查詢走數(shù)據(jù)庫獲得數(shù)據(jù),并把 數(shù)據(jù)放到緩存,后面的查詢統(tǒng)統(tǒng)直接訪問高速緩存。為每個(gè)查詢做Hash,使用NoSQL的技術(shù)可以完成這個(gè)優(yōu)化。(這個(gè)技術(shù)也可以用做靜態(tài)頁面) 對(duì)于火車票量的查詢,個(gè)人覺得不要顯示數(shù)字,就顯示一個(gè)“有”或“無”就好了,這樣可以大大簡(jiǎn)化系統(tǒng)復(fù)雜度,并提升性能。
          六、緩存的問題
          緩存可以用來緩存動(dòng)態(tài)頁面,也可以用來緩存查詢的數(shù)據(jù)。緩存通常有那么幾個(gè)問題: 1)緩存的更新。也叫緩存和數(shù)據(jù)庫的同步。有這么幾種方法,一是緩存time out,讓緩存失效,重查,二是,由后端通知更新,一量后端發(fā)生變化,通知前端更新。前者實(shí)現(xiàn)起來比較簡(jiǎn)單,但實(shí)時(shí)性不高,后者實(shí)現(xiàn)起來比較復(fù)雜 ,但實(shí)時(shí)性高。 2)緩存的換頁。內(nèi)存可能不夠,所以,需要把一些不活躍的數(shù)據(jù)換出內(nèi)存,這個(gè)和操作系統(tǒng)的內(nèi)存換頁和交換內(nèi)存很相似。FIFO、LRU、LFU都是比較經(jīng)典的換頁算法。相關(guān)內(nèi)容參看Wikipeida的緩存算法。 3)緩存的重建和持久化。緩存在內(nèi)存,系統(tǒng)總要維護(hù),所以,緩存就會(huì)丟失,如果緩存沒了,就需要重建,如果數(shù)據(jù)量很大,緩存重建的過程會(huì)很慢,這會(huì)影響生產(chǎn)環(huán)境,所以,緩存的持久化也是需要考慮的。 諸多強(qiáng)大的NoSQL都很好支持了上述三大緩存的問題。

          后端性能優(yōu)化技術(shù)

          前面討論了前端性能的優(yōu)化技術(shù),于是前端可能就不是瓶頸問題了。那么性能問題就會(huì)到后端數(shù)據(jù)上來了。下面說幾個(gè)后端常見的性能優(yōu)化技術(shù)。
          一、數(shù)據(jù)冗余
          關(guān)于數(shù)據(jù)冗余,也就是說,把我們的數(shù)據(jù)庫的數(shù)據(jù)冗余處理,也就是減少表連接這樣的開銷比較大的操作,但這樣會(huì)犧牲數(shù)據(jù)的一致性。風(fēng)險(xiǎn)比較大。很多人 把NoSQL用做數(shù)據(jù),快是快了,因?yàn)閿?shù)據(jù)冗余了,但這對(duì)數(shù)據(jù)一致性有大的風(fēng)險(xiǎn)。這需要根據(jù)不同的業(yè)務(wù)進(jìn)行分析和處理。(注意:用關(guān)系型數(shù)據(jù)庫很容易移植 到NoSQL上,但是反過來從NoSQL到關(guān)系型就難了)
          二、數(shù)據(jù)鏡像
          幾乎所有主流的數(shù)據(jù)庫都支持鏡像,也就是replication。數(shù)據(jù)庫的鏡像帶來的好處就是可以做負(fù)載均衡。把一臺(tái)數(shù)據(jù)庫的負(fù)載均分到多臺(tái)上,同時(shí)又保證了數(shù)據(jù)一致性(Oracle的SCN)。最重要的是,這樣還可以有高可用性,一臺(tái)廢了,還有另一臺(tái)在服務(wù)。 數(shù)據(jù)鏡像的數(shù)據(jù)一致性可能是個(gè)問題,所以我們要吧在單條數(shù)據(jù)上進(jìn)行數(shù)據(jù)分區(qū),也就是說,把一個(gè)暢銷商品的庫存均分到不同的服務(wù)器上,如,一個(gè)暢銷商品有1萬的庫存,我們可以設(shè)置10臺(tái)服務(wù)器,每臺(tái)服務(wù)器上有100個(gè)庫存,這就好像B2C的倉庫一樣。
          三、數(shù)據(jù)分區(qū)
          數(shù)據(jù)鏡像不能解決的一個(gè)問題就是數(shù)據(jù)表里的記錄太多,導(dǎo)致數(shù)據(jù)庫操作太慢。所以,把數(shù)據(jù)分區(qū)。數(shù)據(jù)分區(qū)有很多種做法,一般來說有下面這幾種:

          1)把數(shù)據(jù)把某種邏輯來分類。比如火車票的訂票系統(tǒng)可以按各鐵路局來分,可按各種車型分,可以按始發(fā)站分,可以按目的地分……,反正就是把一張表拆成多張有一樣的字段但是不同種類的表,這樣,這些表就可以存在不同的機(jī)器上以達(dá)到分擔(dān)負(fù)載的目的。

          2)把數(shù)據(jù)按字段分,也就是堅(jiān)著分表。比如把一些不經(jīng)常改的數(shù)據(jù)放在一個(gè)表里,經(jīng)常改的數(shù)據(jù)放在另一個(gè)表里。把一張表變成1對(duì)1的關(guān)系,這樣,你可 以減少表的字段個(gè)數(shù),同樣可以提升一定的性能。另外,字段多會(huì)造成一條記錄的存儲(chǔ)會(huì)被放到不同的頁表里,這對(duì)于讀寫性能都有問題。

          3)平均分表。因?yàn)榈谝环N方法是并不一定平均分均,可能某個(gè)種類的數(shù)據(jù)還是很多。所以,也有采用平均分配的方式,通過主鍵ID的范圍來分表。

          4)同一數(shù)據(jù)分區(qū)。這個(gè)在上面數(shù)據(jù)鏡像提過。也就是把同一商品的庫存值分到不同的服務(wù)器上,比如有10000個(gè)庫存,可以分到10臺(tái)服務(wù)器上,一臺(tái)上有1000個(gè)庫存。然后負(fù)載均衡。 這三種分區(qū)都有好有壞。最常用的還是第一種。數(shù)據(jù)一量分區(qū),你就需要有一個(gè)或是多個(gè)調(diào)度來讓你的前端程序知道去哪里找數(shù)據(jù)。把火車票的數(shù)據(jù)分區(qū),并放在各個(gè)省市,會(huì)對(duì)12306這個(gè)系統(tǒng)有非常有意義的質(zhì)的性能的提高
          四、后端系統(tǒng)負(fù)載均衡
          前面說了數(shù)據(jù)分區(qū),數(shù)據(jù)分區(qū)可以在一定程度上減輕負(fù)載,但是無法減輕熱銷商品的負(fù)載,對(duì)于火車票來說,可以認(rèn)為是大城市的某些主干線上的車票。這就 需要使用數(shù)據(jù)鏡像來減輕負(fù)載。使用數(shù)據(jù)鏡像,你必然要使用負(fù)載均衡,在后端,我們可能很難使用像路由器上的負(fù)載均衡器,因?yàn)槟鞘蔷饬髁康模驗(yàn)榱髁坎⒉?代表服務(wù)器的繁忙程序。因此,我們需要一個(gè)任務(wù)分配系統(tǒng),其還能監(jiān)控各個(gè)服務(wù)器的負(fù)載情況。 任務(wù)分配服務(wù)器有一些難點(diǎn):
          • 負(fù)載情況比較復(fù)雜。什么叫忙?是CPU高?還是磁盤I/O高?還是內(nèi)存使用高?還是并發(fā)高?你可能需要全部都要考慮。這些信息要發(fā)送給那個(gè)任務(wù)分配器上,由任務(wù)分配器挑選一臺(tái)負(fù)載最輕的服務(wù)器來處理。
          • 任務(wù)分配服務(wù)器上需要對(duì)任務(wù)隊(duì)列,不能丟任務(wù)啊,所以還需要持久化。并且可以以批量的方式把任務(wù)分配給計(jì)算服務(wù)器。
          • 任務(wù)分配服務(wù)器死了怎么辦?這里需要一些如Live-Standby或是failover等高可用性的技術(shù)。我們還需要注意那些持久化了的任務(wù)的隊(duì)列如果轉(zhuǎn)移到別的服務(wù)器上的問題。
          我看到有很多系統(tǒng)都用靜態(tài)的方式來分配,有的用hash,有的就簡(jiǎn)單地輪流分析。這些都不夠好,一個(gè)是不能完美地負(fù)載均衡,另一個(gè)靜態(tài)的方法的致命缺陷是,如果有一臺(tái)計(jì)算服務(wù)器死機(jī)了,或是我們需要加入新的服務(wù)器,對(duì)于我們的分配器來說,都需要知道。 還有一種方法是使用搶占式的方式進(jìn)行負(fù)載均衡,由下游的計(jì)算服務(wù)器去任務(wù)服務(wù)器上拿任務(wù)。讓這些計(jì)算服務(wù)器自己決定自己是否要任務(wù)。這樣的好處是可 以簡(jiǎn)化系統(tǒng)的復(fù)雜度,而且還可以任意實(shí)時(shí)地減少或增加計(jì)算服務(wù)器。但是唯一不好的就是,如果有一些任務(wù)只能在某種服務(wù)器上處理,這可能會(huì)引入一些復(fù)雜度。 不過總體來說,這種方法可能是比較好的負(fù)載均衡。
          五、異步、 throttle 和 批量處理
          異步、throttle(節(jié)流閥) 和批量處理都需要對(duì)并發(fā)請(qǐng)求數(shù)做隊(duì)列處理的。
          • 異步在業(yè)務(wù)上一般來說就是收集請(qǐng)求,然后延時(shí)處理。在技術(shù)上就是可以把各個(gè)處理程序做成并行的,也就可以水平擴(kuò)展了。但是異步的技術(shù)問題大概有 這 些,a)被調(diào)用方的結(jié)果返回,會(huì)涉及進(jìn)程線程間通信的問題。b)如果程序需要回滾,回滾會(huì)有點(diǎn)復(fù)雜。c)異步通常都會(huì)伴隨多線程多進(jìn)程,并發(fā)的控制也相對(duì) 麻煩一些。d)很多異步系統(tǒng)都用消息機(jī)制,消息的丟失和亂序也會(huì)是比較復(fù)雜的問題。
          • throttle 技術(shù)其實(shí)并不提升性能,這個(gè)技術(shù)主要是防止系統(tǒng)被超過自己不能處理的流量給搞垮了,這其實(shí)是個(gè)保護(hù)機(jī)制。使用throttle技術(shù)一般來說是對(duì)于一些自己無法控制的系統(tǒng),比如,和你網(wǎng)站對(duì)接的銀行系統(tǒng)。
          • 批量處理的技術(shù),是把一堆基本相同的請(qǐng)求批量處理。比如,大家同時(shí)購買同一個(gè)商品,沒有必要你買一個(gè)我就寫一次數(shù)據(jù)庫,完全可以收集到一定數(shù)量 的 請(qǐng)求,一次操作。這個(gè)技術(shù)可以用作很多方面。比如節(jié)省網(wǎng)絡(luò)帶寬,我們都知道網(wǎng)絡(luò)上的MTU(最大傳輸單元),以態(tài)網(wǎng)是1500字節(jié),光纖可以達(dá)到4000 多個(gè)字節(jié),如果你的一個(gè)網(wǎng)絡(luò)包沒有放滿這個(gè)MTU,那就是在浪費(fèi)網(wǎng)絡(luò)帶寬,因?yàn)榫W(wǎng)卡的驅(qū)動(dòng)程序只有一塊一塊地讀效率才會(huì)高。因此,網(wǎng)絡(luò)發(fā)包時(shí),我們需要收 集到足夠多的信息后再做網(wǎng)絡(luò)I/O,這也是一種批量處理的方式。批量處理的敵人是流量低,所以,批量處理的系統(tǒng)一般都會(huì)設(shè)置上兩個(gè)閥值,一個(gè)是作業(yè)量,另 一個(gè)是timeout,只要有一個(gè)條件滿足,就會(huì)開始提交處理。
          所以,只要是異步,一般都會(huì)有throttle機(jī)制,一般都會(huì)有隊(duì)列來排隊(duì),有隊(duì)列,就會(huì)有持久化,而系統(tǒng)一般都會(huì)使用批量的方式來處理云風(fēng)同學(xué)設(shè)計(jì)的“排隊(duì)系統(tǒng)” 就是這個(gè)技術(shù)。這和電子商務(wù)的訂單系統(tǒng)很相似,就是說,我的系統(tǒng)收到了你的購票下單請(qǐng)求,但是我還沒有真正處理,我的系統(tǒng)會(huì)跟據(jù)我自己的處理能力來throttle住這些大量的請(qǐng)求,并一點(diǎn)一點(diǎn)地處理。一旦處理完成,我就可以發(fā)郵件或短信告訴用戶你來可以真正購票了。

          在這里,我想通過業(yè)務(wù)和用戶需求方面討論一下云風(fēng)同學(xué)的這個(gè)排隊(duì)系統(tǒng),因?yàn)槠鋸募夹g(shù)上看似解決了這個(gè)問題,但是從業(yè)務(wù)和用戶需求上來說可能還是有一些值得我們?nèi)ド钊胨伎嫉牡胤剑?

          1)隊(duì)列的DoS攻擊。首先,我們思考一下,這個(gè)隊(duì) 是個(gè)單純地排隊(duì)的嗎?這樣做還不夠好,因?yàn)檫@樣我們不能杜絕黃牛,而且單純的ticket_id很容易發(fā)生DoS攻擊,比如,我發(fā)起N個(gè) ticket_id,進(jìn)入購票流程后,我不買,我就耗你半個(gè)小時(shí),很容易我就可以讓想買票的人幾天都買不到票。有人說,用戶應(yīng)該要用身份證來排隊(duì), 這樣在購買里就必需要用這個(gè)身份證來買,但這也還不能杜絕黃牛排隊(duì)或是號(hào)販子。因?yàn)樗麄兛梢宰?cè)N個(gè)帳號(hào)來排隊(duì),但就是不買。黃牛這些人這個(gè)時(shí)候只需要干 一個(gè)事,把網(wǎng)站搞得正常不能訪問,讓用戶只能通過他們來買。

          2)對(duì)列的一致性?對(duì)這個(gè)隊(duì)列的操作是不是需要鎖?只要有鎖,性能一定上不去。試想,100萬個(gè)人同時(shí)要求你來分配位置號(hào),這個(gè)隊(duì)列將會(huì)成為性能瓶頸。你一定沒有數(shù)據(jù)庫實(shí)現(xiàn)得性能好,所以,可能比現(xiàn)在還差

          3)隊(duì)列的等待時(shí)間。購票時(shí)間半小時(shí)夠不夠?多不 多?要是那時(shí)用戶正好不能上網(wǎng)呢?如果時(shí)間短了,用戶也會(huì)抱怨,如果時(shí)間長(zhǎng)了,后面在排隊(duì)的那些人也會(huì)抱怨。這個(gè)方法可能在實(shí)際操作上會(huì)有很多問題。另 外,半個(gè)小時(shí)太長(zhǎng)了,這完全不現(xiàn)實(shí),我們用15分鐘來舉例:有1千萬用戶,每一個(gè)時(shí)刻只能放進(jìn)去1萬個(gè),這1萬個(gè)用戶需要15分鐘完成所有操作,那么,這 1千萬用戶全部處理完,需要1000*15m = 250小時(shí),10天半,火車早開了。(我并亂說,根據(jù)鐵道部專家的說明:這幾天,平均一天下單100萬,所以,處理1000萬的用戶需要十天。這個(gè)計(jì)算可能有點(diǎn)簡(jiǎn)單了,我只是想說,在這樣低負(fù)載的系統(tǒng)下用排隊(duì)可能都不能解決問題

          4)隊(duì)列的分分式。這個(gè)排隊(duì)系統(tǒng)只有一個(gè)隊(duì)列好嗎? 還不足夠好。因?yàn)椋绻惴胚M(jìn)去的可以購票的人如果在買同一個(gè)車次的同樣的類型的票(比如某動(dòng)車臥鋪),還是等于在搶票,也就是說系統(tǒng)的負(fù)載還是會(huì)有可能 集中到其中某臺(tái)服務(wù)器上。因此,最好的方法是根據(jù)用戶的需求——提供出發(fā)地和目的地,來對(duì)用戶進(jìn)行排隊(duì)。而這樣一來,隊(duì)列也就可以是多個(gè),只要是多個(gè)隊(duì) 列,就可以水平擴(kuò)展了。 我覺得完全可以向網(wǎng)上購物學(xué)習(xí)。在排隊(duì)(下單)的時(shí)候,收集好用戶的信息和想要買的票,并允許用戶設(shè)置購票的優(yōu)先級(jí),比如,A車次臥鋪買 不到就買 B車次的臥鋪,如果還買不到就買硬座等等,然后用戶把所需的錢先充值好,接下來就是系統(tǒng)完全自動(dòng)地異步處理訂單。成功不成功都發(fā)短信或郵件通知用戶。這 樣,系統(tǒng)不僅可以省去那半個(gè)小時(shí)的用戶交互時(shí)間,自動(dòng)化加快處理,還可以合并相同購票請(qǐng)求的人,進(jìn)行批處理(減少數(shù)據(jù)庫的操作次數(shù))。這種方法最妙的事是 可以知道這些排隊(duì)用戶的需求,不但可以優(yōu)化用戶的隊(duì)列,把用戶分布到不同的隊(duì)列,還可以像亞馬遜的心愿單一樣,讓鐵道部做車次統(tǒng)籌安排和調(diào)整(最后,排隊(duì) 系統(tǒng)(下單系統(tǒng))還是要保存在數(shù)據(jù)庫里的或做持久化,不能只放在內(nèi)存中,不然機(jī)器一down,就等著被罵吧)。

          小結(jié)

          寫了那么多,我小結(jié)一下:
          0)無論你怎么設(shè)計(jì),你的系統(tǒng)一定要能容易地水平擴(kuò)展。也就是說,你的整個(gè)數(shù)據(jù)流中,所有的環(huán)節(jié)都要能夠水平擴(kuò)展。這樣,當(dāng)你的系統(tǒng)有性能問題時(shí),“加3倍的服務(wù)器”才不會(huì)被人譏笑。

          1)上述的技術(shù)不是一朝一夕能搞定的,沒有長(zhǎng)期的積累,基本無望。

          2)集中式的賣票很難搞定,使用上述的技術(shù)可以讓訂票系統(tǒng)能有幾佰倍的性能提升。而在各個(gè)省市建分站,分開賣票,是能讓現(xiàn)有系統(tǒng)性能有質(zhì)的提升的最好方法。

          3)春運(yùn)前夕搶票且票量供遠(yuǎn)小于求這種業(yè)務(wù)模式是相當(dāng)變態(tài)的,讓幾千萬甚至上億的人在某個(gè)早晨的8點(diǎn)鐘同時(shí)登錄同時(shí)搶票的這種業(yè)務(wù)模式是變態(tài)中的變態(tài)。業(yè)務(wù)形態(tài)的變態(tài)決定了無論他們?cè)趺崔k干一定會(huì)被罵。

          4)為了那么一兩個(gè)星期而搞那么大的系統(tǒng),而其它時(shí)間都在閑著,也就是鐵路才干得出來這樣的事了。

          posted @ 2012-01-17 15:23 paulwong 閱讀(682) | 評(píng)論 (1)編輯 收藏

          鐵路的售票系統(tǒng)來說明分庫分表對(duì)架構(gòu)的影響

          一、問題:鐵路的售票系統(tǒng)的數(shù)據(jù)量是海量嗎?

          不是。因?yàn)閿?shù)據(jù)量不大,真不大。

          每一個(gè)車次與車次間是獨(dú)立的,每車次不超過2000張票,一天發(fā)車不超過50萬車次;
          以預(yù)售期15天來講,15*0.1億張不超過1.5億筆的熱線數(shù)據(jù),稱不上海量數(shù)據(jù)的。
          再加上可以按線路分庫,更是不到千萬級(jí)的單表容量。已經(jīng)發(fā)車完成的進(jìn)入歸檔分析。
          即數(shù)據(jù)庫按路線使用不同的服務(wù)器,不同的車次放在不同的表中。并發(fā)量鎖真不大。

          當(dāng)然,如果不分庫分表,再加上不歸檔處理,鐵路的售票系統(tǒng)的數(shù)據(jù)量看起來是海量的;
          關(guān)鍵是這海量的數(shù)據(jù)沒有意義。


          二、如何分庫分表?

          2.1 分庫,考慮數(shù)據(jù)間沒有直接關(guān)系和服務(wù)器如何部署

          鐵路的售票系統(tǒng)為例來說,按路線分庫,再按車次分表是合理的。
          設(shè)路線有1萬條,按每1000條需要兩臺(tái)服務(wù)器(一臺(tái)熱機(jī)沉余),不到20臺(tái)服務(wù)器
          如果使用SAN存儲(chǔ),則使用SAN作為存儲(chǔ),本機(jī)作為熱機(jī)沉余,只需要10臺(tái)。
          當(dāng)然使用mySQL這種經(jīng)濟(jì)型數(shù)據(jù)庫,服務(wù)器需要更多來防災(zāi);
          即可以采用雙寫或多寫的方式來保證數(shù)據(jù)的絕對(duì)安全。

          2.2分表,考慮數(shù)據(jù)間不存在重疊,即數(shù)據(jù)滿足二分原則

          鐵路的售票系統(tǒng)的任意兩個(gè)車次是沒有關(guān)系的,所以可以分表。
          電信的某個(gè)用戶的通話和其它用戶的通話記錄,也是沒有關(guān)系,所以可以分表處理
          (實(shí)際上電信的系統(tǒng),分庫分表后也是不大的,難在后臺(tái)的計(jì)費(fèi)、結(jié)算等規(guī)則)



          三、數(shù)據(jù)庫訪問接口



          1. 元數(shù)據(jù):如何識(shí)別到當(dāng)前要處理的數(shù)量在哪張表?

          鐵路的售票系統(tǒng)會(huì)有一個(gè)車次管理系統(tǒng),例2012年2月12日 D3206 車次,
          按預(yù)先設(shè)計(jì)的在哪臺(tái)服務(wù)器的哪個(gè)庫,建哪個(gè)表。

          2.建立元數(shù)據(jù)的規(guī)則:即具體如何分庫分表的規(guī)則

          這個(gè)就是數(shù)據(jù)庫的訪問接口。

          3.數(shù)據(jù)庫訪問接口的透明程度

          即哪個(gè)層知道哪些元數(shù)據(jù)信息。
          例,是否讓窗口售票的客戶端來解析元數(shù)據(jù)的規(guī)則然后緩存,還是通過中間件來解析緩存的

          具體各層使用怎樣透明程度,和業(yè)務(wù)性質(zhì)、節(jié)點(diǎn)和數(shù)據(jù)中心的拓?fù)涞扔嘘P(guān)。



          四、歷史數(shù)據(jù)歸檔與分析

          1.使用分庫分表后,數(shù)據(jù)需要?dú)w檔,分析處理的程序變得復(fù)雜,但使聯(lián)機(jī)交易變得簡(jiǎn)單
          2.分析:要注意是針對(duì)熱線數(shù)據(jù)分析、歸檔數(shù)據(jù)分析、混合分析有關(guān),
          通過分庫分表和歸檔,更方便使用分布式的統(tǒng)計(jì)方案。

          具體可以參考,淘寶的開放平臺(tái)架構(gòu)師寫的文章:

          結(jié)論:分庫分表跟不分庫分表,整個(gè)架構(gòu)是完全不一樣的。

          像鐵票的售票系統(tǒng)、淘寶、電信、銀行等,絕對(duì)要采用分庫分表的數(shù)據(jù)存儲(chǔ)方案,

          來解決數(shù)據(jù)量的增長(zhǎng)而不影響性能的問題。

          像淘寶等互聯(lián)網(wǎng)應(yīng)用還要解決帶寬即CDN問題。

          posted @ 2012-01-17 13:24 paulwong 閱讀(626) | 評(píng)論 (0)編輯 收藏

          JBoss下DataSource加密(下)

          數(shù)據(jù)源文件:my-oracle-ds.xml

          <datasources>
              
          <local-tx-datasource>
                  
          <jndi-name>jdbc/my-local</jndi-name>
                  <connection-url>
                      jdbc:oracle:thin:@10.5.7.30:1521:orcl
                  
          </connection-url>
                  
          <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
                  <security-domain>EncryptedOracleDbRealm</security-domain>
                  
          <exception-sorter-class-name>
                      org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
                  
          </exception-sorter-class-name>
                  
          <metadata>
                      
          <type-mapping>Oracle10g</type-mapping>
                  
          </metadata>
                  
          <depends>
                      jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword
                  
          </depends>
              
          </local-tx-datasource>



              
          <mbean code="org.jboss.security.plugins.JaasSecurityDomain"
                  name
          ="jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword">
                  
          <constructor>
                      
          <arg type="java.lang.String" value="ServerMasterPassword"></arg>
                  
          </constructor>
                  
          <!-- The opaque master password file used to decrypt the encrypted
                      database password key 
          -->
                  
          <attribute name="KeyStorePass">
                      {CLASS}org.jboss.security.plugins.FilePassword:${jboss.server.home.dir}/conf/server.password
                  
          </attribute>
                  
          <attribute name="Salt">abcdefgh</attribute>
                  
          <attribute name="IterationCount">13</attribute>
              
          </mbean>

          </datasources>

          在jboss4.3/jboss-as/server/default/conf/login-config.xml中增加節(jié)點(diǎn):

          <application-policy name="EncryptedOracleDbRealm">
              
          <authentication>
                  
          <login-module
                      
          code="org.jboss.resource.security.JaasSecurityDomainIdentityLoginModule"
                      flag
          ="required">
                      
          <module-option name="username">username</module-option>
                      
          <module-option name="password">
                          3wW33nIpavHK4pd3qoNTbA
                      
          </module-option>
                      
          <module-option name="managedConnectionFactoryName">
                          jboss.jca:service=LocalTxCM,name=jdbc/my-local
                      
          </module-option>
                      
          <module-option name="jaasSecurityDomain">
                          jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword
                      
          </module-option>
                  
          </login-module>
              
          </authentication>
          </application-policy>

          以上的password由下面命令得出:

          E:\JBOSS\jboss4.3\jboss-as\server\default\lib>java -cp jbosssx.jar
          org.jboss.security.plugins.PBEUtils abcdefgh 
          13 master mypassowrd
          Encoded password:  2mqrIBSpp8JVWFAqCBklhf

          生成server.password文件:

          E:\JBOSS\jboss4.3\jboss-as\server\default\lib>java -cp jbosssx.jar
          org.jboss.security.plugins.FilePassword abcdefgh 
          13 master server.password

          產(chǎn)生后拷貝到:${jboss.server.home.dir}/conf中。

          posted @ 2012-01-16 18:58 paulwong 閱讀(947) | 評(píng)論 (0)編輯 收藏

          Java生成RSA非對(duì)稱型加密的公鑰和私鑰(利用java API)

          非對(duì)稱型加密非常適合多個(gè)客戶端和服務(wù)器之間的秘密通訊,客戶端使用同一個(gè)公鑰將明文加密,而這個(gè)公鑰不能逆向的解密,密文發(fā)送到服務(wù)器后有服務(wù)器端用私鑰解密,這樣就做到了明文的加密傳送。

          非對(duì)稱型加密也有它先天的缺點(diǎn),加密、解密速度慢制約了它的發(fā)揮,如果你有大量的文字需要加密傳送,建議你通過非對(duì)稱型加密來把對(duì)稱型‘密鑰’分發(fā)到客戶端,及時(shí)更新對(duì)稱型‘密鑰’。

          package com.paul.module.common.util;

          import sun.misc.BASE64Decoder;
          import sun.misc.BASE64Encoder;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.io.ObjectInputStream;
          import java.io.ObjectOutputStream;
          import java.security.Key;
          import java.security.KeyPair;
          import java.security.KeyPairGenerator;

          import javax.crypto.Cipher;

          public class RSASecurityUtil2 {
              
          /** 指定加密算法為RSA */
              
          private static final String ALGORITHM = "RSA";
              
          /** 密鑰長(zhǎng)度,用來初始化 */
              
          private static final int KEYSIZE = 1024;
              
          /** 指定公鑰存放文件 */
              
          private static String PUBLIC_KEY_FILE = "PublicKey";
              
          /** 指定私鑰存放文件 */
              
          private static String PRIVATE_KEY_FILE = "PrivateKey";

              
          /**
               * 生成密鑰對(duì)
               * 
          @throws Exception
               
          */
              
          private static void generateKeyPair() throws Exception {
                  
          //        /** RSA算法要求有一個(gè)可信任的隨機(jī)數(shù)源 */
          //        SecureRandom secureRandom = new SecureRandom();
                  
                  
          /** 為RSA算法創(chuàng)建一個(gè)KeyPairGenerator對(duì)象 */
                  KeyPairGenerator keyPairGenerator 
          = KeyPairGenerator.getInstance(ALGORITHM);
                  
                  
          /** 利用上面的隨機(jī)數(shù)據(jù)源初始化這個(gè)KeyPairGenerator對(duì)象 */
          //        keyPairGenerator.initialize(KEYSIZE, secureRandom);
                  keyPairGenerator.initialize(KEYSIZE);
                  
                  
          /** 生成密匙對(duì) */
                  KeyPair keyPair 
          = keyPairGenerator.generateKeyPair();
                  
                  
          /** 得到公鑰 */
                  Key publicKey 
          = keyPair.getPublic();
                  
                  
          /** 得到私鑰 */
                  Key privateKey 
          = keyPair.getPrivate();
                  
                  ObjectOutputStream oos1 
          = null;
                  ObjectOutputStream oos2 
          = null;
                  
          try {
                      
          /** 用對(duì)象流將生成的密鑰寫入文件 */
                      oos1 
          = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
                      oos2 
          = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
                      oos1.writeObject(publicKey);
                      oos2.writeObject(privateKey);
                  } 
          catch (Exception e) {
                      
          throw e;
                  }
                  
          finally{
                      
          /** 清空緩存,關(guān)閉文件輸出流 */
                      oos1.close();
                      oos2.close();
                  }
              }

              
          /**
               * 加密方法
               * 
          @param source 源數(shù)據(jù)
               * 
          @return
               * 
          @throws Exception
               
          */
              
          public static String encrypt(String source) throws Exception {
                  generateKeyPair();
                  Key publicKey;
                  ObjectInputStream ois 
          = null;
                  
          try {
                      
          /** 將文件中的公鑰對(duì)象讀出 */
                      ois 
          = new ObjectInputStream(new FileInputStream(
                              PUBLIC_KEY_FILE));
                      publicKey 
          = (Key) ois.readObject();
                  } 
          catch (Exception e) {
                      
          throw e;
                  }
                  
          finally{
                      ois.close();
                  }
                  
                  
          /** 得到Cipher對(duì)象來實(shí)現(xiàn)對(duì)源數(shù)據(jù)的RSA加密 */
                  Cipher cipher 
          = Cipher.getInstance(ALGORITHM);
                  cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                  
          byte[] b = source.getBytes();
                  
          /** 執(zhí)行加密操作 */
                  
          byte[] b1 = cipher.doFinal(b);
                  BASE64Encoder encoder 
          = new BASE64Encoder();
                  
          return encoder.encode(b1);
              }

              
          /**
               * 解密算法
               * 
          @param cryptograph    密文
               * 
          @return
               * 
          @throws Exception
               
          */
              
          public static String decrypt(String cryptograph) throws Exception {
                  Key privateKey;
                  ObjectInputStream ois 
          = null;
                  
          try {
                      
          /** 將文件中的私鑰對(duì)象讀出 */
                      ois 
          = new ObjectInputStream(new FileInputStream(
                              PRIVATE_KEY_FILE));
                      privateKey 
          = (Key) ois.readObject();
                  } 
          catch (Exception e) {
                      
          throw e;
                  }
                  
          finally{
                      ois.close();
                  }
                  
                  
          /** 得到Cipher對(duì)象對(duì)已用公鑰加密的數(shù)據(jù)進(jìn)行RSA解密 */
                  Cipher cipher 
          = Cipher.getInstance(ALGORITHM);
                  cipher.init(Cipher.DECRYPT_MODE, privateKey);
                  BASE64Decoder decoder 
          = new BASE64Decoder();
                  
          byte[] b1 = decoder.decodeBuffer(cryptograph);
                  
                  
          /** 執(zhí)行解密操作 */
                  
          byte[] b = cipher.doFinal(b1);
                  
          return new String(b);
              }

              
          public static void main(String[] args) throws Exception {
                  String source 
          = "恭喜發(fā)財(cái)!";// 要加密的字符串
                  System.out.println("準(zhǔn)備用公鑰加密的字符串為:" + source);
                  
                  String cryptograph 
          = encrypt(source);// 生成的密文
                  System.out.print("用公鑰加密后的結(jié)果為:" + cryptograph);
                  System.out.println();

                  String target 
          = decrypt(cryptograph);// 解密密文
                  System.out.println("用私鑰解密后的字符串為:" + target);
                  System.out.println();
              }
          }


          http://blog.sina.com.cn/s/blog_43b03c72010080t2.html
          http://topic.csdn.net/t/20040510/14/3049788.html
          http://yuanliyin.iteye.com/blog/853334

          posted @ 2012-01-16 00:37 paulwong 閱讀(15004) | 評(píng)論 (1)編輯 收藏

          《1億在線背后的技術(shù)挑戰(zhàn)》視頻放出

          2011年10月31日,騰訊即通平臺(tái)部高級(jí)總監(jiān)莊泗華在北京航空航天大學(xué)的演講《1億在線背后的技術(shù)挑戰(zhàn)》讓許多聽眾變成了莊老師的粉絲。

          騰訊大講堂放出莊泗華的演講視頻,轉(zhuǎn)載請(qǐng)注明來自騰訊大講堂

          演講PPT下載:http://djt.open.qq.com/portal.php?mod=view&aid=19

          視頻:1.4億在線背后的故事

          第1部分:從十萬級(jí)到百萬級(jí)在線


          第2部分:千萬級(jí)在線


          第3部分:億級(jí)在線


          第4部分:總結(jié)


          posted @ 2012-01-15 21:40 paulwong 閱讀(390) | 評(píng)論 (0)編輯 收藏

          我們應(yīng)當(dāng)怎樣做需求分析(轉(zhuǎn))

          又到新年了,日歷又要從2011年翻到2012年了,這使我有太多的感慨,進(jìn)而勾起了對(duì)太大往事的回憶。過去的10年,毫無疑問是中國軟件業(yè)發(fā)展最快的10年。當(dāng)我們剛剛畢業(yè)的時(shí)候,還在使用VB、PB開發(fā)一些簡(jiǎn)單的數(shù)據(jù)庫應(yīng)用,而現(xiàn)在卻幾乎看不到它們的蹤影,換來的是諸如J2EE和.NET這樣的大型web應(yīng)用。而這期間,RUP、XP、敏捷開發(fā)、持續(xù)集成••••••一個(gè)接一個(gè)的新概念層出不窮,令人眼花繚亂。現(xiàn)在想來,恍如隔世。

          但更令我印象深刻而難以忘懷的,是我親自經(jīng)歷的、親眼目睹的、道聽途說的一個(gè)又一個(gè)的軟件項(xiàng)目,它們有的獲得了成功,但更多的是令人沮喪的失敗。套用一下大文豪托爾斯泰體:幸福的家庭都是一樣的,不幸的家庭卻各有各的不幸;幸福的軟件項(xiàng)目都是一樣的,不幸的軟件項(xiàng)目卻各有各的不幸;或者說,成功的軟件項(xiàng)目都是一樣的,失敗的項(xiàng)目卻各有各的問題。我常常在想,我們的項(xiàng)目開發(fā)到底怎么了,進(jìn)而把它們一個(gè)一個(gè)的剝開來深入分析,竟然觸目驚心。它們有的是需求的問題,有的是客戶關(guān)系的問題,還有設(shè)計(jì)的問題、技術(shù)的問題、時(shí)間管理的問題、人員培養(yǎng)的問題••••••但歸根到底更多的還是需求的問題。需求分析既是一份體力活兒,更是一份技術(shù)活兒,它既是人際交往的藝術(shù),又是邏輯分析與嚴(yán)密思考的產(chǎn)物。正是我們?cè)谛枨蠓治鲞^程存在的巨大隱患,最終導(dǎo)致了那么多項(xiàng)目的失敗。也許你認(rèn)為我在危言聳聽,好吧,我來舉幾個(gè)典型事例分析分析吧。

          我的第一個(gè)故事來自大名鼎鼎的東軟。我在2005年接一個(gè)項(xiàng)目的時(shí)候,聽說這個(gè)項(xiàng)目之前是東軟做的。當(dāng)時(shí)東軟在做這個(gè)項(xiàng)目的時(shí)候,整個(gè)過程經(jīng)歷了10多次結(jié)構(gòu)性的大變更,局部性的調(diào)整更是不計(jì)其數(shù)。據(jù)說某天早上,客戶對(duì)某個(gè)功能不滿意,他們不得不對(duì)幾百處程序進(jìn)行修改。之后客戶對(duì)修改的內(nèi)容還是不滿意,又不得不將幾百處修改重新改回來。最后這個(gè)項(xiàng)目導(dǎo)致的結(jié)果是,整個(gè)這個(gè)項(xiàng)目組的所有成員都離開了東軟,并似乎從此不愿涉足軟件開發(fā)領(lǐng)域。多么慘痛的教訓(xùn)啊!我常常聽到網(wǎng)友抱怨客戶總是對(duì)需求改來改去,但客戶對(duì)需求改來改去的真正原因是什么呢?當(dāng)我們對(duì)客戶的需求沒有真正理解清楚時(shí),我們做出來的東西客戶必然不滿意。客戶只知道他不滿意,但怎樣才能使他滿意呢?他不知道,于是就在一點(diǎn)兒一點(diǎn)兒試,于是這種反復(fù)變更就這樣發(fā)生了。如果我們明白了這一點(diǎn),深入地去理解客戶的業(yè)務(wù),進(jìn)而想到客戶的心坎兒上去,最后做出來的東西必然是客戶滿意的。記住,當(dāng)客戶提出業(yè)務(wù)變更的時(shí)候,我們一定不能被客戶牽著走,客戶說啥就是啥。我們要從業(yè)務(wù)角度深入的去分析,他為什么提出變更,提得合不合理,我有沒有更合理的方案滿足這個(gè)需求。當(dāng)我們提出更加合理的方案時(shí),客戶是樂于接受的,變更也變得可控了。

          第二個(gè)故事來自我自己的項(xiàng)目,一個(gè)早期的項(xiàng)目。在這個(gè)項(xiàng)目中,客戶扔給了我們很多他們目前正在使用的統(tǒng)計(jì)報(bào)表,要我們按照?qǐng)?bào)表的格式做出來。這些報(bào)表都是手工報(bào)表,許多格式既不規(guī)范,又很難于被計(jì)算機(jī)實(shí)現(xiàn)。這些報(bào)表令我耗費(fèi)了不少鬧細(xì)胞,直到最終項(xiàng)目失敗都沒法完成。這件事留給我的深刻教訓(xùn)是,不能客戶怎么說軟件就怎么做。客戶提出的原始需求往往是不考慮技術(shù)實(shí)現(xiàn),基于非計(jì)算機(jī)管理的操作模式提出來的。他們提出的很多需求常常比較理想而不切實(shí)際,畢竟人家是非技術(shù)的。但我們作為技術(shù)人員,需求分析必須實(shí)事求是地、基于技術(shù)可以實(shí)現(xiàn)的角度去考慮。那種“有條件要上,沒有條件創(chuàng)造條件”的魯莽行事,結(jié)果必然是悲慘的。所以我們必須要基于技術(shù)實(shí)現(xiàn)去引導(dǎo)客戶的需求。同時(shí),計(jì)算機(jī)信息化管理就是一次改革,對(duì)以往手工管理模式的改革。如果我們上了信息化管理系統(tǒng),采用的管理模式卻依然是過去的手工模式,新系統(tǒng)的優(yōu)勢(shì)從何而來呢?因此,我們做需求就應(yīng)當(dāng)首先理解現(xiàn)有的管理模式,然后站在信息化管理的角度去審視他們的管理模式是否合理,最后一步一步地去引導(dǎo)他們按照更加合理的方式去操作與管理。

          2007年,我參與了一個(gè)集團(tuán)信息化建設(shè)的項(xiàng)目。這個(gè)項(xiàng)目中的客戶是一個(gè)龐大的群體,他們分別扮演著各種角色。從機(jī)構(gòu)層次劃分,有集團(tuán)領(lǐng)導(dǎo)、二級(jí)機(jī)構(gòu)人員、三級(jí)機(jī)構(gòu)人員;從職能角色劃分,有高層領(lǐng)導(dǎo)、財(cái)務(wù)人員、生產(chǎn)管理員、采購人員、銷售人員,等等。在這樣一個(gè)復(fù)雜場(chǎng)景中,不同人員對(duì)這個(gè)項(xiàng)目的需求是各自不同的。非常遺憾的是,我們?cè)谶M(jìn)行需求分析的時(shí)候沒有認(rèn)真分析清楚所有類型人員的需求。在進(jìn)行需求調(diào)研的時(shí)候,總是集團(tuán)領(lǐng)導(dǎo)帶領(lǐng)我們到基層單位,然后基層單位將各方面的人員叫來開大會(huì)。這樣的大會(huì),各類型的人員七嘴八舌各說各自的需求,還有很多基層人員在大會(huì)上因?yàn)樾邼揪蜎]有提出自己的需求。這樣經(jīng)過數(shù)次開會(huì),需求調(diào)研就草草收?qǐng)觥N覀兡弥粋€(gè)不充分的需求分析結(jié)果就開始項(xiàng)目開發(fā),最終的結(jié)果可想而知。直到項(xiàng)目上線以后,我們才發(fā)現(xiàn)許多更加細(xì)節(jié)的業(yè)務(wù)需求都沒能分析到,系統(tǒng)根本沒法運(yùn)行,不得不宣告失敗。一個(gè)軟件項(xiàng)目的需求調(diào)研首先必須要進(jìn)行角色分析,然后對(duì)不同的角色分別進(jìn)行調(diào)研。需求調(diào)研的最初需要召開項(xiàng)目動(dòng)員大會(huì),這是十分必要的。但真正要完成需求分析,應(yīng)該是一個(gè)一個(gè)的小會(huì),1~3個(gè)業(yè)務(wù)專家,只討論某個(gè)領(lǐng)域的業(yè)務(wù)需求,并且很多問題都不是能一蹴而就完成的,我們必須與專家建立聯(lián)系,反復(fù)溝通后完成。需求分析必須遵從的是一定的科學(xué)方法,而不是盲目的大上快上。

          我的最后一個(gè)故事可能典型到幾乎每個(gè)人都曾經(jīng)遇到過。我們的項(xiàng)目從需求分析到設(shè)計(jì)、開發(fā)、測(cè)試都十分順利。但到了項(xiàng)目進(jìn)行的后期,快到達(dá)最后期限時(shí),我們將我們的開發(fā)成果提交給客戶看,客戶卻對(duì)開發(fā)不滿意,提出了一大堆修改,而且這些修改工作量還不小。怎么辦呢?加班、趕工,測(cè)試時(shí)間被最大限度壓縮。最后項(xiàng)目倒是如期上線了,但大家疲憊不堪,并且上線以后才發(fā)現(xiàn)許多的BUG。需求分析不是一蹴而就的,它應(yīng)當(dāng)貫穿整個(gè)開發(fā)周期,不斷的分析確認(rèn)的過程。以上這個(gè)事例,如果我們提早將開發(fā)成果給客戶看,提早解決問題,后面的情況就將不再發(fā)生。這就是敏捷開發(fā)倡導(dǎo)的需求反饋。敏捷開發(fā)認(rèn)為,需求分析階段不可能解決所有的需求問題,因此在設(shè)計(jì)、開發(fā)、測(cè)試,直到最終交付客戶,這整個(gè)過程都應(yīng)當(dāng)不停地用開發(fā)的成果與客戶交流,及時(shí)獲得反饋。只有這樣才能及時(shí)糾正需求理解的偏差,保證項(xiàng)目的成功。

          以上的故事各有各自的不幸,各自都在不同的開發(fā)環(huán)節(jié)出現(xiàn)了問題。但經(jīng)過深入的分析,各自的問題最終都?xì)w結(jié)為需求分析出現(xiàn)了問題。為了使我們今后的軟件項(xiàng)目不會(huì)重蹈覆轍,似乎真的有必要討論一下我們應(yīng)該怎樣做需求分析。

          posted @ 2012-01-15 20:24 paulwong 閱讀(339) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題
          共115頁: First 上一頁 90 91 92 93 94 95 96 97 98 下一頁 Last 
          主站蜘蛛池模板: 莱州市| 日喀则市| 政和县| 曲阳县| 嵊州市| 阳高县| 清远市| 宁波市| 从化市| 织金县| 武定县| 恩平市| 双桥区| 太白县| 新源县| 介休市| 皮山县| 保山市| 金堂县| 武城县| 太仆寺旗| 南京市| 昂仁县| 左贡县| 通许县| 永吉县| 永善县| 安平县| 安宁市| 时尚| 越西县| 连山| 望奎县| 志丹县| 岳普湖县| 普陀区| 邳州市| 绍兴市| 惠州市| 江北区| 拉萨市|