天天看點

Java Web技術架構方案概述

大型網站系統架構的演進都是随着業務增長不斷演進,所有的出發點都是為了滿足業務需求。最初通路量下,功能簡單時,單體軟體可以解決所有問題;後來通路量逐漸增大,功能愈加豐富,此時單體軟體的架構逐漸成為開發和運維的瓶頸。是以微服務拆分,叢集化部署,消息中間件,記憶體資料庫,資料庫中間件等解決方案逐漸走進視野。

下圖為簡略版的Web系統架構,本文圍繞此圖展開,簡要介紹其中涉及元件的功能和應用場景。

回到最初,Web項目的源頭幾乎全來源于使用者的請求(此處忽略運維相關的定時監控等任務),當海量的請求并發量超過Tomcat伺服器的峰值時,Tomcat的叢集化應運而生,與之同時反向代理元件Ngnix走進視野。Ngnix本身作為入口,其穩定性是關鍵因素,是以利用keepalived實作高可用是正常思維。

綜上,可以看到叢集化的目的在于解決單服務能力不足的問題,高可用的機器備份方案是為了實作系統的穩定運作。但是,在叢集化時又引入了負載均衡,高可用時怎樣實作異常故障自動切換等技術問題,這裡均不深入讨論,僅引入一個概念基礎。另,每一種元件有很多相關的産品,這裡僅針對圖中列出的元件進行介紹。

拆分後的微服務部署在不同的機器上,服務間如何通信實作業務調用?先解釋一個概念,調用有同步和異步兩種,同步是在調用時發起方會阻塞線程等待調用結果傳回後再往下執行,異步調用是調用方按約定将消息發送出去,不關注調用的執行結果,兩者适用的場景不同。對應到上圖中同步調用的方案為Dubbox,消息中間件ActiveMQ為異步調用。

  • Dubbox

Dubbox 是一個分布式服務架構,緻力于提供高性能和透明化的RPC遠端服務調用方案,以及SOA服務治理方案。簡單的說,Dubbox 就是個服務架構,隻有在分布式的時候,才有Dubbox 這樣的分布式服務架構的需求,起本質上是個遠端服務調用的分布式架構。

節點角色說明:

· Provider: 暴露服務的服務提供方。

· Consumer: 調用遠端服務的服務消費方。

· Registry: 服務注冊與發現的注冊中心。

· Monitor: 統計服務的調用次調和調用時間的監控中心。

· Container: 服務運作容器。

調用關系說明:

  1. 服務容器負責啟動,加載,運作服務提供者。
  2. 服務提供者在啟動時,向注冊中心注冊自己提供的服務。
  3. 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
  4. 注冊中心傳回服務提供者位址清單給消費者,如果有變更,注冊中心将基于長連接配接推送變更資料給消費者。
  5. 服務消費者,從提供者位址清單中,基于軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
  6. 服務消費者和提供者,在記憶體中累計調用次數和調用時間,定時每分鐘發送一次統計資料到監控中心。

Dubbox推薦使用 zookeeper 注冊中心。注冊中心負責服務位址的注冊與查找,相當于目錄服務,服務提供者和消費者隻在啟動時與注冊中心互動,注冊中心不轉發請求,壓力較小。是以在服務內建時需要同步部署Zookeeper。

  • ActiveMQ

消息中間件利用高效可靠的消息傳遞機制進行平台無關的資料交流,并基于資料通信來進行分布式系統的內建。通過提供消息傳遞和消息排隊模型,它可以在分布式環境下擴充程序間的通信。對于消息中間件,常見的角色為Producer(生産者)、Consumer(消費者)。

ActiveMQ 是Apache的開源項目,是能力強勁的消息總線。ActiveMQ 是一個完全支援JMS1.1和J2EE 1.4規範的JMS Provider實作。

    什麼是JMS?

JMS(Java Messaging Service)是Java平台上有關面向消息中間件的技術規範,它便于消息系統中的Java應用程式進行消息交換,并且通過提供标準的産生、發送、接收消息的接口簡化企業應用的開發。

JMS本身隻定義了一系列的接口規範,是一種與廠商無關的 API,用來通路消息收發系統。它類似于 JDBC(java Database Connectivity):這裡,JDBC 是可以用來通路許多不同關系資料庫的 API,而 JMS 則提供同樣與廠商無關的通路方法,以通路消息收發服務。許多廠商目前都支援 JMS,包括 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ,這隻是幾個例子。 JMS 使您能夠通過消息收發服務(有時稱為消息中介程式或路由器)從一個 JMS 客戶機向另一個 JML 客戶機發送消息。消息是 JMS 中的一種類型對象,由兩部分組成:報頭和消息主體。報頭由路由資訊以及有關該消息的中繼資料組成。消息主體則攜帶着應用程式的資料或有效負載。

JMS規定的消息類型有兩種:點對點(一對一),釋出/訂閱模式(一對多),我們在使用消息中間件時隻需遵從JMS提供的操作接口進行開發。

ActiveMQ叢集化有兩種方式Master/Slave(ActiveMQ5.10開始支援使用Zookeeper搭建叢集),Broker Cluster。

  • Master/Slave實作了主從複制,實作高可用;
  • Broker Cluster實作了負載均衡。

可以将兩種方式結合起來同時實作負載均衡和高可用。

為了進一步緩解服務叢集的壓力,可以将高頻通路量大或者資源消耗嚴重的服務單獨拆分出來,如圖中的搜尋和檔案服務。

  • SolrCloud

SolrCloud是Solr提供的分布式搜尋方案,當你需要大規模,容錯,分布式索引和檢索能力時使用SolrCloud。當一個系統的索引資料量少的時候是不需要使用SolrCloud的,當索引量很大,搜尋請求并發很高,這時需要使用SolrCloud 來滿足這些需求。

SolrCloud 是基于Solr和Zookeeper的分布式搜尋方案,它的主要思想是使用 Zookeeper作為叢集的配置資訊中心。

它有幾個特色功能:

1)集中式的配置資訊

2)自動容錯

3)近實時搜尋

4)查詢時自動負載均衡

問題來了,何為Solr?

Apache Solr是一個流行的開源搜尋伺服器,它通過使用類似REST的HTTP API,建構搜尋應用程式。它建立在Lucene(全文搜尋引擎)之上。 Solr是企業級的,快速的和高度可擴充的。 使用Solr建構的應用程式非常複雜,可提供高性能。

Solr可以和Hadoop一起使用。由于Hadoop處理大量資料,Solr幫助我們從大的源中找到所需的資訊。不僅限于搜尋,Solr也可以用于存儲目的。像其他NoSQL資料庫一樣,它是一種非關系資料存儲和處理技術。

使用Solr時需要整合中文分析器,例如IK Analyzer。

IK Analyzer 是一個開源的,基亍 java 語言開發的輕量級的中文分詞工具包。IK已發展為面向 Java 的公用分詞元件,獨立亍 Lucene 項目,同時提供了對 Lucene 的預設優化實作。在2012版本中,IK 實作了簡單的分詞歧義排除算法,标志着 IK 分詞器從單純的詞典分詞向模拟語義分詞衍化。

Solr如何使用?

我們可以利用Spring将Solr服務內建到項目中。Spring Data Sol就是為了友善Solr的開發所研制的一個架構,其底層是對SolrJ(官方API)的封裝。搜尋服務的功能開發參考Spring Data Solr相關接口。

  • FastDFS

FastDFS 是用 c 語言編寫的一款開源的分布式檔案系統。FastDFS 為網際網路量身定制,充分考慮了備援備份、負載均衡、線性擴容等機制,并注重高可用、高性能等名額,使用 FastDFS很容易搭建一套高性能的檔案伺服器叢集提供檔案上傳、下載下傳等服務。

FastDFS 架構包括 Tracker server 和 Storage server。用戶端請求 Tracker server 進行檔案上傳、下載下傳,通過 Tracker server 排程最終由 Storage server 完成檔案上傳和下載下傳。

Tracker server 作用是負載均衡和排程,通過 Tracker server 在檔案上傳時可以根據一些政策找到 Storage server 提供檔案上傳服務。可以将 tracker 稱為追蹤伺服器或排程伺服器。

Storage server 作用是檔案存儲,用戶端上傳的檔案最終存儲在 Storage 伺服器上,Storage server 沒有實作自己的檔案系統而是利用作業系統 的檔案系統來管理檔案。可以将Storage稱為存儲伺服器。

服務端兩個角色:

Tracker:管理叢集,tracker 也可以實作叢集。每個 tracker 節點地位平等。收集 Storage 叢集的狀态。

Storage:實際儲存檔案   Storage 分為多個組,每個組之間儲存的檔案是不同的。每個組内部可以有多個成員,組成員内部儲存的内容是一樣的,組成員的地位是一緻的,沒有主從的概念。

由上圖可知,FastDFS叢集搭建完成後,我們需要開發client端向伺服器發起請求實作檔案上傳下載下傳功能,相關開發接口在client的jar包中提供如:fastdfs_client_v1.20.jar。

最後,說說資料庫在大型軟體系統中的改變。

  • Redis Cluster

為何要搭建Redis叢集。Redis是在記憶體中以Key-Value格式儲存資料的,而電腦記憶體一般都不大,這也就意味着Redis不适合存儲大資料,Redis更适合處理高并發。為了擴充裝置的存儲能力,搭建服務叢集是正常思路。

Redis 3.0之後版本支援Redis-Cluster叢集,它是Redis官方提出的解決方案,Redis-Cluster采用無中心結構,每個節點儲存資料和整個叢集狀态,每個節點都和其他所有節點連接配接。其架構圖如下:

用戶端與 Redis 節點直連,不需要中間代理層。用戶端不需要連接配接叢集所有節點連接配接叢集中任何一個可用節點即可。所有的 Redis 節點彼此互聯(PING-PONG 機制),内部使用二進制協定優化傳輸速度和帶寬。

Redis-Cluster分布存儲機制-槽

(1)Redis-Cluster 把所有的實體節點映射到[0-16383] slot上,cluster 負責維護node<->slot<->value。

(2)Redis-Cluster中内置了 16384 個哈希槽,當需要在 Redis 叢集中放置一個 key-value 時,Redis 先對 key 使用 crc16 算法算出一個結果,然後把結果對 16384 求餘數,這樣每個key 都會對應一個編号在 0-16383 之間的哈希槽,Redis 會根據節點數量大緻均等的将哈希槽映射到不同的節點。

Redis-Cluster容錯機制-投票

(1)選舉過程是叢集中所有master參與,如果半數以上master節點與故障節點通信超過(cluster-node-timeout),認為該節點故障,自動觸發故障轉移操作。故障節點對應的從節點自動更新為主節點。

(2)什麼時候整個叢集不可用(cluster_state:fail)?

如果叢集任意master挂掉,且目前master沒有slave。叢集進入fail狀态,也可以了解成叢集的slot映射[0-16383]不完成時進入fail狀态.。

為何要使用Redis?

高頻高并發的通路資料庫會給資料庫造成很大的通路壓力,甚至是癱瘓。為了解決此問題,我們可以使用Redis将常用資料進行緩存,分流通路流量。

如何使用Redis?

類似Solr,Spring提供了Spring Data Redis架構,在Srping應用中通過簡單的配置通路Redis服務。Spring Data Redis對Reids底層開發包(Jedis,  JRedis, and RJC)進行了高度封裝,RedisTemplate提供了Redis各種操作、異常處理及序列化,支援釋出訂閱,并對Spring 3.1 cache進行了實作。

Spring Data Redis針對JRedis提供了如下功能:

1.連接配接池自動管理,提供了一個高度封裝的“RedisTemplate”類。

2.針對jedis用戶端中大量api進行了歸類封裝,将同一類型操作封裝為operation接口。

ValueOperations:簡單K-V操作

SetOperations:set類型資料操作

ZSetOperations:zset類型資料操作

HashOperations:針對map類型的資料操作

ListOperations:針對list類型的資料操作

  • MyCat

MyCat是基于cobar(阿裡開源産品)演變而來,對 cobar 的代碼進行了徹底的重構,使用 NIO 重構了網絡子產品,并且優化了 Buffer 核心,增強了聚合,Join 等基本特性,同時相容絕大多數資料庫成為通用的資料庫中間件。

簡單的說,MyCat就是:一個新穎的資料庫中間件産品支援MySQL叢集,或者mariadb cluster,提供高可用性資料分片叢集。你可以像使用MySQL一樣使用MyCat。對于開發人員來說根本感覺不到MyCat的存在。

MyCat分片

分片是指通過某種特定的條件,将我們存放在同一個資料庫中的資料分散存放到多個資料庫(主機)上面,以達到分散單台裝置負載的效果。

資料的切分(Sharding)根據其切分規則的類型,可以分為兩種切分模式。

   (1)一種是按照不同的表(或者Schema)來切分到不同的資料庫(主機)之上,這種切分可以稱之為資料的垂直(縱向)切分。

(2)另外一種則是根據表中的資料的邏輯關系,将同一個表中的資料按照某種條件拆分到多台資料庫(主機)上面,這種切分稱之為資料的水準(橫向)切分。

MyCat分片政策:

資料庫的讀寫分離:

資料庫讀寫分離對于大型系統或者通路量很高的網際網路應用來說,是必不可少的一個重要功能。對于MySQL來說,标準的讀寫分離是主從模式,一個寫節點Master後面跟着多個讀節點,讀節點的數量取決于系統的壓力,通常是1-3個讀節點的配置。

MyCat讀寫分離和自動切換機制,需要MySQL的主從複制機制配合。