項目相關

------------分佈式、集羣------------

1.什麼是分佈式架構?什麼是集羣?

  • 分佈式 一個業務分拆爲多個子業務,分別佈署到不一樣服務器上,須要各子業務之間配合才能完成整個業務邏輯。好比一個網站,會員系統放在A服務器,消息系統放在B服務器,支付系統放在C服務器等等,那麼這個網站也算是一個分佈式網站。
  • 集羣 同一個業務被佈署到不一樣的服務器以下降單臺服務器的壓力,多臺服務器一塊兒實現同一個業務

相同點:分佈式和集羣都是須要有不少節點服務器經過網絡協同工做完成總體的任務目標。html

區別:java

  1. 分佈式是指將不一樣的業務分給不一樣的服務器,每個服務器都完成不一樣的業務,每一個服務器缺一不可;而集羣指的是將幾臺服務器集中在一塊兒,實現同一業務。每臺服務器並非缺一不可的。
  2. 分佈式是以縮短單個任務的執行時間來提高效率的,而集羣則是經過提升單位時間內執行的任務數來提高效率的。

【注】分佈式中的每個節點,均可以作集羣。 而集羣並不必定就是分佈式的。linux

舉個例子說明: 
  一個小飯店裏,原來只有一個廚師,買菜洗菜切菜炒菜全都是這廚師一人幹,這叫 單機結構 。後來飯店客人多了,一個廚師確實忙活不過來,因而飯店又請來了個廚師,如今飯店有了兩個廚師,這兩個廚師都能從頭至尾作同樣的菜,這兩個廚師就是 集羣 。這樣兩個廚師集羣確實能作更多的活,客人點10個菜能夠分配每一個人抄5個,單個廚師壓力減小了。可是這樣還不行,爲了讓廚師專心作菜,把菜作得更好,因而飯店又請來了採購和配菜師,採購負責買菜,配菜師負責把菜挑揀洗好切好給廚師作好準備,那麼採購、配菜師、廚師之間就行程了 分佈式系統 。後來一個採購和一個配菜師也忙不過來了,因而又再請多了個採購和配菜師,那麼兩個採購又造成了集羣,兩個配菜師也造成了集羣,一樣兩個廚師也仍是集羣,這樣多個集羣一塊兒就行程了 分佈式集羣系統 web

 

分佈式和集羣的關係:面試

  分佈式主要的功能是將咱們的系統模塊化,將系統進行解耦,方便咱們的維護和開發。可是其並不能解決併發問題,也沒法保證咱們的系統在服務器宕機後的正常運轉。redis

  集羣剛好彌補了分佈式的缺陷,集羣,就是多個服務器處理相同的業務,一方面能夠解決或者說改善咱們系統的併發問題,另外一方面能夠解決咱們服務器若是出現必定數量的宕機後,系統仍然能夠正常運轉。算法

2. 爲何要用分佈式?爲何要用集羣?

爲何用分佈式?spring

  傳統的項目中咱們將各個模塊放在一個系統中,系統過於龐大,開發維護困難,各個功能模塊之間的耦合度高,沒法針對單個模塊進行優化。而使用分佈式架構將系統模塊化,便於咱們的維護和開發。sql

咱們的項目之因此利用分佈式架構開發,是由於整個項目實現的功能較多,使每一個功能模塊獨立出來,下降了各系統之間的耦合度,增刪一個功能不會影響其餘功能模塊。數據庫

爲何用集羣?

  項目若是部署在一臺Tomcat上,全部的請求都由這一臺服務器處理,會存在很大風險:

  1. 單臺服務器併發處理能力有限。(通常單臺服務器處理的併發量爲250左右,超過250,可能會出現數據丟失,連接不穩定的狀況)
  2. 使用單臺服務器,一旦服務器故障,整個服務就沒法訪問了。
  3. 單臺服務器計算能力低,沒法完成複雜的海量數據計算。

  集羣是是指將多臺服務器集中在一塊兒,每臺服務器都實現相同的業務,作相同的事情。可是每臺服務器並非缺一不可,存在的做用主要是緩解併發壓力和單點故障轉移問題

集羣的兩大特色與兩大能力:

  兩大特色:可擴展性、高可用性

  1. 可擴展性:集羣的性能不限制於單一的服務實體,新的服務實體能夠動態的添加到集羣,從而加強集羣的性能。
  2. 高可用性:集羣當其中一個節點發生故障時,這臺節點上面所運行的應用程序將在另外一臺節點被自動接管,消除單點故障對於加強數據可用性、可達性和可靠性是很是重要的。

  兩大能力:負載均衡、錯誤恢復

  1. 負載均衡:負載均衡把任務比較均勻的分佈到集羣環境下的計算和網絡資源,以提升數據吞吐量。
  2. 錯誤恢復:若是集羣中的某一臺服務器因爲故障或者維護須要沒法使用,資源和應用程序將轉移到可用的集羣節點上。這種因爲某個節點的資源不能工做,另外一個可用節點中的資源可以透明的接管並繼續完成任務的過程,叫作錯誤恢復。

3.爲何通常集羣都要用3臺服務器來組建?

  • 一臺機器叫單機,不算分佈式。
  • 兩臺機器組成的的集羣,當有一臺機器出現故障另外一臺機器並不能及時做出反應,何況兩臺機器當穩定性不必定要比單機更好。
  • 當有三臺服務器是能實現zookeeper容錯。

4. 你說項目基於SOA架構,什麼是SOA架構?

   SOA:面向服務的架構。也就是把工程都拆分紅服務層工程、表現層工程。服務層中包含業務邏輯,只須要對外提供服務便可。表現層只須要處理和頁面的交互,業務邏輯都是調用服務層的服務來實現。工程均可以獨立部署。

 

項目基於SOA的架構,表現層和服務層是不一樣的工程。因此要實現商品列表查詢須要兩個系統之間進行通訊。如何實現遠程通訊?

  使用dubbo。使用rpc協議進行遠程調用,直接使用socket通訊,傳輸效率高,而且能夠統計出系統之間的調用關係、調用次數,管理服務。

4.介紹一下dubbo.

  Dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案。

(注意不要與負載均衡搞混:負載均衡是對外提供一個公共地址,請求過來時經過輪詢、隨機等,路由到不一樣的服務器。)

說一下dubbo的架構、服務註冊與發現的流程:

Dubbo有5種節點角色:

  • Privoder(服務提供者):用於暴露服務
  • Consumer(服務消費者):用來調用遠程服務
  • Registry(註冊中心):註冊與發現服務
  • Monitor(監控中心):統計服務的調用次數與調用時間
  • Container(服務運行容器)

 流程:

0. 服務容器用來啓動、加載、運行服務提供者;

1. 服務提供者在啓動時,向註冊中心註冊本身提供的服務;

2. 服務消費者在啓動時,想註冊中心訂閱本身所需的服務;

3. 註冊中心返回服務提供者地址列表給消費者。若是有變動,註冊中心將基於長鏈接推送變動數據給消費者;

4. 服務消費者從提供者地址列表中,(基於軟負載均衡)選一臺服務提供者進行調用,若是調用失敗,再選另外一臺調用;

5. 服務提供者和消費者,在內存中累計調用次數與調用時間,定時每分鐘發送統計數據到監控中心。

註冊中心的做用?Dubbo的註冊中心有哪些?你使用的哪一個?

  註冊中心存儲着Provider註冊的遠程服務,並將其所管理的服務列表通知給服務消費方(Consumer),且註冊中心和提供方和消費方之間均保持長鏈接,能夠獲取Provider發佈的服務的變化狀況,並將最新的服務列表推送給Consumer。

  Dubbo的註冊中心有Zookeeper、Redis、Multicast、Simple等。咱們使用的是Zookeeper

Dubbo的spring配置方式?

   服務定義部分放在服務提供方的xml文件:在提供方增長暴露服務配置<dubbo:service>

  <!-- ================項目中服務層爲提供方,使用dubbo發佈服務=================== -->
    <!-- 提供方應用信息,用於計算依賴關係 -->
    <dubbo:application name="taotao-manager" />
    <dubbo:registry protocol="zookeeper" address="192.168.25.129:2181" />
    <!-- 用dubbo協議在20880端口暴露服務 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <!-- 聲明須要暴露的服務接口 -->
    <dubbo:serviceinterface="com.taotao.service.ItemService" ref="itemServiceImpl" />

  服務引用部分放在服務消費方的xml文件:在消費方增長引用服務配置<dubbo:reference>

    <!-- ================項目中表現層爲消費方,引用dubbo服務======================= -->
    <dubbo:application name="taotao-manager-web" />
    <dubbo:registry protocol="zookeeper" address="192.168.25.129:2181" />
    <dubbo:referenceinterface="com.taotao.service.ItemService" id="itemService" />

【注】address的值是本身的zookeeper所在系統的ip地址和端口,若是是集羣,就用逗號分開:

<dubbo:registry protocol="zookeeper" address="192.168.25.140:2181,192.168.25.140:2182,192.168.25.140:2183" /dubbo:registry>

Dubbo默認使用的是什麼通訊框架,還有別的選擇嗎?

  默認也推薦使用netty框架,還有mina。

5.介紹Zoookeeper

看這個http://www.javashuo.com/article/p-ecjpropq-ed.html

  Zookeeper工做原理(詳細)

  ZooKeeper是一個開源的分佈式協調服務,它是集羣的管理者,監視着集羣中各個節點的狀態根據節點提交的反饋進行下一步合理操做。最終,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。

  分佈式應用程序能夠基於Zookeeper實現諸如數據發佈/訂閱、負載均衡、命名服務、分佈式協調/通知、集羣管理、Master選舉、分佈式鎖和分佈式隊列等功能。

  • Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫作Zab協議。Zab協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啓動或者在領導者崩潰後,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步之後恢復模式就結束了。狀態同步保證了leader和Server具備相同的系統狀態。
  • 爲了保證事務的順序一致性,zookeeper採用了遞增的事務id號(zxid)來標識事務。全部的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64位的數字,它高32位是epoch用來標識leader關係是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬於那個leader的統治時期。低32位用於遞增計數。

服務器角色:Leader、Follower、Observer

  • Leader(領導者):事務請求的惟一調度和處理者,保證集羣事務處理的順序性;集羣內部各服務的調度者。
  • Follower(跟隨者):處理客戶端的非事務請求,轉發事務請求給Leader服務器;參與Leader選舉投票。
  • Observer(觀察者):3.3版本之後引入的一個服務器角色,處理客戶端的非事務請求,轉發事務請求給Leader服務器;不參與任何形式的投票。

Zookeeper 下Server工做狀態:

  服務器具備四種狀態,分別是Looking、Following、Leading、Observing。

  • Looking:尋找Leader狀態。當服務器處於該狀態時,它會認爲當前集羣中沒有Leader,所以須要進入Leader選舉狀態。
  • Following:跟隨者狀態。代表當前服務器角色是Follower。
  • Leading:領導者狀態。代表當前服務器角色是Leader。
  • Observing:觀察者狀態。代表當前服務器角色是Observer。

Leader 選舉:半數經過

  每次投票後,服務器都會統計投票信息,判斷是否已經有過半機器接受到相同的投票信息,若是有,此時便認爲已經選出了Leader。

 

 

 

------------Redis------------

個人這篇博客Redis面試題

還有一篇讀書筆記《Redis開發與運維》

項目:淘淘商城05——首頁輪播圖顯示實現&Redis環境搭建&Redis實現緩存

1.爲何用redis?

  像項目中首頁的大廣告和商品類目這些不須要常常修改的數據,若是用戶每次刷新頁面的時候都要去數據庫中查詢,這樣會浪費資源和增長數據庫的壓力。因此咱們想當把這些數據添加到一個緩存中,用戶去訪問的時候,先去緩存中查詢,若是沒有,再去數據庫中查詢,而後把查詢到的數據添加到緩存中。(操做緩存就是直接操做內存,因此速度至關快)

2.介紹一下redis.

  Redis是一種基於 key-value 對非關係型數據庫(nosql),與不少鍵值對數據庫不一樣的是,Redis中的值能夠是由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合等多種數據結構和算法組成,所以Redis能夠知足不少的應用場景。並且由於Redis會將全部數據都存放在內存中,因此它的讀寫性能很是驚人。不只如此,Redis還提供了持久化功能(RDB和AOF),防止redis宕機時的數據丟失。(能夠將內存的數據利用快照(RDB)和日誌(AOF)的形式保存到硬盤上,這樣在發生相似斷電或者機器故障的時候,內存中的數據不會「丟失」)

  Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上

  咱們使用的是spring與jedis整合的客戶端,能夠利用jedis作分片式集羣,解決了redis內存受限的問題。

3.你說使用redis的集羣,爲何搭建redis集羣?搭建redis集羣的步驟?

  使用集羣的緣由就是 單臺服務器併發處理能力有限,而且一旦服務器故障,整個服務就沒法訪問了。集羣就是將多臺服務器都集中在一塊兒,每臺服務器都實現相同的業務,而且若有一臺服務器發生故障,他所運行的業務能夠被其餘服務器進行接管,這樣就緩解併發壓力和單點故障轉移問題,保障了redis的性能。

搭建redis集羣的步驟:

  (至少3個節點,爲了集羣的高可用,爲每個節點增長一個備份機。(6臺服務器,3主3從)。搭建僞分佈式集羣方案:在一臺機器裏面運行6個redis實例。端口須要不一樣(7001-7006)。)

一、首先在linux系統上安裝一個redis:步驟就是【首先上傳redis源碼包(put)並解壓(tar -zxvf),而後進行編譯(make)和安裝】

  1. 第1步:將redis的源碼包上傳到linux系統。 Alt+p打開sftp窗口:輸入put "F:/java/ziyuan/redis-3.0.0.tar.gz"
  2. 第2步:解壓:tar -zxvf redis-3.0.0.tar.gz
  3. 第3步:進行編譯。 cd到解壓後的目錄 輸入命令:make  
  4. 第4步:進行安裝。 輸入命令:make install PREFIX=/usr/local/redis 

二、而後建立咱們集羣要安裝的目錄(redis-cluster),copy以前搭建好的redis共6份,而後分別進入其bin目錄修改redis.conf配置文件,分別更改端口號(爲7001到7006),並開啓集羣cluster-enabled yes。

  1. 建立咱們集羣要安裝的目錄:[root@localhost local]# mkdir redis-cluster
  2. copy 以前搭建好的redis 並更名爲redis01 :[root@localhost local]# cp redis/ redis-cluster/redis01 -r
  3. 分別進入其bin目錄修改redis.conf配置文件[root@localhost bin]# vim redis.conf
  4. 而後啓動各個節點並檢查 redis 啓動狀況。cd /usr/local/redis-cluster/redis01/bin ./redis-server redis.conf

三、Redis 官方提供了 redis-trib.rb 這個工具來建立集羣,這個工具是用ruby腳本實現的,因此須要安裝ruby:

yum -y  install  ruby ruby-devel rubygems rpm-build

gem install redis

四、而後使用ruby腳本搭建集羣。從解壓目錄下的src下的拷貝redis-trib.rb文件到redis-cluster目錄中 cp redis-trib.rb  /usr/local/redis-cluster/,接着執行下面命令就可完成安裝:

[root@localhost redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005  192.168.25.153:7006

 

說一下redis cluster原理:

  redis cluster在設計的時候,就考慮到了去中心化,去中間件,也就是說,集羣中的每一個節點都是平等的關係,每一個節點都保存各自的數據和整個集羣的狀態。每一個節點都和其餘全部節點鏈接,並且這些鏈接保持活躍,這樣就保證了咱們只須要鏈接集羣中的任意一個節點,就能夠獲取到其餘節點的數據。

  Redis 集羣沒有並使用傳統的一致性哈希來分配數據,而是採用一種叫作哈希槽 (hash slot)的方式來分配數據的。redis cluster 默認分配了 16384 個slot,當須要在 Redis 集羣中放置一個 key-value 時,redis先對key使用crc16算法算出一個結果,而後把結果對16384求餘數,這樣每一個key都會對應一個編號在 0-16383之間的哈希槽,redis會根據節點數量大體均等的將哈希槽映射到不一樣的節點

  Redis 集羣會把數據存在一個 master節點,而後在這個 master 和其對應的salve之間進行數據同步當讀取數據時,也根據一致性哈希算法到對應的 master 節點獲取數據只有當一個master 掛掉以後,纔會啓動一個對應的 salve 節點,充當 master

須要注意的是:必需要3個或以上的主節點,不然在建立集羣時會失敗,而且當存活的主節點數小於總節點數的一半時,整個集羣就沒法提供服務了。

http://www.javashuo.com/article/p-mxdparyf-gg.html

4.如何保證Ridis數據與MySql數據一致性?

採用以下策略:

  • 讀的時候:先讀緩存,讀到數據則直接返回;若是沒有讀到,就讀數據庫,同時將數據放入緩存,並返回響應。
  • 更新的時候:先更新數據庫,而後再刪除緩存。

爲何?

  1. 讀的邏輯你們都很容易理解,談談更新。若是不採起我提到的這種更新方法,你還能想到什麼更新方法呢?大概會是:先刪除緩存,而後再更新數據庫。這麼作引起的問題是,若是A,B兩個線程同時要更新數據,而且A,B已經都作完了刪除緩存這一步,接下來,A先更新了數據庫,C線程讀取數據,因爲緩存沒有,則查數據庫,並把A更新的數據,寫入了緩存,最後B更新數據庫。那麼緩存和數據庫的值就不一致了

  2. 另外有人會問,若是採用你提到的方法,爲何最後是把緩存的數據刪掉,而不是把更新的數據寫到緩存裏?這麼作引起的問題是,若是A,B兩個線程同時作數據更新,A先更新了數據庫,B後更新數據庫,則此時數據庫裏存的是B的數據。而更新緩存的時候,是B先更新了緩存,而A後更新了緩存,則緩存裏是A的數據。這樣緩存和數據庫的數據也不一致

5. redis兩種持久化方式?

Redis支持RDBAOF兩種持久化機制,持久化功能有效地避免因進程退出形成的數據丟失問題,當下次重啓時利用以前持久化的文件便可實現數據恢復。

RDB持久化:是把當前進程數據生成快照保存到硬盤的過程。觸發RDB持久化過程分爲手動觸發(save、bgsave)和自動觸發。

  • 優勢:
    • RDB是一個緊湊壓縮的二進制文件,表明Redis在某個時間點上的數據快照。很是適用於備份,全量複製等場景。好比每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
    • Redis加載RDB恢復數據遠遠快於AOF的方式
  • 缺點:
    • RDB方式數據沒辦法作到實時持久化/秒級持久化。由於bgsave每次運行都要執行fork操做建立子進程,屬於重量級操做,頻繁執行成本太高。

AOF(append only file)持久化獨立日誌的方式記錄每次寫命令,重啓時再從新執行AOF文件中的命令達到恢復數據的目的。AOF的主要做用是解決了數據持久化的實時性

  AOF默認是默認不開啓的,開啓AOF功能須要設置配置:appendonly yes。

  AOF緩衝區同步文件策略,由參數appendfsync控制:

appendfsync always    #每次有數據修改發生時都會寫入AOF文件,這樣會嚴重下降Redis的速度
appendfsync everysec  #每秒鐘同步一次,顯示地將多個寫命令同步到硬盤
appendfsync no        #讓操做系統決定什麼時候進行同步

【注】若是同時配了RDB和AOF,優先加載AOF。

 5. 大家redis 存的是什麼格式的數據,都是怎麼存的?

  redis中存放數據都是key -value的形式。

  咱們商城使用String格式來存放的。拿商品來講:商品的Id就是Key ,商品相關的商品信息組成一個JSON存放。

------------數據庫-----------

 用到了數據庫事務

    <!-- 事務管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 數據源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 傳播行爲 -->
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>
    
    <!-- 切面 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice"  pointcut="execution(* com.taotao.service.*.*(..))" />
    </aop:config>
相關文章
相關標籤/搜索