日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【三万字!】Dubbo、Zookeeper学习笔记!秒杀面试官!——双非上岸阿里巴巴系列

發(fā)布時間:2024/2/28 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【三万字!】Dubbo、Zookeeper学习笔记!秒杀面试官!——双非上岸阿里巴巴系列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

東北某不知名雙非本科,四面成功上岸阿里巴巴,在這里把自己整理的筆記分享出來,歡迎大家閱讀。

恰個飯——>《阿里巴巴 Java 開發(fā)手冊》,業(yè)界普遍遵循的開發(fā)規(guī)范


本博客內容持續(xù)維護,如有改進之處,還望各位大佬指出,感激不盡!


文章目錄

  • Dubbo部分
    • 第一章 分布式系統(tǒng)相關概念
      • 1.1 大型互聯(lián)網項目架構目標
      • 1.2 集群和分布式
      • 1.3 架構演進
    • 第二章 Dubbo概述
      • 2.1 Dubbo概念
      • 2.2 Dubbo架構
        • 2.2.1 Dubbo架構及調用順序
        • 2.2.2 Dubbo特點
    • 第三章 Dubbo快速入門
      • 3.1 Zookeeper
        • 3.1.1 Zookeeper概述
        • 3.1.2 Zookeeper安裝與配置
        • 下載安裝
        • 配置啟動
      • 3.2 Dubbo快速入門
        • 3.2.1 Spring和SpringMVC整合
        • 3.2.2 服務提供者
        • 3.2.3 服務消費者
    • 第四章 Dubbo高級特性
      • 4.1 Dubbo-admin管理平臺
        • 4.1.1 dubbo-admin安裝
        • 4.1.2 dubbo-admin簡單使用
      • 4.2 Dubbo常用高級配置
        • 4.2.1 序列化
        • 4.2.2 地址緩存
        • 4.2.3 超時
        • 4.2.4 重試
        • 4.2.5 多版本
        • 4.2.6 負載均衡
        • 4.2.7 集群容錯
        • 4.2.8 服務降級
  • Zookeeper部分
    • 第一章 初識Zookeeper
      • 1.1 Zookeeper概念
    • 第二章 Zookeeper安裝與配置
    • 第三章 Zookeeper命令操作
      • 3.1 Zookeeper命令操作數據類型
      • 3.2 Zookeeper命令操作服務端命令
      • 3.3 Zookeeper客戶端常用命令
      • 3.4 客戶端命令-創(chuàng)建臨時有序節(jié)點
    • 第四章 ZooKeeper JavaAPI 操作
      • 4.1 Curator介紹
      • 4.2 基本操作(配置管理)
        • 操作-建立連接
        • 操作-創(chuàng)建節(jié)點
        • 操作-查詢節(jié)點
        • 操作-修改節(jié)點
        • 操作-刪除節(jié)點
        • 操作-Watch監(jiān)聽概述
          • 監(jiān)聽-NodeCache
          • 監(jiān)聽-PathChildrenCache
          • 監(jiān)聽-TreeCache
      • 4.3 Zookeeper分布式鎖
        • 分布式鎖概念
        • 分布式鎖原理
        • 分布式鎖-模擬12306售票案例
      • 4.4 ZooKeeper 集群搭建
        • 集群介紹
        • 搭建要求
        • 準備工作
        • 配置集群
        • 啟動集群
        • 故障測試
        • Zookeeper 核心理論
  • 相關注解
    • @Service
    • @Reference
  • 儲備知識
    • QoS服務
    • Node.js是干嘛的
    • 項目打包的作用
    • 序列化和反序列化


Dubbo部分

第一章 分布式系統(tǒng)相關概念

1.1 大型互聯(lián)網項目架構目標


互聯(lián)網項目特點:用戶多、流量大、并發(fā)高、海量數據、易受攻擊、功能繁瑣、變更快

大型互聯(lián)網項目架構性能指標:響應時間、并發(fā)數、吞吐量

大型互聯(lián)網項目架構目標:高性能、高可用(網站一直可以正常訪問)、可伸縮(通過硬件增加/減少,提高/減低處理能力)、高可擴展(耦合低、方便通過新增/移除方式,增加/減少功能模塊)、安全性、敏捷性

1.2 集群和分布式

集群:一個業(yè)務模塊,部署在多臺服務器上。

分布式:一個大的業(yè)務系統(tǒng),拆分成小的業(yè)務模塊,分別部署在不同的機器上。

1.3 架構演進




個人理解:微服務架構是對SOA架構的進一步拆分和細化

Dubbo是SOA時代的產物,SpringCloud是微服務時代的產物

第二章 Dubbo概述

2.1 Dubbo概念

  • Dubbo是阿里巴巴公司開源的一個高性能、輕量級的Java RPC框架
  • 致力于提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。
  • 官網:http://dubbo.apache.org

2.2 Dubbo架構

2.2.1 Dubbo架構及調用順序

節(jié)點角色說明

節(jié)點角色說明
Provider暴露服務的服務提供方
Consumer調用遠程服務的服務消費方
Registry服務注冊與發(fā)現的注冊中心
Monitor統(tǒng)計服務的調用次數和調用時間的監(jiān)控中心
Container服務運行容器

調用關系說明參考文檔

  • 服務容器負責啟動,加載,運行服務提供者。
  • 服務提供者在啟動時,向注冊中心注冊自己提供的服務。
  • 服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
  • 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基于長連接推送變更數據給消費者。
  • 服務消費者,從提供者地址列表中,基于軟負載均衡算法,選一臺提供者進行調用,如果調用失敗,再選另一臺調用。
  • 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發(fā)送一次統(tǒng)計數據到監(jiān)控中心。
  • Dubbo 架構具有以下幾個特點,分別是連通性、健壯性、伸縮性、以及向未來架構的升級性

    個人理解:Registry就相當于ESB,Consumer和Provider通過其連接

    2.2.2 Dubbo特點

    連通性

    • 注冊中心負責服務地址的注冊與查找,相當于目錄服務,服務提供者和消費者只在啟動時與注冊中心交互,注冊中心不轉發(fā)請求,壓力較小
    • 監(jiān)控中心負責統(tǒng)計各服務調用次數,調用時間等,統(tǒng)計先在內存匯總后每分鐘一次發(fā)送到監(jiān)控中心服務器,并以報表展示
    • 服務提供者向注冊中心注冊其提供的服務,并匯報調用時間到監(jiān)控中心,此時間不包含網絡開銷
    • 服務消費者向注冊中心獲取服務提供者地址列表,并根據負載算法直接調用提供者,同時匯報調用時間到監(jiān)控中心,此時間包含網絡開銷
    • 注冊中心,服務提供者,服務消費者三者之間均為長連接,監(jiān)控中心除外
    • 注冊中心通過長連接感知服務提供者的存在,服務提供者宕機,注冊中心將立即推送事件通知消費者
    • 注冊中心和監(jiān)控中心全部宕機,不影響已運行的提供者和消費者,消費者在本地緩存了提供者列表
    • 注冊中心和監(jiān)控中心都是可選的,服務消費者可以直連服務提供者

    健壯性

    • 監(jiān)控中心宕掉不影響使用,只是丟失部分采樣數據
    • 數據庫宕掉后,注冊中心仍能通過緩存提供服務列表查詢,但不能注冊新服務
    • 注冊中心對等集群,任意一臺宕掉后,將自動切換到另一臺
    • 注冊中心全部宕掉后,服務提供者和服務消費者仍能通過本地緩存通訊
    • 服務提供者無狀態(tài),任意一臺宕掉后,不影響使用
    • 服務提供者全部宕掉后,服務消費者應用將無法使用,并無限次重連等待服務提供者恢復

    伸縮性

    • 注冊中心為對等集群,可動態(tài)增加機器部署實例,所有客戶端將自動發(fā)現新的注冊中心
    • 服務提供者無狀態(tài),可動態(tài)增加機器部署實例,注冊中心將推送新的服務提供者信息給消費者

    升級性

    當服務集群規(guī)模進一步擴大,帶動IT治理結構進一步升級,需要實現動態(tài)部署,進行流動計算,現有分布式服務架構不會帶來阻力。下圖是未來可能的一種架構:

    節(jié)點角色說明

    節(jié)點角色說明
    Deployer自動部署服務的本地代理
    Repository倉庫用于存儲服務應用發(fā)布包
    Scheduler調度中心基于訪問壓力自動增減服務提供者
    Admin統(tǒng)一管理控制臺
    Registry服務注冊與發(fā)現的注冊中心
    Monitor統(tǒng)計服務的調用次數和調用時間的監(jiān)控中心

    第三章 Dubbo快速入門

    3.1 Zookeeper

    3.1.1 Zookeeper概述

    注冊中心:https://dubbo.apache.org/zh/docs/v2.7/user/references/registry/

    Zookeeper是Apache Hadoop的子項目,是一個樹形的目錄服務,適合作為Dubbo服務的注冊中心,工業(yè)強度較高,可用于生產環(huán)境,并推薦使用。

    更詳細概述,見我的HSF筆記

    3.1.2 Zookeeper安裝與配置

    下載安裝

    1、環(huán)境準備:Java1.7+

    2、上傳:將下載的ZooKeeper放到/opt/ZooKeeper目錄下

    #上傳zookeeper alt+p put f:/setup/apache-zookeeper-3.5.6-bin.tar.gz #打開 opt目錄 cd /opt #創(chuàng)建zooKeeper目錄 mkdir zooKeeper #將zookeeper安裝包移動到 /opt/zooKeeper mv apache-zookeeper-3.5.6-bin.tar.gz /opt/zookeeper/

    3、解壓:將tar包解壓到/opt/zookeeper目錄下

    tar -zxvf apache-ZooKeeper-3.5.6-bin.tar.gz

    配置啟動

    1、配置zoo.cfg

    進入conf目錄拷貝一個zoo_sample.cfg并完成配置(zoo_sample本質上不起配置作用,只是一個模板,需要自行創(chuàng)建zoo.cfg并修改配置內容。)

    #進入到conf目錄 cd /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/ #拷貝(將zoo_sample.cfg拷貝一份,名字是zoo.cfg) cp zoo_sample.cfg zoo.cfg

    修改zoo.cfg

    #打開目錄 cd /opt/zooKeeper/ #創(chuàng)建zooKeeper存儲目錄 mkdir zkdata #修改zoo.cfg vim /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/conf/zoo.cfg

    修改存儲目錄:dataDir = /opt/zookeeper/zkdata

    2、啟動zookeeper

    cd /opt/zooKeeper/apache-zooKeeper-3.5.6-bin/bin/ #啟動(.sh文件一般為腳本執(zhí)行文件,zkServer是注冊中心的意思)./zkServer.sh start

    看到上圖表示zookeeper已經成功啟動。

    3、查看zookeeper狀態(tài)

    ./zkServer.sh status

    zookeeper啟動成功。standalone代表zk沒有搭建集群,現在是單節(jié)點

    zookeeper沒有啟動成功

    3.2 Dubbo快速入門

    3.2.1 Spring和SpringMVC整合

    代碼:1. spring和springmvc整合后代碼

    實施步驟:

    1、創(chuàng)建服務提供者Provider模塊

    2、創(chuàng)建服務消費者Consumer模塊

    3、在服務提供者模塊編寫UserServiceImpl提供服務

    4、在服務消費者中的UserController遠程調用(提供者是Service,消費者是Controller)

    5、UserServiceImpl提供的服務

    6、分別啟動兩服務,測試。

    Dubbo作為一個RPC框架,其最核心的功能就是要實現跨網絡的遠程調用。本小節(jié)就是要創(chuàng)建兩個應用,一個作為服務的提供方,一個作為服務的消費方。通過Dubbo來實現服務消費方遠程調用服務提供方的方法。

    0、創(chuàng)建項目、準備環(huán)境

    首先創(chuàng)建空項目

    接下來配置Maven地址

    接下來創(chuàng)建Maven的Module

    新建服務方:

    新建消費方:

    接下來就是編寫邏輯代碼了。

    核心原理:consumer中的pom.xml中添加了servicer的pom依賴,本質上并沒有用到dubbo

    3.2.2 服務提供者

    代碼見:2. dubbo快速入門

    dubbo的作用:

    服務提供者編寫過程:

    1、將Servicer的服務注冊到Zookeeper中(注冊中心)

    2、在mvc的xml中編寫dubbo的配置,包括配置項 目的名稱(唯一標識),配置注冊中心(zookeeper)的地址,配置dubbo包掃描的路徑

    3、配置web.xml

    3.2.3 服務消費者

    服務消費者編寫過程:

    1、在Controller中遠程注入userService,即獲取其url(拋棄Autowired注解,使用Reference注解)

    2、在mvc的xml中編寫dubbo的配置,包括配置項目的名稱(唯一標識),配置注冊中心的地址(本機ip+端口),配置dubbo包掃描的路徑

    3、配置web.xml

    服務方和消費方都遵循上述配置,不同的是消費方配置的是Controller,并且不用放到注冊中心

    **注意:當消費者調用提供者的Service方法時,消費者中也要定義相對應的Service類的接口,因此為了去冗余設計,新定義一個interface的module,來做代碼提取。**至于如何調用,直接在Servicer和Consumer的pom.xml中定義即可。

    以上,完成了最最最最簡單的Dubbo的功能實現。

    第四章 Dubbo高級特性

    4.1 Dubbo-admin管理平臺

    簡介:

    • dubbo-admin管理平臺,是圖形化的服務管理頁面
    • 從注冊中心獲取到所有提供者/消費者進行配置管理
    • 路由規(guī)則、動態(tài)配置、服務降級、訪問控制、權重調整、負載均衡等管理功能
    • dubbo-admin是一個前后端分離的項目。前端使用vue,后端使用springboot
    • 安裝dubbo-admin其實就是部署該項目

    4.1.1 dubbo-admin安裝

    1、環(huán)境準備

    dubbo-admin 是一個前后端分離的項目。前端使用vue,后端使用springboot,安裝 dubbo-admin 其實就是部署該項目。我們將dubbo-admin安裝到開發(fā)環(huán)境上。要保證開發(fā)環(huán)境有jdk,maven,nodejs

    安裝node**(如果當前機器已經安裝請忽略)**

    因為前端工程是用vue開發(fā)的,所以需要安裝node.js,node.js中自帶了npm,后面我們會通過npm啟動

    把node.js理解成更牛逼的tomcat就行

    下載地址

    https://nodejs.org/en/

    2、下載 Dubbo-Admin

    進入github,搜索dubbo-admin

    https://github.com/apache/dubbo-admin

    下載:

    3、把下載的zip包解壓到指定文件夾(解壓到那個文件夾隨意)

    4、修改配置文件

    解壓后我們進入…\dubbo-admin-develop\dubbo-admin-server\src\main\resources目錄,找到 application.properties 配置文件 進行配置修改

    修改zookeeper地址

    # centers in dubbo2.7 admin.registry.address=zookeeper://192.168.149.135:2181 admin.config-center=zookeeper://192.168.149.135:2181 admin.metadata-report.address=zookeeper://192.168.149.135:2181

    admin.registry.address注冊中心(服務信息的中介(非持久化)
    admin.config-center 配置中心(存儲 Dubbo 服務的各種治理規(guī)則(持久化)
    admin.metadata-report.address元數據中心(元數據是指 Dubbo服務對應的方法列表以及參數結構等信息

    5、打包項目

    在 dubbo-admin-develop 目錄執(zhí)行打包命令

    mvn clean package

    6、啟動后端

    切換到目錄

    dubbo-Admin-develop\dubbo-admin-distribution\target>

    執(zhí)行下面的命令啟動 dubbo-admin,dubbo-admin后臺由SpringBoot構建。

    java -jar .\dubbo-admin-0.1.jar

    7、前臺后端

    dubbo-admin-ui 目錄下執(zhí)行命令

    npm run dev

    8、訪問

    瀏覽器輸入。用戶名密碼都是root

    http://localhost:8081/

    4.1.2 dubbo-admin簡單使用

    注意:Dubbo Admin【服務Mock】【服務統(tǒng)計】將在后續(xù)版本發(fā)布…

    在上面的步驟中,我們已經進入了Dubbo-Admin的主界面,在【快速入門】章節(jié)中,我們定義了服務生產者、和服務消費者,下面我們從Dubbo-Admin管理界面找到這個兩個服務

    1、點擊服務查詢

    2、查詢結果

    A:輸入的查詢條件com.itheima.service.UserService

    B:搜索類型,主要分為【按服務名】【按IP地址】【按應用】三種類型查詢

    C:搜索結果

    3.1.4 dubo-admin查看詳情

    我們查看com.itheima.service.UserService (服務提供者)的具體詳細信息,包含【元數據信息】

    1)點擊詳情

    從【詳情】界面查看,主要分為3個區(qū)域

    A區(qū)域:主要包含服務端 基礎信息比如服務名稱、應用名稱等

    B區(qū)域:主要包含了生產者、消費者一些基本信息

    C區(qū)域:是元數據信息,注意看上面的圖,元數據信息是空的

    我們需要打開我們的生產者配置文件加入下面配置

    <!-- 元數據配置 --><dubbo:metadata-report address="zookeeper://192.168.149.135:2181" />

    重新啟動生產者,再次打開Dubbo-Admin

    這樣我們的元數據信息就出來了

    4.2 Dubbo常用高級配置

    4.2.1 序列化

    注意!!!將來所有的pojo類都需要實現Serializable接口!

    代碼實現見:3. dubbo高級特性-序列化

    兩臺機器之間傳輸數據,通過序列化和反序列化傳輸Java對象

  • dubbo 內部已經將序列化和反序列化的過程內部封裝了
  • 我們只需要在定義pojo類時實現Serializable接口即可
  • 一般會定義一 個公共的pojo模塊,讓生產者和消費者都依賴該模塊。
  • User對象未實現Serializable接口

    錯誤信息:

    解決辦法:

    User implements Serializable

    下圖為項目的基礎架構圖:

  • interface的pom中寫入pojo的依賴。service和web的pom中寫入interface的依賴。
  • User繼承了序列化接口
  • 4.2.2 地址緩存

    注冊中心掛了,服務是否可以正常訪問?

  • 可以,因為dubbo服務消費者在第一-次調用時,會將服務提供方地址緩存到本地,以后在調用則不會訪問注冊中心。
  • 當服務提供者地址發(fā)生變化時,注冊中心會通知服務消費者。
  • 運行后,發(fā)現還是可以繼續(xù)訪問的。

    4.2.3 超時

    參考代碼:4. 超時與重試

    • 服務消費者在調用服務提供者的時候發(fā)生了阻塞、等待的情形,這個時候,服務消費者會直等待下去。
    • 在某個峰值時刻,大量的請求都在同時請求服務消費者,會造成線程的大量堆積,勢必會造成雪崩。
    • dubbo利用超時機制來解決這個問題,設置-個超時時間, 在這個時間段內,無法完成服務訪問,則自動斷開連接。
    • 使用timeout屬性配置超時時間,默認值1000,單位毫秒
    //timeout 超時時間 單位毫秒 retries 重試次數 @Service(timeout = 3000,retries=0)

    代碼實現:用sleep模擬服務器查詢很慢:

    4.2.4 重試

  • 設置了超時時間,在這個時間段內,無法完成服務訪問,則自動斷開連接。
  • 如果出現網絡抖動,則這一-次請求就會失敗。
  • Dubbo提供重試機制來避免類似問題的發(fā)生。
  • 通過retries屬性來設置重試次數。默認為2次
  • //timeout 超時時間 單位毫秒 retries 重試次數 @Service(timeout = 3000,retries=2)

    4.2.5 多版本

    參考代碼:5. 多版本

    **灰度發(fā)布:**當出現新功能時,會讓一部分用戶先使用新功能,用戶反饋沒問題時,再將所有用戶遷移到新功能。

    dubbo中使用version屬性來設置和調用同一個接口的不同版本

    生產者配置(通過@Service注解)

    @Service(version="v2.0") public class UserServiceImp12 implements UserService {...}

    消費者配置(通過@Reference注解)

    @Reference(version = "v2.0")//遠程注入 private UserService userService;

    代碼示例:

    4.2.6 負載均衡

    解釋:當存在多個服務提供者時,消費者應該怎樣消費,才能使多個服務提供者的負載均衡。

    負載均衡策略(4種) :

  • **Random:**按權重隨機,默認值。按權重設置隨機概率。

  • RoundRobin: 按權重輪詢。

  • LeastActive: 最少活躍調用數,相同活躍數的隨機。

  • **ConsistentHash: **一致性Hash,相同參數的請求總是發(fā)到同一提供者。

  • 服務提供者配置

    @Service(weight = 100) public class UserServiceImp12 implements UserService {...}

    application.xml 配置parameter key

    消費者配置

    //@Reference(loadbalance = "roundrobin") //@Reference(loadbalance = "leastactive") //@Reference(loadbalance = "consistenthash") @Reference(loadbalance = "random")//默認 按權重隨機 private UserService userService;

    代碼參考:

    4.2.7 集群容錯

    解釋:如果某一個服務器出錯了,則選擇執(zhí)行什么策略。是換其他服務器重試,還是直接返回失敗等等。

    集群容錯模式:
    **Failover Cluster:**失敗重試。默認值。當出現失敗,重試其它服務器,默認重試2次,使用retries配置。一般用于讀操作
    **Failfast Cluster 😗*快速失敗,發(fā)起-次調用,失敗立即報錯。通常用于寫操作。
    **Failsafe Cluster:**失敗安全,出現異常時,直接忽略。返回一個空結果。
    **Failback Cluster:**失敗自動恢復,后臺記錄失敗請求,定時重發(fā)。
    **Forking Cluster 😗*并行調用多個服務器,只要一個成功即返回。
    Broadcast Cluster: 廣播調用所有提供者,逐個調用,任意一臺報錯則報錯。

    消費者配置

    @Reference(cluster = "failover")//遠程注入 private UserService userService;

    代碼示例:

    4.2.8 服務降級

    服務降級:當服務器壓力劇增的情況下,根據實際業(yè)務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運作或高效運作

    服務降級方式:
    mock= force:return null:表示消費方對該服務的方法調用都直接返回null值,不發(fā)起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。

    mock=fail:return null:表示消費方對該服務的方法調用在失敗后,再返回null值,不拋異常。用來容忍不重要服務不穩(wěn)定時對調用方的影響

    消費方配置

    //遠程注入 @Reference(mock ="force :return null")//不再調用userService的服務 private UserService userService;

    Zookeeper部分

    第一章 初識Zookeeper

    1.1 Zookeeper概念

    • Zookeeper 是 Apache Hadoop 項目下的一個子項目,是一個樹形目錄服務。

    • Zookeeper 翻譯過來就是 動物園管理員,他是用來管 Hadoop(大象)、Hive(蜜蜂)、Pig(小 豬)的管理員。簡稱zk

    • Zookeeper 是一個分布式的、開源的分布式應用程序的協(xié)調服務。

    • Zookeeper提供的功能主要包括

      • 配置管理(增刪改查)
      • 分布式鎖(常規(guī)鎖無效,因為是不同機器(常規(guī)鎖由JDK提供),不同集群,因此要采用分布式鎖)
      • 集群管理

    第二章 Zookeeper安裝與配置

    見3.1

    第三章 Zookeeper命令操作

    3.1 Zookeeper命令操作數據類型

    • ZooKeeper 是一個樹形目錄服務,其數據模型和Unix的文件系統(tǒng)目錄樹很類似,擁有一個層次化結構。

    • 這里面的每一個節(jié)點都被稱為: ZNode,每個節(jié)點上都會保存自己的數據和節(jié)點信息

    • 節(jié)點可以擁有子節(jié)點,同時也允許少量(1MB)數據存儲在該節(jié)點之下。

    • 節(jié)點可以分為四大類:

      • PERSISTENT 持久化節(jié)點
      • EPHEMERAL 臨時節(jié)點 :-e (服務端關閉后就消失了)
      • PERSISTENT_SEQUENTIAL 持久化順序節(jié)點 :-s (即節(jié)點后跟序號)
      • EPHEMERAL_SEQUENTIAL 臨時順序節(jié)點 :-es

    3.2 Zookeeper命令操作服務端命令

    進入到Zookeeper/bin中,可執(zhí)行如下操作

    • 啟動 ZooKeeper 服務: ./zkServer.sh start

    • 查看 ZooKeeper 服務狀態(tài): ./zkServer.sh status

    • 停止 ZooKeeper 服務: ./zkServer.sh stop

    • 重啟 ZooKeeper 服務: ./zkServer.sh restart

    3.3 Zookeeper客戶端常用命令

    概述:連接上Server(服務端)后,操作節(jié)點。

    • 連接ZooKeeper服務端
    ./zkCli.sh –server ip:port
    • 斷開連接
    quit
    • 查看命令幫助
    help
    • 顯示指定目錄下節(jié)點(如果目錄是/,則為根節(jié)點)
    ls 目錄
    • 創(chuàng)建節(jié)點(節(jié)點里面存放value)
    create /節(jié)點path value 例子: create /app1
    • 獲取節(jié)點值
    get /節(jié)點path
    • 設置節(jié)點值
    set /節(jié)點path value
    • 刪除單個節(jié)點
    delete /節(jié)點path
    • 刪除帶有子節(jié)點的節(jié)點
    deleteall /節(jié)點path

    3.4 客戶端命令-創(chuàng)建臨時有序節(jié)點

    • 創(chuàng)建臨時節(jié)點
    create -e /節(jié)點path value
    • 創(chuàng)建順序節(jié)點
    create -s /節(jié)點path value
    • 查詢節(jié)點詳細信息
    ls –s /節(jié)點path
    • czxid:節(jié)點被創(chuàng)建的事務ID

    • ctime: 創(chuàng)建時間

    • mzxid: 最后一次被更新的事務ID

    • mtime: 修改時間

    • pzxid:子節(jié)點列表最后一次被更新的事務ID

    • cversion:子節(jié)點的版本號

    • dataversion:數據版本號

    • aclversion:權限版本號

    • ephemeralOwner:用于臨時節(jié)點,代表臨時節(jié)點的事務ID,如果為持久節(jié)點則為0

    • dataLength:節(jié)點存儲的數據的長度

    • numChildren:當前節(jié)點的子節(jié)點個數

    以上的命令也側面體現出了Zookeeper的作用,即持久化or非持久化存儲數據、配置管理、分布式鎖、集群管理(節(jié)點儲存信息,樹形結構、方便查找)

    第四章 ZooKeeper JavaAPI 操作

    4.1 Curator介紹

    其核心就是對節(jié)點的操作,對節(jié)點的操作貫穿配置管理、分布式鎖、集群搭建三大模塊

    • Curator 是 Apache ZooKeeper 的Java客戶端庫。

    • 常見的ZooKeeper Java API :

      • 原生Java API
      • ZkClient
      • Curator
    • Curator 項目的目標是簡化 ZooKeeper 客戶端的使用。

    • Curator 最初是 Netfix 研發(fā)的,后來捐獻了 Apache 基金會,目前是 Apache 的頂級項目。

    • 官網:http://curator.apache.org/

    4.2 基本操作(配置管理)

    操作-建立連接

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kF4w6Jb7-1626871686069)(/Users/zhanglong/Library/Application Support/typora-user-images/image-20210720110747301.png)]

    具體代碼見資料

    1、搭建項目

    創(chuàng)建項目curator-zk

    引入pom和日志文件

    資料文件夾下pom.xml和log4j.properties

    2、創(chuàng)建測試類,使用curator連接zookeeper

    @Before public void testConnect() {//重試策略RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);//2.第二種方式//CuratorFrameworkFactory.builder();client = CuratorFrameworkFactory.builder().connectString("192.168.200.130:2181").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("itheima").build();//開啟連接client.start(); }

    操作-創(chuàng)建節(jié)點

    /** * 創(chuàng)建節(jié)點:create 持久 臨時 順序 數據 * 1. 基本創(chuàng)建 :create().forPath("") * 2. 創(chuàng)建節(jié)點 帶有數據:create().forPath("",data) * 3. 設置節(jié)點的類型:create().withMode().forPath("",data) * 4. 創(chuàng)建多級節(jié)點 /app1/p1 :create().creatingParentsIfNeeded().forPath("",data) */ @Test public void testCreate() throws Exception {//2. 創(chuàng)建節(jié)點 帶有數據//如果創(chuàng)建節(jié)點,沒有指定數據,則默認將當前客戶端的ip作為數據存儲String path = client.create().forPath("/app2", "hehe".getBytes());System.out.println(path); } @Test public void testCreate2() throws Exception {//1. 基本創(chuàng)建//如果創(chuàng)建節(jié)點,沒有指定數據,則默認將當前客戶端的ip作為數據存儲String path = client.create().forPath("/app1");System.out.println(path); } @Test public void testCreate3() throws Exception {//3. 設置節(jié)點的類型//默認類型:持久化String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");System.out.println(path); } @Test public void testCreate4() throws Exception {//4. 創(chuàng)建多級節(jié)點 /app1/p1//creatingParentsIfNeeded():如果父節(jié)點不存在,則創(chuàng)建父節(jié)點String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1");System.out.println(path); }

    操作-查詢節(jié)點

    /** * 查詢節(jié)點: * 1. 查詢數據:get: getData().forPath() * 2. 查詢子節(jié)點: ls: getChildren().forPath() * 3. 查詢節(jié)點狀態(tài)信息:ls -s:getData().storingStatIn(狀態(tài)對象).forPath() */ @Test public void testGet1() throws Exception {//1. 查詢數據:getbyte[] data = client.getData().forPath("/app1");System.out.println(new String(data)); } @Test public void testGet2() throws Exception {// 2. 查詢子節(jié)點: lsList<String> path = client.getChildren().forPath("/");System.out.println(path); } @Test public void testGet3() throws Exception {Stat status = new Stat();System.out.println(status);//3. 查詢節(jié)點狀態(tài)信息:ls -sclient.getData().storingStatIn(status).forPath("/app1");System.out.println(status); }

    操作-修改節(jié)點

    /** * 修改數據 * 1. 基本修改數據:setData().forPath() * 2. 根據版本修改: setData().withVersion().forPath() * * version 是通過查詢出來的。目的就是為了讓其他客戶端或者線程不干擾我。 * * @throws Exception */ @Test public void testSet() throws Exception {client.setData().forPath("/app1", "itcast".getBytes()); } @Test public void testSetForVersion() throws Exception {Stat status = new Stat();//3. 查詢節(jié)點狀態(tài)信息:ls -sclient.getData().storingStatIn(status).forPath("/app1");int version = status.getVersion();//查詢出來的 3System.out.println(version);client.setData().withVersion(version).forPath("/app1", "hehe".getBytes()); }

    操作-刪除節(jié)點

    /** * 刪除節(jié)點: delete deleteall * 1. 刪除單個節(jié)點:delete().forPath("/app1"); * 2. 刪除帶有子節(jié)點的節(jié)點:delete().deletingChildrenIfNeeded().forPath("/app1"); * 3. 必須成功的刪除:為了防止網絡抖動。本質就是重試。 client.delete().guaranteed().forPath("/app2"); * 4. 回調:inBackground * @throws Exception */ @Test public void testDelete() throws Exception {// 1. 刪除單個節(jié)點client.delete().forPath("/app1"); } @Test public void testDelete2() throws Exception {//2. 刪除帶有子節(jié)點的節(jié)點client.delete().deletingChildrenIfNeeded().forPath("/app4"); } @Test public void testDelete3() throws Exception {//3. 必須成功的刪除client.delete().guaranteed().forPath("/app2"); } @Test public void testDelete4() throws Exception {//4. 回調client.delete().guaranteed().inBackground(new BackgroundCallback(){@Overridepublic void processResult(CuratorFramework client, CuratorEvent event) throws Exception {System.out.println("我被刪除了~");System.out.println(event);}}).forPath("/app1"); }

    操作-Watch監(jiān)聽概述

    • ZooKeeper 允許用戶在指定節(jié)點上注冊一些Watcher,并且在一些特定事件觸發(fā)的時候,ZooKeeper 服務端會將事件通知到感興趣的客戶端上去,該機制是 ZooKeeper 實現分布式協(xié)調服務的重要特性。

    • ZooKeeper 中引入了Watcher機制來實現了發(fā)布/訂閱功能能,能夠讓多個訂閱者同時監(jiān)聽某一個對象,當一個對象自身狀態(tài)變化時,會通知所有訂閱者。

    • ZooKeeper 原生支持通過注冊Watcher來進行事件監(jiān)聽,但是其使用并不是特別方便

    ? 需要開發(fā)人員自己反復注冊Watcher,比較繁瑣。

    • Curator引入了 Cache 來實現對 ZooKeeper 服務端事件的監(jiān)聽。

    • ZooKeeper提供了三種Watcher:

      • NodeCache : 只是監(jiān)聽某一個特定的節(jié)點
      • PathChildrenCache : 監(jiān)控一個ZNode的子節(jié)點.
      • TreeCache : 可以監(jiān)控整個樹上的所有節(jié)點,類似于PathChildrenCache和NodeCache的組合
    監(jiān)聽-NodeCache
    /** * 演示 NodeCache:給指定一個節(jié)點注冊監(jiān)聽器 */ @Test public void testNodeCache() throws Exception {//1. 創(chuàng)建NodeCache對象final NodeCache nodeCache = new NodeCache(client,"/app1");//2. 注冊監(jiān)聽nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {System.out.println("節(jié)點變化了~");//獲取修改節(jié)點后的數據byte[] data = nodeCache.getCurrentData().getData();System.out.println(new String(data));}});//3. 開啟監(jiān)聽.如果設置為true,則開啟監(jiān)聽是,加載緩沖數據nodeCache.start(true);while (true){} }
    監(jiān)聽-PathChildrenCache
    @Test public void testPathChildrenCache() throws Exception {//1.創(chuàng)建監(jiān)聽對象PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/app2",true);//2. 綁定監(jiān)聽器pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() { @Overridepublic void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {System.out.println("子節(jié)點變化了~");System.out.println(event);//監(jiān)聽子節(jié)點的數據變更,并且拿到變更后的數據//1.獲取類型PathChildrenCacheEvent.Type type = event.getType();//2.判斷類型是否是updateif(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){System.out.println("數據變了!!!");byte[] data = event.getData().getData();System.out.println(new String(data));}}});//3. 開啟pathChildrenCache.start();while (true){} }
    監(jiān)聽-TreeCache
    /** * 演示 TreeCache:監(jiān)聽某個節(jié)點自己和所有子節(jié)點們 */ @Test public void testTreeCache() throws Exception {//1. 創(chuàng)建監(jiān)聽器TreeCache treeCache = new TreeCache(client,"/app2");//2. 注冊監(jiān)聽treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {System.out.println("節(jié)點變化了");System.out.println(event);}});//3. 開啟treeCache.start();while (true){} }

    4.3 Zookeeper分布式鎖

    核心實現原理:臨時順序節(jié)點。

    分布式鎖概念

    • 在我們進行單機應用開發(fā),涉及并發(fā)同步的時候,我們往往采用synchronized或者Lock的方式來解決多線程間的代碼同步問題,這時多線程的運行都是在同一個JVM之下,沒有任何問題。

    • 但當我們的應用是分布式集群工作的情況下,屬于多JVM下的工作環(huán)境,跨JVM之間已經無法通過多線程的鎖解決同步問題。

    • 那么就需要一種更加高級的鎖機制,來處理種跨機器的進程之間的數據同步問題——這就是分布式鎖。

    不同架構層面的分布式鎖實現

    分布式鎖原理

    • 核心思想:當客戶端要獲取鎖,則創(chuàng)建節(jié)點,使用完鎖,則刪除該節(jié)點。
    • 客戶端獲取鎖時,在lock節(jié)點下創(chuàng)建臨時順序節(jié)點。
    • 然后獲取lock下面的所有子節(jié)點,客戶端獲取到所有的子節(jié)點之后,如果發(fā)現自己創(chuàng)建的子節(jié)點序號最小,那么就認為該客戶端獲取到了鎖。使用完鎖后,將該節(jié)點刪除。
    • 如果發(fā)現自己創(chuàng)建的節(jié)點并非lock所有子節(jié)點中最小的,說明自己還沒有獲取到鎖,此時客戶端需要找到比自己小的那個節(jié)點,同時對其注冊事件監(jiān)聽器,監(jiān)聽刪除事件。
    • 如果發(fā)現比自己小的那個節(jié)點被刪除,則客戶端的Watcher會收到相應通知,此時再次判斷自己創(chuàng)建的節(jié)點是否是lock子節(jié)點中序號最小的,如果是則獲取到了鎖,如果不是則重復以上步驟繼續(xù)獲取到比自己小的一個節(jié)點并注冊監(jiān)聽。

    原理:以判斷是否獲取到最后一個節(jié)點來決定獲取順序,或者是否可以獲取,這樣就可以保證在同一時間該數據只被一個進程使用

    分布式鎖-模擬12306售票案例

    總結一下:和正常鎖的用法一樣,不過調用了不同方法。因為它都為我們封裝好了。

    Curator實現分布式鎖API

    • 在Curator中有五種鎖方案:

      • InterProcessSemaphoreMutex:分布式排它鎖(非可重入鎖)

      • InterProcessMutex:分布式可重入排它鎖

      • InterProcessReadWriteLock:分布式讀寫鎖

      • InterProcessMultiLock:將多個鎖作為單個實體管理的容器(單獨設置一個容器,把多個鎖放到這個容器里管理)

      • InterProcessSemaphoreV2:共享信號量(如信號量設為多少,就允許多少人同時訪問)

    1、創(chuàng)建線程進行加鎖設置

    public class Ticket12306 implements Runnable{private int tickets = 10;//數據庫的票數private InterProcessMutex lock ;@Overridepublic void run() {while(true){//獲取鎖try {lock.acquire(3, TimeUnit.SECONDS);if(tickets > 0){System.out.println(Thread.currentThread()+":"+tickets);Thread.sleep(100);tickets--;}} catch (Exception e) {e.printStackTrace();}finally {//釋放鎖try {lock.release();} catch (Exception e) {e.printStackTrace();}}}} }

    2、創(chuàng)建連接,并且初始化鎖

    public Ticket12306(){//重試策略RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);//2.第二種方式//CuratorFrameworkFactory.builder();CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192.168.149.135:2181").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).build();//開啟連接client.start();lock = new InterProcessMutex(client,"/lock"); }

    3、運行多個線程進行測試

    public class LockTest {public static void main(String[] args) {Ticket12306 ticket12306 = new Ticket12306();//創(chuàng)建客戶端Thread t1 = new Thread(ticket12306,"攜程");Thread t2 = new Thread(ticket12306,"飛豬");t1.start();t2.start();} }

    4.4 ZooKeeper 集群搭建

    集群介紹

    Leader選舉:

    • Serverid:服務器ID

      比如有三臺服務器,編號分別是1,2,3。

      編號越大在選擇算法中的權重越大。

    • Zxid:數據ID

      服務器中存放的最大數據ID。值越大說明數據越新,在選舉算法中數據越新權重越大。

    • 在Leader選舉的過程中,如果某臺ZooKeeper獲得了超過半數的選票,則此ZooKeeper就可以成為Leader了。

    搭建要求

    真實的集群是需要部署在不同的服務器上的,但是在我們測試時同時啟動很多個虛擬機內存會吃不消,所以我們通常會搭建偽集群,也就是把所有的服務都搭建在一臺虛擬機上,用端口進行區(qū)分。

    我們這里要求搭建一個三個節(jié)點的Zookeeper集群(偽集群)。

    準備工作

    重新部署一臺虛擬機作為我們搭建集群的測試服務器。

    (1)安裝JDK 【此步驟省略】。

    (2)Zookeeper壓縮包上傳到服務器(put命令)

    (3)將Zookeeper解壓 ,建立/usr/local/zookeeper-cluster目錄,將解壓后的Zookeeper復制到以下三個目錄

    /usr/local/zookeeper-cluster/zookeeper-1

    /usr/local/zookeeper-cluster/zookeeper-2

    /usr/local/zookeeper-cluster/zookeeper-3

    [root@localhost ~]# mkdir /usr/local/zookeeper-cluster [root@localhost ~]# cp -r apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-1 [root@localhost ~]# cp -r apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-2 [root@localhost ~]# cp -r apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-3

    (4)創(chuàng)建data目錄 ,并且將 conf下zoo_sample.cfg 文件改名為 zoo.cfg

    mkdir /usr/local/zookeeper-cluster/zookeeper-1/data mkdir /usr/local/zookeeper-cluster/zookeeper-2/data mkdir /usr/local/zookeeper-cluster/zookeeper-3/datamv /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo_sample.cfg /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg mv /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo_sample.cfg /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg mv /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo_sample.cfg /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

    (5) 配置每一個Zookeeper 的dataDir 和 clientPort 分別為2181 2182 2183

    修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg

    vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfgclientPort=2181 dataDir=/usr/local/zookeeper-cluster/zookeeper-1/data

    修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg

    vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfgclientPort=2182 dataDir=/usr/local/zookeeper-cluster/zookeeper-2/data

    修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

    vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfgclientPort=2183 dataDir=/usr/local/zookeeper-cluster/zookeeper-3/data

    配置集群

    (1)在每個zookeeper的 data 目錄下創(chuàng)建一個 myid 文件,內容分別是1、2、3 。這個文件就是記錄每個服務器的ID

    echo 1 >/usr/local/zookeeper-cluster/zookeeper-1/data/myid echo 2 >/usr/local/zookeeper-cluster/zookeeper-2/data/myid echo 3 >/usr/local/zookeeper-cluster/zookeeper-3/data/myid

    (2)在每一個zookeeper 的 zoo.cfg配置客戶端訪問端口(clientPort)和集群服務器IP列表。

    集群服務器IP列表如下

    vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfgserver.1=192.168.149.135:2881:3881 server.2=192.168.149.135:2882:3882 server.3=192.168.149.135:2883:3883

    解釋:server.服務器ID=服務器IP地址:服務器之間通信端口:服務器之間投票選舉端口(根據ip地址來判斷是否是同一個集群)

    啟動集群

    啟動集群就是分別啟動每個實例。

    /usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh start /usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start

    啟動后我們查詢一下每個實例的運行狀態(tài)

    /usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status /usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

    先查詢第一個服務

    Mode為follower表示是跟隨者(從)

    再查詢第二個服務Mod 為leader表示是領導者(主)

    查詢第三個為跟隨者(從)

    故障測試

    (1)首先我們先測試如果是從服務器掛掉,會怎么樣

    把3號服務器停掉,觀察1號和2號,發(fā)現狀態(tài)并沒有變化

    /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh stop /usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status /usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

    由此得出結論,3個節(jié)點的集群,從服務器掛掉,集群正常

    (2)我們再把1號服務器(從服務器)也停掉,查看2號(主服務器)的狀態(tài),發(fā)現已經停止運行了。

    /usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh stop/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

    由此得出結論,3個節(jié)點的集群,2個從服務器都掛掉,主服務器也無法運行。因為可運行的機器沒有超過集群總數量的半數。

    (3)我們再次把1號服務器啟動起來,發(fā)現2號服務器又開始正常工作了。而且依然是領導者。

    /usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh start/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

    (4)我們把3號服務器也啟動起來,把2號服務器停掉,停掉后觀察1號和3號的狀態(tài)。

    /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start /usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh stop/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

    發(fā)現新的leader產生了~

    由此我們得出結論,當集群中的主服務器掛了,集群中的其他服務器會自動進行選舉狀態(tài),然后產生新得leader

    (5)我們再次測試,當我們把2號服務器重新啟動起來啟動后,會發(fā)生什么?2號服務器會再次成為新的領導嗎?我們看結果

    /usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status /usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

    我們會發(fā)現,2號服務器啟動后依然是跟隨者(從服務器),3號服務器依然是領導者(主服務器),沒有撼動3號服務器的領導地位。

    由此我們得出結論,當領導者產生后,再次有新服務器加入集群,不會影響到現任領導者。

    Zookeeper 核心理論

    Zookeepe集群角色

    在ZooKeeper集群服中務中有三個角色:

    • Leader 領導者 :

    • 處理事務請求
    • 集群內部各服務器的調度者
    • Follower 跟隨者 :

    • 處理客戶端非事務請求,轉發(fā)事務請求給Leader服務器
    • 參與Leader選舉投票
    • Observer 觀察者:

    • 處理客戶端非事務請求,轉發(fā)事務請求給Leader服務器

    示意圖如下:

    相關注解

    @Service

    引入路徑:import org.apache.dubbo.config.annotation.Service;

    作用:將這個類提供的方法對外發(fā)布,將訪問的地址、ip、端口、路徑注冊到注冊中心里。

    @Reference

    翻譯:參考的,涉及的。

    代替@Autowired。

    @Autowired為本地注入,@Reference為遠程注入。

    儲備知識

    QoS服務

    QoS(Quality of Service,服務質量)指一個網絡能夠利用各種基礎技術,為指定的網絡通信提供更好的服務能力,是網絡的一種安全機制, 是用來解決網絡延遲和阻塞等問題的一種技術。dubbo為用戶提供類似的網絡服務用來online和offline service來解決網絡延遲,阻塞等問題。

    QoS配置

    dubbo的QoS是默認開啟的,端口為22222,可以通過配置修改端口

    <dubbo:application name="demo-provider"><dubbo:parameter key="qos.port" value="33333"/> </dubbo:application>

    或者關閉服務

    <dubbo:application name="demo-provider"><dubbo:parameter key="qos.enable" value="false"/> </dubbo:application>

    為了安全考慮,dubbo的qos默認是只支持本地連接的,如果要開啟任意ip可連接,需做如下配置

    <dubbo:application name="demo-provider"><dubbo:parameter key="qos.port" value="33333"/><dubbo:parameter key="qos.accept.foreign.ip" value="false"/> </dubbo:application>

    Node.js是干嘛的

    如果你去年注意過技術方面的新聞,我敢說你至少看到node.js不下一兩次。那么問題來了“node.js是什么?”。有些人沒準會告訴你“這是一種通過JavaScript語言開發(fā)web服務端的東西”。如果這種晦澀解釋還沒把你搞暈,你沒準會接著問:“為什么我們要用node.js?”,別人一般會告訴你:node.js有非阻塞,事件驅動I/O等特性,從而讓高并發(fā)(high concurrency)在的輪詢(Polling)和comet構建的應用中成為可能。

    當你看完這些解釋覺得跟看天書一樣的時候,你估計也懶得繼續(xù)問了。不過沒事。我這篇文章就是在避開高端術語的同時,幫助你你理解node.js的。

    瀏覽器給網站發(fā)請求的過程一直沒怎么變過。當瀏覽器給網站發(fā)了請求。服務器收到了請求,然后開始搜尋被請求的資源。如果有需要,服務器還會查詢一下數據庫,最后把響應結果傳回瀏覽器。不過,在傳統(tǒng)的web服務器中(比如Apache),每一個請求都會讓服務器創(chuàng)建一個新的進程來處理這個請求。

    后來有了Ajax。有了Ajax,我們就不用每次都請求一個完整的新頁面了,取而代之的是,每次只請求需要的部分頁面信息就可以了。這顯然是一個進步。但是比如你要建一個FriendFeed這樣的社交網站(類似人人網那樣的刷朋友新鮮事的網站),你的好友會隨時的推送新的狀態(tài),然后你的新鮮事會實時自動刷新。要達成這個需求,我們需要讓用戶一直與服務器保持一個有效連接。目前最簡單的實現方法,就是讓用戶和服務器之間保持長輪詢(long polling)。

    HTTP請求不是持續(xù)的連接,你請求一次,服務器響應一次,然后就完了。長輪訓是一種利用HTTP模擬持續(xù)連接的技巧。具體來說,只要頁面載入了,不管你需不需要服務器給你響應信息,你都會給服務器發(fā)一個Ajax請求。這個請求不同于一般的Ajax請求,服務器不會直接給你返回信息,而是它要等著,直到服務器覺得該給你發(fā)信息了,它才會響應。比如,你的好友發(fā)了一條新鮮事,服務器就會把這個新鮮事當做響應發(fā)給你的瀏覽器,然后你的瀏覽器就刷新頁面了。瀏覽器收到響應刷新完之后,再發(fā)送一條新的請求給服務器,這個請求依然不會立即被響應。于是就開始重復以上步驟。利用這個方法,可以讓瀏覽器始終保持等待響應的狀態(tài)。雖然以上過程依然只有非持續(xù)的Http參與,但是我們模擬出了一個看似持續(xù)的連接狀態(tài)

    我們再看傳統(tǒng)的服務器(比如Apache)。每次一個新用戶連到你的網站上,你的服務器就得開一個連接。每個連接都需要占一個進程,這些進程大部分時間都是閑著的(比如等著你好友發(fā)新鮮事,等好友發(fā)完才給用戶響應信息。或者等著數據庫返回查詢結果什么的)。雖然這些進程閑著,但是照樣占用內存。這意味著,如果用戶連接數的增長到一定規(guī)模,你服務器沒準就要耗光內存直接癱了。

    這種情況怎么解決?解決方法就是剛才上邊說的:非阻塞事件驅動。這些概念在我們談的這個情景里面其實沒那么難理解。你把非阻塞的服務器想象成一個loop循環(huán),這個loop會一直跑下去。一個新請求來了,這個loop就接了這個請求,把這個請求傳給其他的進程(比如傳給一個搞數據庫查詢的進程),然后響應一個回調(callback)。完事了這loop就接著跑,接其他的請求。這樣下來。服務器就不會像之前那樣傻等著數據庫返回結果了。

    如果數據庫把結果返回來了,loop就把結果傳回用戶的瀏覽器,接著繼續(xù)跑。在這種方式下,你的服務器的進程就不會閑著等著。從而在理論上說,同一時刻的數據庫查詢數量,以及用戶的請求數量就沒有限制了。服務器只在用戶那邊有事件發(fā)生的時候才響應,這就是事件驅動。

    FriendFeed是用基于Python的非阻塞框架Tornado (知乎也用了這個框架) 來實現上面說的新鮮事功能的。不過,Node.js就比前者更妙了。Node.js的應用是通過javascript開發(fā)的,然后直接在Google的變態(tài)V8引擎上跑。用了Node.js,你就不用擔心用戶端的請求會在服務器里跑了一段能夠造成阻塞的代碼了。因為javascript本身就是事件驅動的腳本語言。你回想一下,在給前端寫javascript的時候,更多時候你都是在搞事件處理和回調函數。javascript本身就是給事件處理量身定制的語言。

    Node.js還是處于初期階段。如果你想開發(fā)一個基于Node.js的應用,你應該會需要寫一些很底層代碼。但是下一代瀏覽器很快就要采用WebSocket技術了,從而長輪詢也會消失。在Web開發(fā)里,Node.js這種類型的技術只會變得越來越重要。

    總結:

    Apache:進程獨立,每個進程占用一定資源,無法釋放。

    ajax:長輪詢

    node.js:非阻塞、事件驅動。

    項目打包的作用

    如果用Linux語句運行項目,就一定要先打包,因為我們沒有像Idea一樣把項目整合在一起的工具, 因此只能把它打成一個Jar包,再運行。

    序列化和反序列化

    序列化是指將Java對象轉換為字節(jié)序列的過程,而反序列化則是將字節(jié)序列轉換為Java對象的過程。

    Java對象序列化是將實現了Serializable接口的對象轉換成一個字節(jié)序列,能夠通過網絡傳輸、文件存儲等方式傳輸 ,傳輸過程中卻不必擔心數據在不同機器、不同環(huán)境下發(fā)生改變,也不必關心字節(jié)的順序或其他任何細節(jié),并能夠在以后將這個字節(jié)序列完全恢復為原來的對象(恢復這一過程稱之為反序列化)。

    對象的序列化是非常有趣的,因為利用它可以實現輕量級持久性,“持久性”意味著一個對象的生存周期不單單取決于程序是否正在運行,它可以生存于程序的調用之間。通過將一個序列化對象寫入磁盤,然后在重新調用程序時恢復該對象,從而達到實現對象的持久性的效果。

    本質上講,序列化就是把實體對象狀態(tài)按照一定的格式寫入到有序字節(jié)流,反序列化就是從有序字節(jié)流重建對象,恢復對象狀態(tài)。

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的【三万字!】Dubbo、Zookeeper学习笔记!秒杀面试官!——双非上岸阿里巴巴系列的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。