久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

轻量级微服务架构

發(fā)布時(shí)間:2023/12/14 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 轻量级微服务架构 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 微服務(wù)架構(gòu)設(shè)計(jì)概述
    • 為什么需要微服務(wù)架構(gòu)
      • 傳統(tǒng)架構(gòu)的問(wèn)題
      • 如何解決傳統(tǒng)應(yīng)用架構(gòu)的問(wèn)題
      • 傳統(tǒng)架構(gòu)還有那些問(wèn)題
    • 微服務(wù)架構(gòu)是什么
    • 微服務(wù)架構(gòu)概念
      • 微服務(wù)的交付流程
      • 微服務(wù)開(kāi)發(fā)規(guī)范
      • 微服務(wù)架構(gòu)模式
    • 微服務(wù)架構(gòu)有哪些特點(diǎn)和挑戰(zhàn)
      • 微服務(wù)架構(gòu)的特點(diǎn)
      • 微服務(wù)架構(gòu)的挑戰(zhàn)
    • 如何搭建微服務(wù)架構(gòu)
      • 微服務(wù)架構(gòu)圖
      • 微服務(wù)的技術(shù)選型
  • 微服務(wù)開(kāi)發(fā)框架
    • Spring Boot是什么
      • SpringBoot的由來(lái)
      • Spring Boot 特性
      • SpringBoot相關(guān)插件
      • SpringBoot的應(yīng)用場(chǎng)景
    • 如何使用SpringBoot框架
      • 搭建SpringBoot開(kāi)發(fā)框架
      • 開(kāi)發(fā)一個(gè)簡(jiǎn)單的SpringBoot應(yīng)用程序
      • 運(yùn)行SpringBoot應(yīng)用程序
    • SpringBoot的生產(chǎn)級(jí)特性
      • 端點(diǎn)
      • 健康檢查
      • 應(yīng)用基本信息
      • 跨域
      • 外部配置
      • 遠(yuǎn)程監(jiān)控
  • 微服務(wù)網(wǎng)關(guān)
    • Node.js是什么
      • Node.js快速入門(mén)
      • Node.js的應(yīng)用場(chǎng)景
    • 如何使用Node.js
    • 安裝Node.js
      • 使用Node.js開(kāi)發(fā)WEB應(yīng)用
  • 微服務(wù)注冊(cè)與發(fā)現(xiàn)
    • ZooKeeper是什么
      • ZooKeeper樹(shù)狀模型
      • ZooKeeper的集群結(jié)構(gòu)
      • 如何使用ZooKeeper
      • 運(yùn)行ZooKeeper
      • 使用ZooKeeper搭建集群環(huán)境
      • 使用命令行客戶(hù)端鏈接ZooKeeper
      • 使用java客戶(hù)端鏈接ZooKeeper
      • 使用Node.js客戶(hù)端鏈接ZooKeeper
    • 實(shí)現(xiàn)服務(wù)注冊(cè)組件
      • 設(shè)計(jì)服務(wù)注冊(cè)表數(shù)據(jù)結(jié)構(gòu)
  • 微服務(wù)封裝
    • Docker是什么
      • Docker簡(jiǎn)介
      • 虛擬機(jī)與Docker對(duì)比
      • Docker的特點(diǎn)
  • 微服務(wù)的部署
      • Jenkins簡(jiǎn)介

微服務(wù)架構(gòu)設(shè)計(jì)概述

自從Martin Fowler(馬丁)在2014年提出了Micro Service(微服務(wù))的概念之后,業(yè)界就卷起了一股關(guān)于微服務(wù)的熱潮,大家討論多年的SOA(Service-Oriented Architecture,面向服務(wù)的架構(gòu))終于有了新的解決方案,人們不再需要笨重的ESB(Enterprise Service Bus,企業(yè)服務(wù)總線(xiàn))。恰逢Docker技術(shù)逐漸普及,一個(gè)嶄新的輕量級(jí)SOA架構(gòu)MSA(Micro Service Architecture,微服務(wù)架構(gòu))伴隨著Docker容器技術(shù)正向我們攜手走來(lái)。

為什么需要微服務(wù)架構(gòu)

微服務(wù)架構(gòu)(MSA)的出現(xiàn)絕不是偶然的,由于傳統(tǒng)應(yīng)用架構(gòu)的不合理,從而產(chǎn)生了新的架構(gòu)模式,這類(lèi)現(xiàn)象再正常不過(guò)了。那么,傳統(tǒng)的架構(gòu)究竟有哪些問(wèn)題呢?下面進(jìn)行分析。

傳統(tǒng)架構(gòu)的問(wèn)題

下圖是一個(gè)經(jīng)典的Java Web應(yīng)用程序,它包括Web UI部分,還包括若干個(gè)業(yè)務(wù)模塊,就像這里出現(xiàn)的ModelA、ModelB、ModelC等。
WebUI與這些Model封裝在一個(gè)war包中,因此需要將此war部署到Web Server(例如TOMCAT)上才能運(yùn)行,該應(yīng)用程序會(huì)連接到DataBase(如MySQL)上操作數(shù)據(jù)。
在系統(tǒng)運(yùn)行過(guò)程中,我們通過(guò)監(jiān)視程序發(fā)現(xiàn),ModelA和ModelB都需要消耗10%的系統(tǒng)資源,加起來(lái)占總系統(tǒng)的20%,而ModelC卻需要占用80%的系統(tǒng)資源。運(yùn)行一段時(shí)間后,ModelC將會(huì)成為系統(tǒng)的瓶頸,從而降低系統(tǒng)的性能。
那么如何解決這個(gè)問(wèn)題呢?人們想到了一個(gè)辦法。

如何解決傳統(tǒng)應(yīng)用架構(gòu)的問(wèn)題

只需要將這個(gè)應(yīng)用程序復(fù)制一份相同的程序,并將其部署到另外一個(gè)Web Server上,下方還是鏈接到相同的DataBase,只是在這些Web Server的上方架設(shè)一臺(tái)Load Balancer(負(fù)載均衡器,LB),可見(jiàn)應(yīng)用程序獲得了“水平擴(kuò)展”。
請(qǐng)求首先會(huì)發(fā)送到LB上,通過(guò)LB上的路由算法(例如輪詢(xún)或哈希),將請(qǐng)求轉(zhuǎn)發(fā)到后面具體的Web Server上,這類(lèi)請(qǐng)求轉(zhuǎn)發(fā)技術(shù)被稱(chēng)為Reverse Proxy(反向代理)。
由于進(jìn)入LB的請(qǐng)求(流量)被均衡到下方各臺(tái)Web Server中了,流量得到了分?jǐn)?#xff0c;負(fù)載得到了均衡,因此該技術(shù)也被稱(chēng)為L(zhǎng)oad Balance(負(fù)載均衡)。
如果流量加大,我們還可以繼續(xù)水平擴(kuò)展更多的Web Server,該架構(gòu)理論上可以無(wú)限擴(kuò)展,只要LB能夠抗的住巨大流量就行。
通過(guò)上述方案,輕松的將負(fù)載進(jìn)行了均衡,在一定的程度上緩解了流量對(duì)Web Server的壓力,但此時(shí)卻造成了大量的系統(tǒng)資源浪費(fèi),比如對(duì)系統(tǒng)資源占用率不搞的ModelA和ModelB也進(jìn)行了水平擴(kuò)展,其實(shí)我們只想對(duì)ModelC進(jìn)行擴(kuò)展而已。
除了水平擴(kuò)展方案帶來(lái)的系統(tǒng)資源浪費(fèi),實(shí)際上傳統(tǒng)架構(gòu)還有其他的問(wèn)題,我們繼續(xù)討論。

傳統(tǒng)架構(gòu)還有那些問(wèn)題

傳統(tǒng)應(yīng)用架構(gòu)實(shí)際上是一個(gè)Monolith(單塊架構(gòu)),因?yàn)檎麄€(gè)應(yīng)用都被封裝在一個(gè)WebAPP中,就像是巨石一塊,無(wú)法拆解,我們所做的水平擴(kuò)展也只是在擴(kuò)展一塊塊的巨石。為了便于表達(dá),我們不妨將單塊架構(gòu)搭建起來(lái)的應(yīng)用簡(jiǎn)稱(chēng)為“單塊應(yīng)用”。
我們?cè)俨渴饐螇K應(yīng)用的時(shí)候,同樣也會(huì)遇到很多的麻煩,比如:

  • 修改了一個(gè)Model(可能只是修改了一行代碼),就需要重新部署整個(gè)應(yīng)用。
  • 部署整個(gè)應(yīng)用所消耗的時(shí)間與對(duì)系統(tǒng)帶來(lái)的開(kāi)銷(xiāo)都是非常多的。

此外,對(duì)于Java Web應(yīng)用而言,打包war包里的代碼一般是class 文件,這也就意味著,我們的單塊應(yīng)用只是基于java語(yǔ)言開(kāi)發(fā)的,無(wú)法將應(yīng)用中某個(gè)單個(gè)的Model通過(guò)其他開(kāi)發(fā)語(yǔ)言來(lái)實(shí)現(xiàn)(假如我們不考慮JVM上運(yùn)行動(dòng)態(tài)語(yǔ)言的情況下),也許其他語(yǔ)言開(kāi)發(fā)實(shí)現(xiàn)某個(gè)模塊更加合適,這樣就會(huì)產(chǎn)生技術(shù)選型的單一問(wèn)題。
綜上所述,傳統(tǒng)應(yīng)用架構(gòu)存在以下問(wèn)題:

  • 系統(tǒng)資源浪費(fèi)
  • 部署效率太低
  • 技術(shù)選型單一

當(dāng)然,傳統(tǒng)應(yīng)用架構(gòu)的問(wèn)題還遠(yuǎn)不止這些。當(dāng)業(yè)務(wù)越來(lái)越復(fù)雜時(shí),應(yīng)用會(huì)變得越來(lái)越臃腫,“身材”越來(lái)越“胖”而無(wú)法瘦身。于是,人們找到了新的思路來(lái)解決傳統(tǒng)應(yīng)用架構(gòu)的問(wèn)題,這就是微服務(wù)架構(gòu)。
那么微服務(wù)架構(gòu)與傳統(tǒng)應(yīng)用架構(gòu)的區(qū)別到底在哪?我們繼續(xù)探討。

微服務(wù)架構(gòu)是什么

微服務(wù)架構(gòu)從字面上來(lái)理解就是:許多微小服務(wù)搭建起來(lái)的應(yīng)用架構(gòu)。
這句話(huà)涉及到很多問(wèn)題,我們逐一討論,比如:

  • 服務(wù)多“微”才能叫微服務(wù)?
  • 如何管理越來(lái)越多的微服務(wù)?
  • 客戶(hù)端是怎樣調(diào)用微服務(wù)的?

帶著這些問(wèn)題,開(kāi)始下面的討論,首先我們來(lái)看如何定義微服務(wù)架構(gòu)。

微服務(wù)架構(gòu)概念

當(dāng)馬丁大神提出微服務(wù)架構(gòu)這個(gè)概念的時(shí)候,同時(shí)他也對(duì)微服務(wù)架構(gòu)提出了幾條要求,也就是說(shuō),當(dāng)我們的應(yīng)用滿(mǎn)足一下條件時(shí),才能稱(chēng)之為微服務(wù)架構(gòu),具體包括:

  • 根據(jù)業(yè)務(wù)模塊劃分服務(wù)種類(lèi);
  • 每個(gè)服務(wù)可以獨(dú)立部署且相互隔離
  • 通過(guò)輕量級(jí)API調(diào)用服務(wù)
  • 服務(wù)保證良好的高可用性

我們簡(jiǎn)單的分析一下:首先根據(jù)產(chǎn)品的業(yè)務(wù)功能模塊來(lái)劃分服務(wù)種類(lèi),也就是說(shuō),我們需要按照業(yè)務(wù)功能去劃分種類(lèi),這是“垂直劃分”;而在代碼層面上進(jìn)行劃分,這是“水平劃分”。每個(gè)服務(wù)可以獨(dú)立部署,還需要相互隔離,也就是說(shuō),服務(wù)之間是沒(méi)有任何干擾的,可將每個(gè)服務(wù)放入到獨(dú)立的程序中運(yùn)行,因?yàn)檫M(jìn)程之間是完全隔離的。客戶(hù)端通過(guò)輕量級(jí)API來(lái)調(diào)用微服務(wù),比如可以通過(guò)HTTP或者RPC的方式來(lái)調(diào)用,目的是為了降低調(diào)用所產(chǎn)生的的性能開(kāi)銷(xiāo)。服務(wù)需要確保高可用性,不能長(zhǎng)時(shí)間的無(wú)法響應(yīng),需要提供多個(gè)“候補(bǔ)隊(duì)員”,在某個(gè)服務(wù)出現(xiàn)故障時(shí),可以自動(dòng)調(diào)用其中一個(gè)正常工作的服務(wù)。
微服務(wù)架構(gòu)顛覆了傳統(tǒng)應(yīng)用架構(gòu)的模式,若不定義良好的交付流程與開(kāi)發(fā)規(guī)范,則很難讓微服務(wù)發(fā)揮出真正的價(jià)值,下面我們來(lái)看一下微服務(wù)的交付流程。

微服務(wù)的交付流程

使用微服務(wù)架構(gòu)開(kāi)發(fā)應(yīng)用程序,我們實(shí)際上是針對(duì)一個(gè)個(gè)服務(wù)進(jìn)行設(shè)計(jì)、開(kāi)發(fā)、測(cè)試、部署。因?yàn)槊總€(gè)服務(wù)之間是沒(méi)有彼此依賴(lài)的,大概的交付流程付下:
在設(shè)計(jì)階段,架構(gòu)師將產(chǎn)品功能拆分成若干個(gè)服務(wù),為每個(gè)服務(wù)設(shè)計(jì)API接口(例如REST API),需要給出API文檔,包括API的名稱(chēng)、版本、請(qǐng)求參數(shù)、響應(yīng)結(jié)果、錯(cuò)誤代碼等信息。在開(kāi)發(fā)階段,開(kāi)發(fā)工程師去實(shí)現(xiàn)API接口,也包括完成API的單元測(cè)試工作。在此期間,前段工程師會(huì)并行開(kāi)發(fā)Web UI部分,可根據(jù)API文檔造出一些假數(shù)據(jù)(我們稱(chēng)之為“mock”數(shù)據(jù))。這樣一來(lái),前段工程師就不必等待后端API全部開(kāi)發(fā)完畢,才能開(kāi)始自己的工作。在測(cè)試階段,前后端工程師分別將自己的代碼部署到測(cè)試環(huán)境上,測(cè)試工程師將針對(duì)測(cè)試用例進(jìn)行手工或自動(dòng)化測(cè)試,隨后產(chǎn)品經(jīng)理將從產(chǎn)品功能上進(jìn)行驗(yàn)收。在部署階段,運(yùn)維工程師將代碼部署到預(yù)發(fā)環(huán)境中,測(cè)試工程師再一次進(jìn)行一些冒煙測(cè)試,當(dāng)不在發(fā)生任何問(wèn)題的時(shí)候,經(jīng)技術(shù)經(jīng)理確認(rèn),運(yùn)維工程師將代碼部署到生產(chǎn)環(huán)境中,這一系列的部署過(guò)程都需要做到自動(dòng)化,才能提高效率。
需要注意的是,以上過(guò)程中看似需要多種工程師參與,實(shí)際上并非每種角色都對(duì)應(yīng)具體的工程師。往往在小的團(tuán)隊(duì)里,一名工程師可以身兼多職,這些都是正常現(xiàn)象。只是對(duì)于大團(tuán)隊(duì)而言,分工比較明確,更容易實(shí)施這套交付流程。
在以上交付流程中,開(kāi)發(fā)、測(cè)試、部署這三個(gè)階段可能都會(huì)涉及對(duì)代碼的控制,我們還需要指定相關(guān)的開(kāi)發(fā)規(guī)范,以確保多人能夠良好的協(xié)作。

微服務(wù)開(kāi)發(fā)規(guī)范

無(wú)論使用傳統(tǒng)應(yīng)用架構(gòu),還是微服務(wù)架構(gòu),我們都需要定義良好的開(kāi)發(fā)規(guī)范。經(jīng)驗(yàn)表明,我們需要善用代碼版本控制系統(tǒng)。就拿Git來(lái)說(shuō),它很好的支持了多分支代碼版本,我們需要利用這個(gè)特性來(lái)提高開(kāi)發(fā)效率,下圖是一副經(jīng)典的分支管理規(guī)范:

最穩(wěn)定的代碼放在master分支上(想當(dāng)于SVN的trunk分支),我們不要直接在master分支上提交代碼,只能在分支上進(jìn)行合并操作,例如將其他分支的代碼合并到master分支上。
我們?nèi)粘i_(kāi)發(fā)中的代碼需要從master分支上拉下一條develop分支出來(lái),該分支所有人都能訪問(wèn),但一般情況下,我們也不會(huì)直接在該分支上提交代碼,代碼同樣是從其他分支上合并到develop上去的。
當(dāng)我們需要開(kāi)發(fā)某個(gè)新特性的時(shí)候,需要從develop分支上拉出一條feature分支,例如feature1和feature2,在這些分支上并行的開(kāi)發(fā)具體特性。
當(dāng)特性開(kāi)發(fā)完畢之后,我們決定發(fā)布某個(gè)版本了,此時(shí)需要從develop分支上拉出一條release分支,例如release-1.0,并將需要發(fā)布的特性從相關(guān)的feature分支合并到release分支上,隨后對(duì)release分支部署測(cè)試環(huán)境,測(cè)試工程師在該分支上做功能測(cè)試,開(kāi)發(fā)工程師在該分支上改bug。待測(cè)試工程師無(wú)法找到任何bug時(shí),我們可以將release分支部署到預(yù)發(fā)環(huán)境中。再次檢驗(yàn)以后,無(wú)任何bug,此時(shí)可以將release部署到生產(chǎn)環(huán)境上。待上線(xiàn)完成之后,將release分支上的代碼同時(shí)合并到develop分支與master分支上,并在master分支上打一個(gè)tag,例如v1.0.0。
當(dāng)在生產(chǎn)環(huán)境中發(fā)現(xiàn)bug時(shí),我們需要從對(duì)應(yīng)的tag上(例如v1.0.0)拉出一條hotfix分支(例如hotfix-1.0.1),并在該分支上進(jìn)行bug修復(fù),待bug完全修復(fù)后,需要將hotfix分支上的代碼同時(shí)合并到master和develop上。
對(duì)于版本號(hào)我們也有要求,格式為:x.y.z,其中x用于有重大重構(gòu)時(shí)才會(huì)升級(jí),y用于有新特性發(fā)布時(shí)才會(huì)升級(jí),z用于修復(fù)了某個(gè)bug后才會(huì)升級(jí)。
針對(duì)每個(gè)服務(wù)的開(kāi)發(fā)工作,我們都需要嚴(yán)格按照以上開(kāi)發(fā)規(guī)范來(lái)執(zhí)行。
實(shí)際上,我們使用的開(kāi)發(fā)規(guī)范是業(yè)界知名的Git Flow,可以通過(guò)以下博客了解到Git Flow的詳細(xì)過(guò)程:
http://nvie.com/posts/a-successful-git-branching-model/。
此外,在GitHub中有一個(gè)基于以上Git Flow的命令行工具,名為git-flow,其項(xiàng)目地址如下:
https://github.com/nive/gitflow。
我們已經(jīng)對(duì)微服務(wù)架構(gòu)的概念、交付流程、開(kāi)發(fā)規(guī)范進(jìn)行了描述,下面我們大致歸納一下微服務(wù)有哪些特點(diǎn)。

微服務(wù)架構(gòu)模式

世界著名軟件大師Chris Richardson(克里斯)創(chuàng)建了一個(gè)總結(jié)微服務(wù)架構(gòu)模式的網(wǎng)站。該網(wǎng)站上列出了大量的微服務(wù)架構(gòu)模式,分為:核心模式、部署模式、通信模式、服務(wù)發(fā)現(xiàn)模式、數(shù)據(jù)管理模式等。該網(wǎng)站的網(wǎng)址:http://microservice.io/。

微服務(wù)架構(gòu)有哪些特點(diǎn)和挑戰(zhàn)

微服務(wù)架構(gòu)相對(duì)于傳統(tǒng)的架構(gòu)有著顯著的特點(diǎn),同時(shí)微服務(wù)架構(gòu)也給我們帶來(lái)了一定的挑戰(zhàn),我們先從他的特點(diǎn)說(shuō)起。

微服務(wù)架構(gòu)的特點(diǎn)

  • 微小度顆粒
    微服務(wù)的粒度是根據(jù)業(yè)務(wù)功能來(lái)劃分的,對(duì)于某些復(fù)雜的業(yè)務(wù)來(lái)說(shuō),可能粒度較大,相對(duì)于簡(jiǎn)單的業(yè)務(wù)而言,可能粒度較小。總之,微服務(wù)的粒度可大可小,但往往我們希望他盡可能的小,但又不希望微服務(wù)之間有直接的依賴(lài),因此粒度的劃分是一件非常考驗(yàn)架構(gòu)師水平的事情。
  • 責(zé)任單一性
    我們需要確保每個(gè)微服務(wù)只做一件事情,也就是我們經(jīng)常提到的“單一職責(zé)原則”,該原則對(duì)微服務(wù)的劃分提供了指導(dǎo)方針。如果我們將一個(gè)服務(wù)提供多個(gè)API,那么就必須做到每個(gè)API職責(zé)單一性。
  • 運(yùn)行隔離性
    每個(gè)服務(wù)相互隔離,且互不影響。也就是說(shuō),每個(gè)服務(wù)運(yùn)行在自己的進(jìn)程中。眾所周知,進(jìn)程之間是隔離的,是安全的,而進(jìn)程內(nèi)部或線(xiàn)程之間的資源是共享的。換句話(huà)說(shuō),一個(gè)服務(wù)出了問(wèn)題,不會(huì)影響到其他服務(wù)。
  • 管理自動(dòng)化
    隨著業(yè)務(wù)功能不斷增多,服務(wù)的數(shù)量也會(huì)逐漸增加,我們需要對(duì)服務(wù)提供自動(dòng)化部署與監(jiān)控預(yù)警的能力,這樣才能更加高效的管理這些服務(wù)。需要注意的是,我們必須借助自動(dòng)化技術(shù),才能確保管理服務(wù)更加的容易。
  • 微服務(wù)的架構(gòu)特點(diǎn)非常明顯,可能還有很多,但同時(shí)微服務(wù)架構(gòu)也給我們帶來(lái)了許多挑戰(zhàn)。

    微服務(wù)架構(gòu)的挑戰(zhàn)

  • 運(yùn)行要求較高
    運(yùn)維工程師除了需要掌握使用自動(dòng)化技術(shù)來(lái)部署微服務(wù),還需要對(duì)整個(gè)微服務(wù)系統(tǒng)進(jìn)行有效的監(jiān)控,并保障系統(tǒng)的高可用性。可見(jiàn),微服務(wù)架構(gòu)的引入會(huì)帶來(lái)運(yùn)維成本的上升。
  • 分布式復(fù)雜性
    微服務(wù)架構(gòu)的本質(zhì)還是一個(gè)分布式架構(gòu),每個(gè)服務(wù)可以部署在任意的機(jī)器上。對(duì)于分布式系統(tǒng)而言,網(wǎng)絡(luò)延遲、系統(tǒng)容錯(cuò)、分布式事務(wù)等問(wèn)題都會(huì)給我們帶來(lái)很大的挑戰(zhàn)。
  • 部署依賴(lài)較強(qiáng)
    對(duì)于業(yè)務(wù)復(fù)雜的情況,可能存在多個(gè)服務(wù)來(lái)共同完成一件事情,服務(wù)之間雖然沒(méi)有相互調(diào)用,但可能會(huì)有調(diào)用的順序要求。業(yè)務(wù)上的依賴(lài)性導(dǎo)致了部署的依賴(lài)性,從而在某一時(shí)間點(diǎn),同一服務(wù)可能具備多個(gè)版本。
  • 通信成本較高
    既然微服務(wù)是隔離在自己進(jìn)程中運(yùn)行的,那么從客戶(hù)端調(diào)用微服務(wù),需要跨進(jìn)程進(jìn)行調(diào)用,而進(jìn)程間的調(diào)用一定比進(jìn)程內(nèi)的調(diào)用更加消耗資源,從而帶來(lái)通信成本上的開(kāi)銷(xiāo)。
  • 如何搭建微服務(wù)架構(gòu)

    可見(jiàn),微服務(wù)架構(gòu)的要求還是想當(dāng)高的,不僅僅對(duì)技術(shù),而且對(duì)運(yùn)維都有很高要求,我們需要設(shè)計(jì)出一款簡(jiǎn)單易用的輕量級(jí)微服務(wù)架構(gòu)來(lái)滿(mǎn)足自身的需求。下面用一張圖來(lái)描述一下我們對(duì)微服務(wù)架構(gòu)的愿景。

    微服務(wù)架構(gòu)圖

    我們不妨從下往上來(lái)理解這張圖。底層部署了一系列的Service,每個(gè)Service可能有自己的DB,或者多個(gè)Service公用一個(gè)DB,且同一個(gè)Service可部署多個(gè)。當(dāng)Service啟動(dòng)時(shí),會(huì)自動(dòng)的將信息注冊(cè)到Service Registry(服務(wù)注冊(cè)表)中,比如:每個(gè)服務(wù)的IP與端口。當(dāng)Web UI發(fā)出請(qǐng)求時(shí),該請(qǐng)求會(huì)發(fā)送到Service Gateway(服務(wù)網(wǎng)關(guān))中,Service Gateway讀取請(qǐng)求數(shù)據(jù),并從Service Registry中獲取對(duì)應(yīng)的Service信息(IP與端口號(hào)),最后,Service Gateway主動(dòng)調(diào)用下面對(duì)應(yīng)的Service。整個(gè)過(guò)程就是這樣,其中Service Gateway擔(dān)當(dāng)了重要角色。
    大家可能會(huì)認(rèn)為Service Gateway將成為一個(gè)中心,造成單點(diǎn)故障。沒(méi)錯(cuò),完全有這個(gè)可能,所以我們將他做的越“薄”越好,所以我們?cè)偌夹g(shù)選型上,要謹(jǐn)慎考慮。
    此外,對(duì)于Service Registry的高可用性也有很高的要求,他不僅在每個(gè)Service啟動(dòng)時(shí)提供“服務(wù)注冊(cè)”,還需要在Service Gateway處理每個(gè)請(qǐng)求時(shí)提供“服務(wù)發(fā)現(xiàn)”。如果他失效了,那么整個(gè)系統(tǒng)將無(wú)法工作。

    微服務(wù)的技術(shù)選型

    我們可以使用SpringBoot作為微服務(wù)開(kāi)發(fā)框架,SpringBoot擁有嵌入式Tomcat,可直接運(yùn)行一個(gè)jar包來(lái)運(yùn)行微服務(wù),此外,他還提供一些“開(kāi)箱即用”的插件,可大大提高我們的開(kāi)發(fā)效率,我們也可以去擴(kuò)展更多的插件。
    發(fā)布微服務(wù)時(shí),可以鏈接ZooKeeper來(lái)注冊(cè)微服務(wù),實(shí)現(xiàn)“服務(wù)注冊(cè)”。實(shí)際上ZooKeeper中有一個(gè)名為ZNode的內(nèi)存樹(shù)狀模型,樹(shù)上的結(jié)點(diǎn)用于存放微服務(wù)的配置信息。使用Node.js處理瀏覽器發(fā)送的請(qǐng)求,在Node.js中鏈接ZooKeeper,發(fā)現(xiàn)服務(wù)配置,實(shí)現(xiàn)“服務(wù)發(fā)現(xiàn)”,有大量的Node.js的ZooKeeper客戶(hù)端可以完成這個(gè)任務(wù)。
    通過(guò)Node.js將請(qǐng)求發(fā)送到Tomcat上,實(shí)現(xiàn)“反向代理”,同樣也有大量的Node.js庫(kù)供我們自由選擇。Node.js的“單線(xiàn)程模型”且“非阻塞異步式I/O”特性通過(guò)“事件循環(huán)”的方式來(lái)支撐大量的高并發(fā)請(qǐng)求,此外Node.js原生也提供了集群特性,可確保高可用性。
    為了實(shí)現(xiàn)微服務(wù)的自動(dòng)化部署,我們可以通過(guò)Jenkins搭建自動(dòng)化部署系統(tǒng),并使用Docker將服務(wù)進(jìn)行容器化封裝。
    綜上所述,微服務(wù)架構(gòu)技術(shù)選型如下所示:
    SpringBoot:http://projects.spring.io/spring-boot/。
    ZooKeeper:http://zookeeper.apache.org/。
    Node.js:https://nodejs.org/。
    Jenkins:https://jenkins.io/。
    Docker:https://www.docker.com/。
    我們通過(guò)一張圖來(lái)歸納一下微服務(wù)架構(gòu)的技術(shù)選型

  • 使用Jenkins部署服務(wù)
  • 使用SpringBoot開(kāi)發(fā)服務(wù)
  • 使用Docker封裝服務(wù)
  • 使用ZooKeeper注冊(cè)服務(wù)
  • 使用Node.js調(diào)用服務(wù)
  • 除了上述的技術(shù)選型外,實(shí)際上還有其他可選的方案,比如Netflix公司開(kāi)源的微服務(wù)技術(shù)棧:
    Netflix:http://netflix.github.io/。
    Spring官方在SpringBoot的基礎(chǔ)上,封裝了Netflix相關(guān)組件,提供了一個(gè)名為SpringCloud的開(kāi)源項(xiàng)目。
    SpringCloud:http://projects.spring.io/spring-cloud/。
    就連曾今的JBoss也推出了自己的微服務(wù)框架WildFly Swarm。
    WildFly Swarm:http://wildfly-swarm.io/。
    此外,還有一個(gè)輕量級(jí)的REST框架也宣稱(chēng)具備可開(kāi)發(fā)微服務(wù)的能力。
    Dropwizad:http://dropwizad.io/。
    以上僅為java相關(guān)的微服務(wù)技術(shù)選型,其他開(kāi)發(fā)語(yǔ)言也有自己的微服務(wù)開(kāi)發(fā)技術(shù)棧。

    微服務(wù)開(kāi)發(fā)框架

    Spring猶如一股清風(fēng),吹散了EJB對(duì)javaEE的絕對(duì)統(tǒng)治地位。他的IOC、AOP等特性開(kāi)啟了我們對(duì)面向?qū)ο缶幊痰男乱曇?#xff0c;讓我們驚嘆道:原來(lái)程序還能這樣寫(xiě)!隨著SpringMVC逐漸強(qiáng)大起來(lái),贏得了JAVA WEB開(kāi)發(fā)的很大的市場(chǎng)占有率。不管是struts還是Strust2都遜色于它,就連持久層技術(shù)Hibernate的市場(chǎng)也在逐漸縮小,因?yàn)镾pring+MyBitis早已成為市場(chǎng)主流。可以斷言,Spring“一統(tǒng)江湖”指日可待。實(shí)際上,Spring已經(jīng)十多歲了,在開(kāi)源世界里他已經(jīng)不再年輕,給我們的感覺(jué)是它的體積越來(lái)越大,使用起來(lái)越來(lái)越方便 。就像事先商量好的一樣,SpringBoot的誕生讓Spring應(yīng)用程序變得更加高效,恰巧當(dāng)Spring Boot遇上“微服務(wù)”之后,讓我們更加意識(shí)到,微服務(wù)的春天已經(jīng)悄悄來(lái)到了。

    Spring Boot是什么

    SpringBoot是為生產(chǎn)級(jí)Spring應(yīng)用而生的,他使得開(kāi)發(fā)Spring應(yīng)用程序更加高效、簡(jiǎn)潔。那么,SpringBoot具備哪些生產(chǎn)級(jí)特性呢?我們不妨從它的由來(lái)開(kāi)始講起。

    SpringBoot的由來(lái)

    在Spring1.0的時(shí)代,我們習(xí)慣于用XML文件來(lái)配置Bean,在XML文件中可以輕松的進(jìn)行依賴(lài)注入,但當(dāng)Bean的數(shù)量越來(lái)越多時(shí),XML也會(huì)變得越來(lái)越復(fù)雜,少則上百行,多則上千行,沒(méi)有人愿意維護(hù)一大段XML配置。緊接著Spring2.0很快到來(lái)了,他在XML命名空間上做了一些優(yōu)化,讓配置看起來(lái)盡可能的簡(jiǎn)單,但仍沒(méi)有徹底解決配置上的問(wèn)題,知道Spring3.0的出現(xiàn),我們可以使用Spring提供的java注解取代曾今的XML配置了,似乎我們都忘記了曾今發(fā)生了過(guò)什么,Spring變得前所未有的簡(jiǎn)單。當(dāng)Spring4.0出現(xiàn)后,我們甚至連XML配置文件都不需要了,完全使用java源碼級(jí)別的配置與Spring提供的注解就能快速的開(kāi)發(fā)出Spring應(yīng)用程序。
    盡管Spring已經(jīng)非常優(yōu)秀了,但仍無(wú)法改變Java Web應(yīng)用程序的運(yùn)行模式,也就是說(shuō),我們?nèi)孕枰獙ar包部署到web Server上,才能對(duì)外提供服務(wù)。能否運(yùn)行一個(gè)簡(jiǎn)單的main()方法就能啟動(dòng)web Server呢?Spring Boot滿(mǎn)足了我們的需求,我們下面就來(lái)全面的了解一下Spring Boot的所有特性。

    Spring Boot 特性

  • 可創(chuàng)建獨(dú)立的Spring應(yīng)用程序
    使用SpringBoot所創(chuàng)建的應(yīng)用程序都是一個(gè)個(gè)獨(dú)立的jar包,而并非war包,即使是war應(yīng)用也是jar包,這方面似乎帶有一點(diǎn)顛覆性的味道。我們可以直接運(yùn)行帶有@SpringBootApplication注解的main()方法就能運(yùn)行一個(gè)Spring應(yīng)用程序,實(shí)際上是在SpringBoot應(yīng)用程序內(nèi)部嵌入了一個(gè)WebServer而已。但這些并不能說(shuō)明SpringBoot就不能以war包的形式部署到Web Server中了,我們同樣可以使用SpringBoot來(lái)開(kāi)發(fā)傳統(tǒng)的javaweb應(yīng)用。
  • 提供嵌入式的Web Server(無(wú)需部署war包)
    我們不在將war包部署到WebServer中,而是啟動(dòng)SpringBoot應(yīng)用程序后,會(huì)在默認(rèn)端口8080下啟動(dòng)一個(gè)嵌入式的tomcat,也可以在SpringBoot提供的application.properties配置文件中配置具體的端口號(hào)。當(dāng)然,除了Tomcat,SpringBoot還提供了Jetty、Undertow等嵌入式的Web Server,我們可以根據(jù)實(shí)際情況,自行在Maven配置文件中添加相關(guān)的Web Server的插件,SpringBoot插件體系十分的廣泛。
  • 無(wú)任何代碼生成技術(shù)也無(wú)任何XML配置
    在某些開(kāi)源框架中,會(huì)使用字節(jié)碼生成技術(shù)(例如CGLib、Javassist、ASM等),在程序運(yùn)行時(shí)動(dòng)態(tài)的生成class文件并將其加載到JVM中,我們稱(chēng)這種行為叫做“代碼生成技術(shù)”,在Spring Boot中沒(méi)有使用任何代碼生成技術(shù)。此外,SpringBoot不像傳統(tǒng)Spring應(yīng)用那樣配置大量的XML文件,除了使用一個(gè)application.properties配置文件,SpringBoot再無(wú)其他配置文件了,而且所有插件相關(guān)的配置也在這個(gè)配置文件中。
  • 自動(dòng)化配置
    Spring Boot的配置都在application.properties文件中,但并不意味著在SpringBoot應(yīng)用就必須包含該文件。實(shí)際上,配置文件中包含了大量的配置項(xiàng),而許多配置項(xiàng)都有默認(rèn)值,很多配置項(xiàng)我們其實(shí)都不用去修改,使用其默認(rèn)值就行,這類(lèi)行為叫做“自動(dòng)化配置”,我們只需要使用SpringBoot提供的相關(guān)注解就能啟動(dòng)具體特性。這一特性實(shí)際上是由SpringBoot提供的一些列@ConditionalOnXxx條件注解來(lái)實(shí)現(xiàn)的,而底層使用了Spring4.0的Condition接口。
  • 提供一些列生產(chǎn)級(jí)特性
    SpringBoot是為了生產(chǎn)級(jí)Spring應(yīng)用而生的,提供了大量的生產(chǎn)級(jí)特性,例如核心指標(biāo)、健康檢查、外部配置等,這類(lèi)技術(shù)對(duì)微服務(wù)架構(gòu)想當(dāng)有價(jià)值。例如,核心指標(biāo)的是我們可以隨時(shí)給SpringBoot發(fā)送/metrics請(qǐng)求,隨后可以獲取一個(gè)JSON數(shù)據(jù),包括內(nèi)存、Java堆、類(lèi)加載、處理器、線(xiàn)程池等信息。我們還能再Java命令行上直接運(yùn)行SpringBoot應(yīng)用,并帶上外部配置參數(shù),這些參數(shù)將覆蓋已有的默認(rèn)值配置參數(shù)。甚至我們還能通過(guò)發(fā)送一個(gè)URL請(qǐng)求去關(guān)閉SpringBoot應(yīng)用,在自動(dòng)化技術(shù)中會(huì)有一定的幫助。
  • 提供開(kāi)箱即用的Spring插件
    SpringBoot提供了大量“開(kāi)箱即用”的插件,我們只需要添加一段Maven依賴(lài)配置即可開(kāi)啟使用。這些插件在SpringBoot的世界里有一個(gè)優(yōu)雅的名字,叫做Starter。每個(gè)Starter可能都會(huì)有自己的配置項(xiàng),而這些配置項(xiàng)都是可以在application.properties文件中統(tǒng)一配置。
    SpringBoot是一個(gè)典型的“核心+插件”的系統(tǒng)架構(gòu),核心包含Spring最核心的功能,其他更多的功能都是通過(guò)插件的方式來(lái)擴(kuò)展。那么SpringBoot擁有哪些插件呢?
  • SpringBoot相關(guān)插件

    SpringBoot官方提供了大量插件,涉及面非常的廣,包括Web、SQL、NoSQL、安全、驗(yàn)證、緩存、消息隊(duì)列、分布式事物、模板引擎、工作流等,還提供了Cloud、Social、Ops方面的支持。
    此外,SpringBoot對(duì)某項(xiàng)技術(shù)提供了多種選型,比如:

    • SQL API ------- JDBC、JPA、JOOQ等;
    • 關(guān)系數(shù)據(jù)庫(kù)------MySQL、PostgreSQL等;
    • 內(nèi)存數(shù)據(jù)庫(kù)------H2、HSQLDB、Derby等;
    • NoSQL數(shù)據(jù)庫(kù)-----Redis、MongoDB、Cassandra等;
    • 消息隊(duì)列-------RabbitMQ、Bitronix等;
    • 模板引擎------Velocity、Freemarker、Mustache等。

    官方還提供了一個(gè)名為“Spring Initialzr”的在線(xiàn)代碼生成器,我們只需選擇自己想要的插件,就能一件下載對(duì)應(yīng)的代碼框架。就連IDEA也支持了Spring Initialzr。
    SpringBoot擁有非常強(qiáng)大的插件體系,如此之多的插件,讓我們?cè)陂_(kāi)發(fā)應(yīng)用程序的時(shí)候如虎添翼,我們可以?xún)?yōu)先從這個(gè)“插件庫(kù)”中選擇插件,如果有的插件不夠用或者不合適,我們還可以實(shí)現(xiàn)自己想要的插件。
    SpringBoot所提供的功能強(qiáng)大且實(shí)用,但SpringBoot并非適合開(kāi)發(fā)所有應(yīng)用場(chǎng)景。那么那些場(chǎng)景比較適合使用SpringBoot呢?

    SpringBoot的應(yīng)用場(chǎng)景

  • 傳統(tǒng)的WebMVC架構(gòu)
    傳統(tǒng)的WebMVC架構(gòu)比較適合用SpringBoot來(lái)開(kāi)發(fā),View層可以使用JSP或者模板引擎(例如Velocity),從View層發(fā)送請(qǐng)求到Spring的controller,通過(guò)操作數(shù)據(jù)庫(kù)并將獲取的數(shù)據(jù)封裝進(jìn)Model,最后將Model返回到View中。總之,SpringMVA能夠做到的,SpringBoot都能做到,因?yàn)镾pringBoot在更高層對(duì)SpringMVC進(jìn)行了封裝。
  • 前后端分離架構(gòu)
    在前后端分離的架構(gòu)中,后端可基于SpringBoot開(kāi)發(fā)REST API,前端通過(guò)REST API來(lái)獲取JSON數(shù)據(jù),從而進(jìn)行視圖渲染,生成最終的HTML界面。實(shí)際上,移動(dòng)端H5應(yīng)用我們也可以采用類(lèi)似的方式來(lái)實(shí)現(xiàn)。在前后端分離的架構(gòu)中,可能會(huì)遇到“跨域問(wèn)題”,SpringBoot對(duì)跨域問(wèn)題也做了非常好的支持。
  • 微服務(wù)架構(gòu)
    微服務(wù)架構(gòu)要求我們對(duì)產(chǎn)品功能進(jìn)行細(xì)粒度劃分,且每個(gè)微服務(wù)之間需要使用輕量級(jí)技術(shù)進(jìn)行通信,因此每個(gè)微服務(wù)需要對(duì)外提供輕量級(jí)API接口(例如REST API),使用SpringBoot發(fā)布REST API是最方便的。此外,SpringBoot還擁有一系列的生產(chǎn)級(jí)特性,他與微服務(wù)是天作之和。
  • 現(xiàn)在大家應(yīng)該了解到SpringBoot是什么以及他可以做什么了,下面通過(guò)幾個(gè)簡(jiǎn)單的示例來(lái)展示一下SpringBoot的基本用法,目標(biāo)是讓大家快速上手。

    如何使用SpringBoot框架

    不僅對(duì)SpringBoot框架,其實(shí)學(xué)習(xí)任何框架的第一步都是搭建開(kāi)發(fā)環(huán)境,然后嘗試寫(xiě)一個(gè)“helloworld”應(yīng)用程序并試圖讓他跑起來(lái),最后才去探索他的若干特性。我們現(xiàn)在就來(lái)搭建一個(gè)SpringBoot開(kāi)發(fā)框架,充分體驗(yàn)一下SpringBoot給我們開(kāi)發(fā)帶來(lái)的快樂(lè)。

    搭建SpringBoot開(kāi)發(fā)框架

    • 使用IDEA創(chuàng)建一個(gè)Maven項(xiàng)目
      我們?cè)買(mǎi)DEA中創(chuàng)建一個(gè)Project,名稱(chēng)為msa-hello,對(duì)應(yīng)的Maven坐標(biāo)為:
    • groupId:demo.msa
    • artifactId:msa-hello
    • version:1.0.0

    當(dāng)然,大家也可以按照自己的喜好來(lái)命名,不一定非要與文中相似。
    在pom文件中添加如下的SpringBoot的Maven配置:

    <parent><groupId>org.springbootframwork.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.3.3.RELEASE</version> </parent>

    通過(guò)上面的配置,我們的應(yīng)用才算是SpringBoot應(yīng)用,該配置會(huì)繼承大量的SpringBoot插件,但這些插件都未啟用,我們下面要做的就是啟用對(duì)我們有用的插件。例如,啟用Web插件,需要繼續(xù)添加如下的配置:

    <dependencies><dependency><groupId>org.springframwork.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> </dependencies>

    以上配置只需要配置groupId和artifactId即可,因?yàn)樵诟竝om中已經(jīng)配置了version了。
    SpringBoot提供了相應(yīng)的Maven插件,只需要通過(guò)下面的配置即可使用:

    <build><plugins><groupId>org.springframwork.boot</gourpId><artifactId>spring-boot-maven-plugin</artifactId></plugins> </build>

    需要說(shuō)明的是spring-boot-maven-plugin并不是SpringBoot應(yīng)用必須要求的,但仍建議大家使用,下面會(huì)講到他的具體意義。
    現(xiàn)在SpringBoot開(kāi)發(fā)框架已經(jīng)搭建完畢,下面要做的就是開(kāi)發(fā)一些簡(jiǎn)單的功能來(lái)進(jìn)一步體驗(yàn)它,我們就以“helloworld”應(yīng)用程序來(lái)講解。

    開(kāi)發(fā)一個(gè)簡(jiǎn)單的SpringBoot應(yīng)用程序

    由于msa-hello應(yīng)用的groupId是demo.msa,因此我們需要定義一個(gè)名稱(chēng)也為demo.msa的包名,所有的代碼在該包下。

    import org.spingframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class HelloApplication{public static void main(String[] args){SpringApplication.run(HellowApplication.class,args);} }

    以上HelloApplication類(lèi)并不是一個(gè)普通的類(lèi),他必須擁有一下兩個(gè)特點(diǎn):

  • 類(lèi)名上有@SpringBootApplication注解,表示他是一個(gè)SpringBoot應(yīng)用。
  • 類(lèi)名中包含一個(gè)main()方法,且通過(guò)SpringApplication類(lèi)的run()方法運(yùn)行該類(lèi)。
  • 下面我們做一個(gè)簡(jiǎn)單的REST API,例如GET:/hello,表示API的請(qǐng)求方法是GET請(qǐng)求,請(qǐng)求路徑是/hello,該API只返回一個(gè)”hello“字符串。
    直接在HellowApplication類(lèi)中添加如下代碼:

    import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;@RestController @SpringBootApplication public class HelloApplication{@RequestMapping(method=RequestMethod.GET,path="/hello")public String hello(){return "hello";} }

    為了對(duì)外發(fā)布REST API,我們只需要做三件事情:

  • 在類(lèi)名上添加@RestController注解,表示它具備發(fā)布REST API的能力,還能將每個(gè)REST API的返回值自動(dòng)序列化為JSON格式。
  • 在類(lèi)中加一個(gè)hello()方法,并通過(guò)@RequestMethod注解定義REST API的請(qǐng)求信息,包括請(qǐng)求類(lèi)型與請(qǐng)求路徑。
  • 完成hello()方法,目前是返回一個(gè)簡(jiǎn)單的“hello”字符串,實(shí)際上返回任何java對(duì)象,且返回的java對(duì)象被JSON序列化后返回客戶(hù)端。
  • 當(dāng)然,如果我們只考慮“單一職責(zé)原則”,那么應(yīng)該將@RestController與@RequestMapping注解以及所涉及的代碼從HelloApplication類(lèi)中抽取出來(lái),將其放入單獨(dú)的Controller類(lèi)中,就像下面這樣:

    import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class HelloController{@RequestMapping(method=RequestMapping.GET,path="/hello")public String hello(){return "hello";} }

    對(duì)于GET請(qǐng)求,我們可以簡(jiǎn)化@RequestMapping的寫(xiě)法,可以直接寫(xiě)成下面你的方法:

    @RequestMapping(“/hello”)

    因?yàn)槟J(rèn)的REST API就是GET請(qǐng)求。
    現(xiàn)在一個(gè)簡(jiǎn)單的SpringBoot應(yīng)用程序就開(kāi)發(fā)完畢了。
    我們可以通過(guò)Maven編譯并打包,在target目錄下將看到一個(gè)msa-hello-1.0.0.jar的文件,使用解壓工具打開(kāi)jar文件,將看到如下圖的目錄結(jié)構(gòu)。

    • demo
    • lib
    • META-INF
    • org

    demo目錄下存放項(xiàng)目的class文件,lib目錄下存放項(xiàng)目運(yùn)行所依賴(lài)的jar包,META-INF目錄下存放Maven構(gòu)件所生成的相關(guān)文件,其中包含一個(gè)MANIFEST.MF文件,該文件內(nèi)容如下:

    Manifest-Version:1.0 Implementation-Title:msa-hello Implementation-Version:1.0.0 Archiver-Version:Plexus Archiver Built-By:huangyong Start-Class:demo.msa.HelloApplication Implementation-Vendor-Id:demo.msa Spring-Boot-Version:1.3.3.RELEASE Created-By:Apache Maven 3.0.5 Build-Jdk:1.8.0_60 Implementation-Vendor:Pivotal Software, Inc. Main-Class:org.springframework.boot.loader.JarLauncher

    注意最后一行的Main-Class,它表示運(yùn)行jar包所需的Main類(lèi),即提供main()方法所在的類(lèi)。可見(jiàn),其并非我們編寫(xiě)的HelloApplication類(lèi),而是SpringBoot提供的JarLauncher類(lèi),該類(lèi)存放在jar包中的org目錄下。
    此外,我們也可以在IDEA中查看該項(xiàng)目jar包的依賴(lài)關(guān)系。

    運(yùn)行SpringBoot應(yīng)用程序

    運(yùn)行SpringBoot應(yīng)用程序非常簡(jiǎn)單,我們可以根據(jù)實(shí)際情況,自由的選擇使用一下三種方法來(lái)運(yùn)行SpringBoot應(yīng)用程序。

  • 在IDEA中直接運(yùn)行
    直接在IDEA中執(zhí)行HelloApplication類(lèi)來(lái)啟動(dòng)SpringBoot應(yīng)用程序。
    該方式有利于程序的debug,在日常開(kāi)發(fā)過(guò)程中優(yōu)先使用這種方式,但debug方式肯定比run方式啟動(dòng)的慢一些。

  • 使用Maven運(yùn)行
    可以使用Maven命令來(lái)運(yùn)行

    mvn spring-boot:run

    以上就用到了spring-boot-maven-plugin插件,我們運(yùn)行的是spring-boot插件的run目標(biāo),此外他還提供了spring-boot:start與spring-boot:stop目標(biāo)。

  • 使用Java命令運(yùn)行
    使用java命令行來(lái)運(yùn)行SpringBoot應(yīng)用程序:

    java -jar msa-hello-1.0.0.jar

    該方式看似不需要spring-boot-maven-plugin插件,但實(shí)際上是需要的。通過(guò)該插件所打的jar包不是一般的jar包,它比一般的jar包體積要大許多,因?yàn)樗\(yùn)行該jar包所需要的其他jar包。

  • 可見(jiàn),SpringBoot還是很容易上手的,只要會(huì)Maven并熟悉Spring的基本用法,就能夠迅速搭建SpringBoot框架。后面的內(nèi)容中還會(huì)繼續(xù)擴(kuò)展此框架,讓他成為一款真正的輕量級(jí)微服務(wù)開(kāi)發(fā)框架。
    除了SpringBoot的基本特性外,還有一些更高級(jí)的特性,尤其是SpringBoot提供的生產(chǎn)級(jí)特性,也對(duì)我們的開(kāi)發(fā)非常的有幫助。

    SpringBoot的生產(chǎn)級(jí)特性

    SpringBoot提供了大量開(kāi)箱即用的插件,其中有一個(gè)名為Actuator的插件提供了大量生產(chǎn)級(jí)特性,可以通過(guò)Maven配置使用該插件。

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>

    添加Maven依賴(lài)后,我們重啟SpringBoot應(yīng)用程序,就能開(kāi)啟端點(diǎn)生產(chǎn)級(jí)特性了。

    端點(diǎn)

    SpringBoot的Actuator插件提供了一系列的http請(qǐng)求,我們可以發(fā)送相應(yīng)的請(qǐng)求,來(lái)獲取SpringBoot應(yīng)用程序的相關(guān)信息。這些HTTP請(qǐng)求都是GET類(lèi)型的,而且不帶任何參數(shù),他們就是所謂的“端點(diǎn)”,也許他的英文“Endpoint”更容易理解,SpringBoot的Actuator插件默認(rèn)提供了一下端點(diǎn)。

    端點(diǎn)描述
    autoconfig獲取自動(dòng)配置信息
    beans獲取Spring Bean基本信息
    configprops獲取配置項(xiàng)信息
    dump獲取當(dāng)前線(xiàn)程基本信息
    env獲取環(huán)境變量信息
    health獲取健康檢查信息
    info獲取應(yīng)用基本信息
    metrics獲取性能指標(biāo)信息
    mappings獲取請(qǐng)求映射信息
    trace獲取請(qǐng)求調(diào)用信息

    例如我們?cè)贋g覽器地址發(fā)送/metrics請(qǐng)求時(shí),會(huì)看到性能指標(biāo)的返回結(jié)果。
    默認(rèn)情況下,以上的端點(diǎn)都是開(kāi)啟的,我們隨時(shí)可以訪問(wèn),根據(jù)實(shí)際情況我們可以自由控制哪些端點(diǎn)需要啟用,哪些端點(diǎn)需要停用。也可以全部停用、啟用,這些端點(diǎn)的控制在application.properties文件中配置。一下給一些實(shí)際的操作。

  • 關(guān)閉metrics端點(diǎn)

    endpoints.metrics.enabled=false

    在瀏覽器訪問(wèn)/metircs的時(shí)候,看到的將是“Whitelable Error Page"的錯(cuò)誤頁(yè)面,對(duì)應(yīng)的HTTP狀態(tài)碼為404(not found)。

  • 關(guān)閉所有端點(diǎn),僅開(kāi)啟metrics端點(diǎn)

    endpoints.enable=false
    endpoints.metrics.enabled=true

    現(xiàn)在只有metrics端點(diǎn)是啟用的,訪問(wèn)其他的端點(diǎn)會(huì)報(bào)錯(cuò)。

  • 修改metrics端點(diǎn)的名稱(chēng)

    endpotins.metrics.id=performance

    這樣我們就可以通過(guò)/performance請(qǐng)求來(lái)訪問(wèn)以前的mertics端點(diǎn)了,此時(shí)繼續(xù)發(fā)送/mertics,會(huì)看到報(bào)錯(cuò)信息。

  • 修改metrics端點(diǎn)的請(qǐng)求路勁

    endpoints.mertics.path=/endpotins/mertics

    通過(guò)以上的配置,我們需要在發(fā)送/endpoints/mertics請(qǐng)求后才能訪問(wèn)metrics端點(diǎn)。

  • 如果我們想知道SpringBoot為我們提供了那些端點(diǎn),應(yīng)該如何做呢?
    SpringBoot的HATEOAS插件為我們提供了幫助,實(shí)際上,HATEOAS是一個(gè)超媒體(Hypermedia)技術(shù),他也是REST應(yīng)用程序架構(gòu)的一種約束。通過(guò)他可以匯總端點(diǎn)信息,包括各個(gè)端點(diǎn)的名稱(chēng)與鏈接。開(kāi)啟HATEOAS插件,只需要添加一下依賴(lài):

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-hateoas</artifactId> </dependency>

    此后,我們將擁有actuator端點(diǎn),當(dāng)我們發(fā)送/actuator請(qǐng)求后,將看到所有的端點(diǎn)及其鏈接方式。

    健康檢查

    在SpringBoot所提供的端點(diǎn)中,有一個(gè)名為health的端點(diǎn),用于查看當(dāng)前以你該用的運(yùn)行狀態(tài),即應(yīng)用的健康狀況。檢查應(yīng)用的健康狀況,我們簡(jiǎn)稱(chēng)為“健康檢查”。
    當(dāng)我們?cè)跒g覽器發(fā)送/health請(qǐng)求后,將看到應(yīng)用的健康情況,可以看到應(yīng)用的運(yùn)行狀態(tài)、磁盤(pán)空間情況等信息。
    實(shí)際上,SpringBoot包含了許多內(nèi)置的健康檢查功能,每項(xiàng)功能對(duì)應(yīng)具體的健康檢查指標(biāo)類(lèi)(HealthIndicator),如下所示:

    名稱(chēng)描述
    ApplicationHealthIndicator檢查應(yīng)用運(yùn)行狀態(tài)(對(duì)應(yīng)status部分)
    DiskSpaceHealthIndicator查看磁盤(pán)空間(對(duì)應(yīng)diskSpace部分)
    DataSourceHealthIndicator檢查數(shù)據(jù)庫(kù)連接
    MailHealthIndicator檢查郵箱服務(wù)器
    JmsHealthIndicator檢查JMS代理
    RedisHealthIndicator檢查Redis服務(wù)器
    MongoHealthIndicator檢查MongoDB數(shù)據(jù)庫(kù)
    CassandraHealthIndicator檢查Cassandra數(shù)據(jù)庫(kù)
    RabbitHealthIndicator檢查Rabbit服務(wù)器
    SolrHealthIndicator檢查Solr服務(wù)器
    ElasticsearchHealthIndicator檢查ElasticSearch集群

    我們添加相關(guān)的SpringBoot插件后,即可開(kāi)啟對(duì)應(yīng)的健康檢查功能。默認(rèn)情況下只有ApplicationHealthIndicator與DiskSpaceHealthIndicator是啟用的。我們還可以通過(guò)management.health.defaults.enabled屬性來(lái)控制是否開(kāi)啟健康檢查特性,默認(rèn)為true,表示是開(kāi)啟的。
    雖然SpringBoot提供的健康檢查已經(jīng)很全面了,但如果我們還覺(jué)得不夠用的話(huà),也可以實(shí)現(xiàn)自己的健康檢查,需實(shí)現(xiàn)ort.springframework.boot.actuate.health.HealthIndicator接口,并覆蓋health()方法即可。
    實(shí)際上,我們可以利用健康檢查特性來(lái)開(kāi)發(fā)一個(gè)微服務(wù)系統(tǒng)監(jiān)控平臺(tái),用于獲取每個(gè)微服務(wù)的運(yùn)行狀態(tài)與性能指標(biāo)。當(dāng)然也有現(xiàn)成的解決方案,比如spring-boot-admin,它就是一款基于Spring Boot的開(kāi)源監(jiān)控平臺(tái)。
    spring-boot-admin項(xiàng)目地址:https://github.com/codecentric/spring-boot-admin。

    應(yīng)用基本信息

    除了health端點(diǎn)以外,還有一個(gè)名為info的端點(diǎn),我們可以用它來(lái)獲取SpringBoot應(yīng)用程序的基本信息,比如應(yīng)用程序的名稱(chēng)、描述、版本等。當(dāng)我們發(fā)送/info請(qǐng)求時(shí),卻獲取不到任何數(shù)據(jù),因?yàn)槲覀兡壳斑€沒(méi)有配置任何的應(yīng)用信息。
    應(yīng)用基本信息的相關(guān)配置都是以info為前綴的配置項(xiàng),就像下面這樣:

    info.app.name=Hello
    info.app.description=This is a demo of Spring Boot
    info.app.version=1.0.0

    隨后我們就可以通過(guò)瀏覽器獲取上面的配置信息了

    跨域

    使用SpringBoot開(kāi)發(fā)的REST API是想當(dāng)容易的,一般情況下,REST API是獨(dú)立部署的,如果WebUI也進(jìn)行獨(dú)立部署,那么REST API與WebUI可能在不同的域名部署,從WebUI發(fā)送的AJAX請(qǐng)求去調(diào)用REST API時(shí)就會(huì)遇到“跨域問(wèn)題”,在瀏覽器控制臺(tái)會(huì)報(bào)錯(cuò):“No’Access-Control-Allow-Origin’header is present on the requested resource.”,因?yàn)锳JAX的安全限制,它是不支持跨域的,我們需要通過(guò)技術(shù)手段來(lái)解決這個(gè)問(wèn)題。
    曾今我們可以使用JSONP(JSON with Padding)來(lái)實(shí)現(xiàn)跨域問(wèn)題,簡(jiǎn)單的來(lái)說(shuō)就是客戶(hù)端發(fā)送一個(gè)AJAX請(qǐng)求,并在請(qǐng)求參數(shù)后面添加一個(gè)callback參數(shù),指向一個(gè)JS函數(shù)(成為callback回調(diào)函數(shù))。服務(wù)器返回了一個(gè)JavaScript函數(shù),該函數(shù)將JSON數(shù)據(jù)做了一個(gè)封裝(Padding),就像這樣callback({…});,這樣我們只需要在客戶(hù)端上定義一個(gè)callback回調(diào)函數(shù),就能獲取從服務(wù)器端返回的JSON數(shù)據(jù)了。
    JSONP看似簡(jiǎn)單好用,實(shí)際上它也有非常明顯的限制,只支持GET請(qǐng)求,如果我們需要使用JSON技術(shù)發(fā)送其他請(qǐng)求(比如POST)就不太可能了。當(dāng)然也可以通過(guò)其他手段來(lái)實(shí)現(xiàn),比如iframe,但該方法過(guò)于繁瑣,多年前早已棄用。現(xiàn)在,我們優(yōu)先選擇的是更加輕量級(jí)的CORS(Cross-Origin Resource Sharing)來(lái)實(shí)現(xiàn)跨域問(wèn)題,他目前也加入到了W3C規(guī)范中了,而且當(dāng)前主流瀏覽器都能很好的支持該規(guī)范。
    關(guān)于CORS理論知識(shí)可以參見(jiàn)它的官方網(wǎng)站:http://www.w3.org/TR/cors/。
    SpringBoot很好的支持了CORS,我們只需要添加關(guān)于CORS的端點(diǎn)配置就能隨時(shí)開(kāi)啟該特性,默認(rèn)情況下他是禁用的,通過(guò)以下配置可以使用:

    endpoints.cors.allowed-origins=http://www.com endpoints.cors.allowed-mehtods=GET,POST,PUT,DELETE

    此外,也可以在HelloApplication類(lèi)上加上@CorssOrigin注解來(lái)實(shí)現(xiàn)跨域,就像這樣:

    import org.springframework.web.bind.annotation.CrossOrigin;@SpringBootApplication @RestController @CrossOrigin public class HelloApplication{... }

    在@CrossOrigin注解中也提供了origins、methods等屬性,我們可以自行配置。當(dāng)然,我們也可以使用如下方法配置CORS下相關(guān)屬性。

    import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter{@Overridepublic void addCorsMappings(CorsRegistry registry){registry.addMapping("/**").allowedOrigins("http://www.xxx.com").allowMethods("GET","POST","PUT","DELETE");}}

    實(shí)際上,在Spring4.2以后才開(kāi)始支持CORS。可以閱讀Spring官方博客上的一篇關(guān)于CORS的文章。
    CORS support in Spring Framework :http://spring.io/blog/2015/06/08/cors-support-in-spring-framework。

    外部配置

    我們可以在application.properies配置文件中指定SpringBoot的相關(guān)配置項(xiàng),還可以@…@占位符獲取Maven資源過(guò)濾的相關(guān)屬性,此外還可以通過(guò)外部配置覆蓋SpringBoot配置項(xiàng)的默認(rèn)值,可以先從以下位置獲取:

  • Java命令行參數(shù)。
  • JNDI屬性。
  • JAVA系統(tǒng)屬性。
  • 操作系統(tǒng)環(huán)境變量。
  • jar包外的application.properties配置文件。
  • jar包內(nèi)的application.properites配置文件。
  • @PropertySource注解。
  • SpringApplication.setDefaultProperties默認(rèn)值。
  • 以“java命令行參數(shù)”為例,我們?cè)谶\(yùn)行SpringBoot的jar包時(shí),可以通過(guò)以下方式指定外部配置:

    java -jar xxx.jar --server.port=18080

    通過(guò)上面的–server.port配置,可以將默認(rèn)的8080端口改為18080

    遠(yuǎn)程監(jiān)控

    SpringBoot提供了一個(gè)名為Remote Shell的插件,允許我們可以通過(guò)ssh遠(yuǎn)程鏈接正在運(yùn)行中的SpringBoot應(yīng)用程序,只需要添加以下配置:

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-remote-shell</artifactId> </dependency>

    當(dāng)我們啟動(dòng)SpringBoot應(yīng)用程序的時(shí)候,將在控制臺(tái)看到監(jiān)控相關(guān)的信息。

    微服務(wù)網(wǎng)關(guān)

    在上一章節(jié)中,我們使用SpringBoot開(kāi)發(fā)了一個(gè)簡(jiǎn)單的服務(wù),也討論了前后端不在一個(gè)域名下會(huì)產(chǎn)生的“跨域問(wèn)題”,好在SpringBoot已經(jīng)提供了CORS跨域特性,我們才能在前端自由的調(diào)用后端發(fā)布的服務(wù)。這樣的架構(gòu)看似不錯(cuò),但似乎還有點(diǎn)問(wèn)題,比如,每個(gè)微服務(wù)可能部署在不同的IP與端口上,前端必須知道后端服務(wù)部署的位置,那么能否做到前端無(wú)須知道后端具體服務(wù)的具體細(xì)節(jié),通過(guò)一個(gè)統(tǒng)一的方式去調(diào)用后端服務(wù)呢?其實(shí)我們需要的是一個(gè)“API網(wǎng)關(guān)”,前端所有的請(qǐng)求都會(huì)進(jìn)入該網(wǎng)關(guān),通過(guò)網(wǎng)關(guān)去調(diào)用后端的服務(wù)。
    本章我們使用Node.js搭建一個(gè)統(tǒng)一的網(wǎng)關(guān),我們?cè)谖⒎?wù)架構(gòu)中稱(chēng)其為API Gateway(API 網(wǎng)關(guān))或Service Gateway(服務(wù)網(wǎng)關(guān)),所有從前端發(fā)送的請(qǐng)求都會(huì)到這個(gè)網(wǎng)關(guān)上,Node.js通過(guò)“方向代理”技術(shù)來(lái)調(diào)用后端發(fā)布的服務(wù)。不過(guò)在完成這件事之前,我們有必要搞清楚Node.js究竟是什么。

    Node.js是什么

    從字面上的意思來(lái)看,Node.js更像是一款JavaScript框架,其實(shí)不完全是這樣的,我們千萬(wàn)不要被她的名字所誤導(dǎo)。
    Node.js官網(wǎng)

    在首頁(yè)上我們就可以清楚的看到對(duì)Node.js的詮釋:

    Node.js是一個(gè)基于ChromeV8引擎的JavaScript運(yùn)行環(huán)境,它使用了一個(gè)“事件驅(qū)動(dòng)”且“異步非租塞I/O”的模型使其輕量且高效,Node.js的包管理器NPM是全球最大的開(kāi)源庫(kù)生態(tài)系統(tǒng)。

    針對(duì)Node.js的定義,我們想稍微補(bǔ)充說(shuō)明一下:

  • Node.js是一個(gè)運(yùn)行環(huán)境,并非JavaScripte類(lèi)庫(kù)或者框架
  • Node.js是基于ChormeV8引擎開(kāi)發(fā)的,改引擎是業(yè)界公認(rèn)的高性能JavaScript引擎(沒(méi)有之一)。
  • Node.js提供了“事件驅(qū)動(dòng)”模型,可以將當(dāng)前事件加入到事件隊(duì)列中去輪詢(xún)。
  • Node.js提供了“異步非阻塞I/O”模型,它比傳統(tǒng)的“同步阻塞式I/O”模型具備更高的吞吐率。
  • Node.js的NPM與java的Maven異曲同工,但生態(tài)圈似乎更加龐大(官方號(hào)稱(chēng))。
  • 此外,Node.js非常的小巧,但模塊體系卻非常的龐大,我們可以在NPM官網(wǎng)上尋找對(duì)自己有幫助的模塊。
    對(duì)于“高并發(fā)”我們一般采用的“多線(xiàn)程”技術(shù)來(lái)解決,也就是說(shuō),創(chuàng)建大量的線(xiàn)程來(lái)處理更多并發(fā)的請(qǐng)求。而創(chuàng)建管理線(xiàn)程是一件非常消耗內(nèi)存的事情,且在CPU核心數(shù)不多的情況下,會(huì)出現(xiàn)大量的上下文切換現(xiàn)象,因?yàn)镃PU需要不斷的從一堆線(xiàn)程中選擇一個(gè)線(xiàn)程來(lái)處理它的內(nèi)部的指令。由此說(shuō)來(lái),該方案在內(nèi)存較大且CPU強(qiáng)的環(huán)境下還是想當(dāng)不錯(cuò)的選擇,Java提供的就是這樣的解決方案。
    Node.js另辟蹊徑,采用“單線(xiàn)程”技術(shù)來(lái)解決高并發(fā)的問(wèn)題,在內(nèi)部提供一個(gè)“事件驅(qū)動(dòng)”與“異步非阻塞I/O”模型,讓我們可以在硬件資源相對(duì)普通的條件下也能扛得住高并發(fā)的壓力。
    解決高并發(fā),實(shí)際上就是解決I/O問(wèn)題。我們通常所說(shuō)的I/O問(wèn)題其實(shí)包括兩方面,即“網(wǎng)絡(luò)I/O”與“磁盤(pán)I/O”。java的I/O模型是同步的,直到后來(lái)NIO(非阻塞I/O)技術(shù)的出現(xiàn),Java編程模型才有了異步的特性,而Node.js與生俱來(lái)就有異步的特性,而且利用JavaScript的回調(diào)函數(shù)可以使異步編程變得格外的簡(jiǎn)單。
    可見(jiàn)Node.js只是利用了JavaScript語(yǔ)言的特性去完成服務(wù)端的事情,甚至有人提到,幾乎所有的服務(wù)端開(kāi)發(fā)語(yǔ)言(例如java、PHP、Python等)可以做的,它都能做到,而且做得更好。雖然我們對(duì)這一點(diǎn)實(shí)際上是保持懷疑態(tài)度的,但不得不否認(rèn)Node.js確實(shí)是一項(xiàng)顛覆性的技術(shù)。它讓JavaScript自AJAX以后迎來(lái)了第二次高潮,而且這次高潮明顯蓋過(guò)上一次。

    Node.js快速入門(mén)

    下面我們通過(guò)一段簡(jiǎn)單的Node.js代碼來(lái)快速的了解他的基本用法

    var fs = require('fs');fs.readFile('/etc/hosts',function(err,data){if(err)throw err;console.log(data.toString()); })

    首先我們通過(guò)Node.js內(nèi)置的require()函數(shù)來(lái)引入FS模塊(它是Node.js內(nèi)置的模塊),同時(shí)創(chuàng)建了一個(gè)名為fs的變量。隨后我們通過(guò)調(diào)用fs變量的readFile()函數(shù)來(lái)讀取/etc/hosts文件,但此函數(shù)并沒(méi)有返回值。實(shí)際上,Node.js會(huì)創(chuàng)建一個(gè)讀取文件的事件,并立刻將該事件加入到事件隊(duì)列中,當(dāng)前線(xiàn)程并不會(huì)阻塞在這里。理論上后續(xù)不管有多少線(xiàn)程都會(huì)進(jìn)來(lái)并產(chǎn)生一系列事件,這些事件會(huì)加入到同樣的事件隊(duì)列中,他們會(huì)在事件隊(duì)列中進(jìn)行循環(huán),一旦某個(gè)事件被觸發(fā)(比如文件讀取成功),則會(huì)執(zhí)行后面定義的回調(diào)函數(shù)(比如readFile()函數(shù)的第二個(gè)參數(shù),回調(diào)函數(shù)一般是最后一個(gè)參數(shù))。
    可見(jiàn)Node.js完全利用了JavaScript的編程范式,采用回調(diào)函數(shù)來(lái)實(shí)現(xiàn)異步行為。但也有很多人不太習(xí)慣這種異步的API,往往跳同步API會(huì)讓人覺(jué)得更加的自然,畢竟調(diào)用某函數(shù)拿到某返回值,這是非常容易理解的。
    實(shí)際上,Node.js也提供了同步API。針對(duì)以上文件讀取的示例,我們用同步API來(lái)實(shí)現(xiàn),代碼如下:

    var fs = require('fs');var data = fs.readFile('ect/hosts'); console.log(data.toString());

    我們調(diào)用JS變量的readFileSync()函數(shù)可以通過(guò)同步的方式來(lái)獲取文件的內(nèi)容,此時(shí)不在出現(xiàn)回到函數(shù),而是在調(diào)用API后直接拿到函數(shù)的返回值。
    Node.js上手過(guò)程其實(shí)非常容易,代碼風(fēng)格也非常的優(yōu)雅。既然這么好的武器,我們應(yīng)該在那些場(chǎng)景下考慮使用它呢?

    Node.js的應(yīng)用場(chǎng)景

    Node.js是針對(duì)“實(shí)時(shí)Web”應(yīng)用程序而開(kāi)發(fā)的,非常適合為了實(shí)時(shí)性較強(qiáng)且并發(fā)量較大的應(yīng)用場(chǎng)景。

  • I/O密集型Web應(yīng)用
    我們?nèi)粘?吹降膽?yīng)用一般分為兩大類(lèi),即“CPU密集型”和“I/O密集型”。前者對(duì)CPU要求較高,需要一個(gè)強(qiáng)大的計(jì)算過(guò)程,需要較多的CPU核心來(lái)完成具體的業(yè)務(wù),比如股票交易系統(tǒng)、數(shù)據(jù)分析系統(tǒng)等。后者更加偏重于對(duì)I/O的要求,常會(huì)有頻繁的網(wǎng)絡(luò)傳輸或者磁盤(pán)存儲(chǔ)等現(xiàn)象,比如高并發(fā)網(wǎng)站、實(shí)時(shí)Web系統(tǒng)等。
    由于Node.js采用的是單線(xiàn)程模型,肯定不適合做CPU密集型的應(yīng)用,否則CPU資源將被長(zhǎng)期消耗,從而影響整個(gè)系統(tǒng)的吞吐率。因此開(kāi)發(fā)I/O密集型才是Node.js的強(qiáng)項(xiàng),它充分利用了事件驅(qū)動(dòng)與異步非阻塞技術(shù),能支持大量的并發(fā)鏈接,從而提高整個(gè)系統(tǒng)的吞吐率。
    尤其在Web方面,Node.js有著強(qiáng)大的優(yōu)勢(shì),他內(nèi)置了一個(gè)HTTP服務(wù)器(實(shí)際上是一個(gè)HTTP模塊),性能與穩(wěn)定性方面都與流行的Nginx不分伯仲(業(yè)界有人做過(guò)這方面的測(cè)試)。此外,基于Node.js的模塊體系非常強(qiáng)大,其中不乏優(yōu)秀的Web框架,Express就是這樣的框架,它將基于Node.js的Web應(yīng)用開(kāi)發(fā)過(guò)程變得非常的簡(jiǎn)單與高效,下文我們也會(huì)了解到他。
    Express官網(wǎng)
  • Web聊天室
    Node.js是為實(shí)時(shí)性而生的,Web聊天室正符合這類(lèi)實(shí)時(shí)性的要求。使用Node.js集成Socket.IO可以輕松的搭建一個(gè)Web Socket服務(wù)器,此外,Socket.IO也提供了客戶(hù)端JS類(lèi)庫(kù),我們可以在短時(shí)間內(nèi)開(kāi)發(fā)一套Web聊天室。
    Socket.IO官網(wǎng)
    當(dāng)我們打開(kāi)瀏覽器,進(jìn)入Web聊天室時(shí),客戶(hù)端會(huì)主動(dòng)與服務(wù)器建立一個(gè)WebSocket鏈接,而且這是一個(gè)長(zhǎng)鏈接。在同一時(shí)段內(nèi),可能會(huì)有很多人進(jìn)入聊天室,此時(shí)會(huì)有多個(gè)客戶(hù)端與服務(wù)器建立WebSocket鏈接。當(dāng)某人輸入一段文字,然后單擊“發(fā)送”按鈕,此時(shí)會(huì)將消息通過(guò)WebSocket協(xié)議發(fā)送服務(wù)端。當(dāng)服務(wù)端收到消息后,立即通過(guò)WebSocket廣播的方式,將消息推送到所有已經(jīng)建立鏈接的客戶(hù)端。
    在服務(wù)器端處理客戶(hù)端發(fā)送過(guò)來(lái)的大量消息時(shí),會(huì)利用Node.js的異步特性,當(dāng)收到消息后,將產(chǎn)生一個(gè)事件并將其加入到隊(duì)列中,同時(shí)立刻返回客戶(hù)端,當(dāng)事件觸發(fā)后,立即將消息廣播到所有的客戶(hù)端。
  • 命令行工具
    使用Node.js可以輕松開(kāi)發(fā)命令行工具,我么可以寫(xiě)一段Node.js程序,通過(guò)NPM提供的命令將其安裝到操作系統(tǒng)中,隨時(shí)可以在命令控制行控制臺(tái)上輸入該命令來(lái)運(yùn)行Node.js程序。
  • HTTP代理服務(wù)器
    Node.js可以通過(guò)異步的方式處理大量的并發(fā)請(qǐng)求,他可以作為服務(wù)端應(yīng)用程序的代理,起到充當(dāng)HTTP代理服務(wù)器的作用,類(lèi)似于Nginx、Apache等。
    在Node.js的NPM中同樣存在這樣的HTTP代理模塊,我們只需要將其引入進(jìn)來(lái),并使用該模塊提供的API,就能快速的搭建一個(gè)HTTP代理服務(wù)器。
  • 如何使用Node.js

    Node.js屬于上手非常快的技術(shù),學(xué)習(xí)他沒(méi)有太高的難度,只要我們會(huì)寫(xiě)JavaScript,并且了解一些基本的編程思想就能快速使用了。但他所設(shè)計(jì)的面還是挺廣的,如果深入掌握他,還是需要一個(gè)過(guò)程的。
    為了讓大家快速的學(xué)會(huì)使用Node.js,我們不放從安裝開(kāi)始。

    安裝Node.js

    官方網(wǎng)站提供了不同操作系統(tǒng)下的Node.js安裝包,我們只需要根據(jù)自己的需求,下載對(duì)應(yīng)的安裝包即可。
    當(dāng)然,如果大家使用的是Mac操作系統(tǒng),還可以使用更加簡(jiǎn)單的方法安裝Node.js。我們可以安裝一個(gè)名為Homebrew的軟件用它來(lái)暗轉(zhuǎn)Node.js程序,當(dāng)然其他流行的命令行程序也能通過(guò)它來(lái)安裝。
    Hombrew官網(wǎng):http://brew.sh/。

    使用Node.js開(kāi)發(fā)WEB應(yīng)用

    第一步,新建一個(gè)app.js的Node.js程序,代碼如下:

    var http = require('http'); var PORT = 1234; var app = http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/html'});res.wirte('<h1>Hellow</h1>');res.end(); )} app.listen(PORT,function(){console.log('Server is run at %d',PORT); })

    首先我們通過(guò)Node.js內(nèi)置的require()函數(shù)引入HTTP模塊,該模塊是開(kāi)發(fā)WEB應(yīng)用的核心模塊。隨后我們調(diào)用http對(duì)象的createServer函數(shù)來(lái)創(chuàng)建app對(duì)象。在該函數(shù)的參數(shù)中有一個(gè)function(req,res){…}回調(diào)函數(shù),包含req請(qǐng)求參數(shù)與res響應(yīng)參數(shù)。該函數(shù)用于處理所有的HTTP請(qǐng)求,我們只需要寫(xiě)入具體的數(shù)據(jù)到res響應(yīng)對(duì)象中即可。最后需要調(diào)用app對(duì)象的listen()函數(shù),并在響應(yīng)的端口上啟動(dòng)Web應(yīng)用,該函數(shù)同樣也有一個(gè)回調(diào)函數(shù),當(dāng)Web應(yīng)用啟動(dòng)后被調(diào)用。
    需要注意的是,res對(duì)象的weiteHead()函數(shù)用于寫(xiě)入響應(yīng)頭(Response Head),write()函數(shù)用于寫(xiě)入響應(yīng)體(Response Body),最后一定要使用end()函數(shù)用于發(fā)送數(shù)據(jù)寫(xiě)入完畢事件這樣才能結(jié)束整個(gè)HTTP請(qǐng)求與響應(yīng)過(guò)程。
    第二步,可以通過(guò)命令來(lái)執(zhí)行Node.js程序:

    $ node app.js

    隨后我們可以在瀏覽其中輸入一下地址來(lái)訪問(wèn)Node.js的WEB應(yīng)用。

    http://localhost:1234/

    瀏覽器中將輸出“hello”字樣的HEML頁(yè)面,至此一個(gè)簡(jiǎn)單的WEB應(yīng)用就開(kāi)發(fā)完畢了。
    在Node.js應(yīng)用運(yùn)行過(guò)程中,如果我們修改了源文件,此時(shí)是無(wú)法生效的。因?yàn)镹ode.js為了確保高性能,在啟動(dòng)服務(wù)的時(shí)候就將代碼加載到了內(nèi)存中運(yùn)行。修改了源文件對(duì)實(shí)際運(yùn)行的效果沒(méi)有任何影響,就算被刪除了也是一樣的。該特性確保了運(yùn)行階段的效率,但影響了開(kāi)發(fā)階段的效率。

    微服務(wù)注冊(cè)與發(fā)現(xiàn)

    Service Registry(服務(wù)注冊(cè)表)是整個(gè)“微服務(wù)架構(gòu)”中的“核心”,他不僅提供了Service Registry(服務(wù)注冊(cè))功能,同時(shí)也為Service Discovery(服務(wù)發(fā)現(xiàn))功能提供了支持。服務(wù)注冊(cè)很好理解,就是在服務(wù)啟動(dòng)后,將服務(wù)的相關(guān)配置信息(例如IP與端口)注冊(cè)到服務(wù)注冊(cè)表中。當(dāng)客戶(hù)調(diào)用這些服務(wù)時(shí),將通過(guò)Service Gateway(服務(wù)網(wǎng)關(guān))從服務(wù)注冊(cè)表中獲取這些服務(wù)配置,然后通過(guò)反向代理的方式去調(diào)用具體的服務(wù)接口,從服務(wù)注冊(cè)表中獲取服務(wù)配置的過(guò)程就是服務(wù)發(fā)現(xiàn)。
    此外,服務(wù)注冊(cè)表會(huì)定期檢測(cè)已經(jīng)注冊(cè)的服務(wù),若發(fā)現(xiàn)某些服務(wù)已經(jīng)無(wú)法訪問(wèn)了,則將從服務(wù)注冊(cè)表中移除掉,這個(gè)定期檢查的過(guò)程被稱(chēng)為“心跳檢測(cè)”。由此可見(jiàn),服務(wù)注冊(cè)表對(duì)“分布式數(shù)據(jù)一致性”的要求是想當(dāng)高的,換句話(huà)說(shuō),服務(wù)注冊(cè)表中的服務(wù)配置一旦變更了,通知機(jī)制必須做到高性能,且服務(wù)注冊(cè)表本身還需要具備高可用。
    ZooKeeper是服務(wù)注冊(cè)表的最佳解決方案之一。

    ZooKeeper是什么

    ZooKeeper字面上的意思就是動(dòng)物園管理員的意思,ZooKeeper在軟件世界里就是一名管理員,它被用來(lái)提供分布式環(huán)境下的協(xié)調(diào)服務(wù)。Yahoo公司使用java語(yǔ)言開(kāi)發(fā)了ZooKeeper,它是Hadoop項(xiàng)目中的子項(xiàng)目,基于Google的Chubby的開(kāi)源實(shí)現(xiàn),在Hadoop、HBase、Kafka等技術(shù)中充當(dāng)了核心組件的角色。他的設(shè)計(jì)目標(biāo)就是將哪些復(fù)雜且容易出錯(cuò)的分布式一致性服務(wù)加一封裝,構(gòu)成一個(gè)高效且可靠的服務(wù),并為用戶(hù)提供了一系列簡(jiǎn)單易用的接口。
    ZooKeeper是一個(gè)經(jīng)典的分布式數(shù)據(jù)一致性解決方案,分布式應(yīng)用程序可以基于它實(shí)現(xiàn)數(shù)據(jù)發(fā)布與訂閱、負(fù)載均衡、命名服務(wù)、分布式協(xié)調(diào)服務(wù)與通知、集群管理、領(lǐng)導(dǎo)選舉、分布式鎖、分布式隊(duì)列等功能。
    ZooKeeper一般是以集群的方式對(duì)外提供服務(wù),一個(gè)集群包括多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)對(duì)應(yīng)一臺(tái)ZooKeeper服務(wù)器,所有的節(jié)點(diǎn)共同對(duì)外提供服務(wù)。整個(gè)集群環(huán)境對(duì)分布式數(shù)據(jù)一致性提供了全面的支持,具體包括以下五大特性:

  • 順序性
    從同一個(gè)客戶(hù)端發(fā)送的請(qǐng)求,最終將會(huì)嚴(yán)格按照其發(fā)送順序進(jìn)入到ZooKeeper中。可見(jiàn),這就像一個(gè)隊(duì)列,擁有“先進(jìn)先出”的特性,也就確保了請(qǐng)求的順序性。
  • 原子性
    所有請(qǐng)求的響應(yīng)結(jié)果在整個(gè)分布式集群環(huán)境中具備原子性,也就是說(shuō),要么在整個(gè)集群中所有機(jī)器都成功的處理了某一個(gè)請(qǐng)求,要么就都沒(méi)有處理,絕對(duì)不會(huì)出現(xiàn)集群中部分機(jī)器處理了某一個(gè)請(qǐng)求,而另一部分機(jī)器卻沒(méi)有處理的情況,這方面的要求與事務(wù)的原子性是一樣的。
  • 單一性
    無(wú)論客戶(hù)端鏈接到哪個(gè)ZooKeeper服務(wù)器,每個(gè)客戶(hù)端所看到的的服務(wù)端數(shù)據(jù)模型都是一致的,不可能出現(xiàn)兩種不同的數(shù)據(jù)狀態(tài)。實(shí)際上每臺(tái)ZooKeeper服務(wù)器之間會(huì)進(jìn)行數(shù)據(jù)同步的,而這個(gè)同步過(guò)程是相當(dāng)高效的。
  • 可靠性
    一旦服務(wù)數(shù)據(jù)狀態(tài)發(fā)生了變化,就會(huì)立刻存儲(chǔ)起來(lái),除非此時(shí)又有另一個(gè)請(qǐng)求對(duì)其進(jìn)行了變更,否則數(shù)據(jù)一定是可靠的。
  • 實(shí)時(shí)性
    當(dāng)某個(gè)請(qǐng)求被成功處理了之后,客戶(hù)端能夠立即獲取服務(wù)端的最新數(shù)據(jù)狀態(tài),整個(gè)過(guò)程具備實(shí)時(shí)性。
  • ZooKeeper樹(shù)狀模型

    ZooKeeper內(nèi)部擁有一個(gè)樹(shù)狀內(nèi)存模型,類(lèi)似于文件系統(tǒng),有若干個(gè)目錄,每個(gè)目錄中也有若干個(gè)文件,只是在ZooKeeper中將這些目錄和文件稱(chēng)為ZNode,每個(gè)ZNode有對(duì)應(yīng)的路徑及其包含的數(shù)據(jù)。ZNode可由ZooKeeper客戶(hù)端來(lái)創(chuàng)建,當(dāng)客戶(hù)端與服務(wù)器端建立鏈接后,服務(wù)端將為客戶(hù)端創(chuàng)建一個(gè)Session(會(huì)話(huà)),客戶(hù)端對(duì)ZNode的所有操作均在這個(gè)會(huì)話(huà)中來(lái)完成。
    ZNode實(shí)際上有四類(lèi)節(jié)點(diǎn),如下表:

    ZNode類(lèi)型說(shuō)明
    Persistent(持久節(jié)點(diǎn))當(dāng)會(huì)話(huà)結(jié)束后,該節(jié)點(diǎn)不會(huì)被刪除
    Persistent Sequence(持久順序結(jié)點(diǎn))當(dāng)會(huì)話(huà)結(jié)束后,該節(jié)點(diǎn)不會(huì)被刪除,且結(jié)點(diǎn)名中帶自增數(shù)后綴
    Ephemeral(臨時(shí)結(jié)點(diǎn))當(dāng)會(huì)話(huà)結(jié)束后,該節(jié)點(diǎn)會(huì)被刪除
    Ephemeral Sequence(臨時(shí)順序結(jié)點(diǎn))當(dāng)會(huì)話(huà)結(jié)束后,該節(jié)點(diǎn)會(huì)被刪除,且結(jié)點(diǎn)名中帶自增數(shù)后綴

    需要注意的是,持久性結(jié)點(diǎn)才能有子節(jié)點(diǎn),這是ZooKeeper所限制的。
    ZooKeeper使用這個(gè)基于內(nèi)存的樹(shù)狀模型來(lái)存儲(chǔ)分布式數(shù)據(jù),正式因?yàn)閷⑺械臄?shù)據(jù)都存放在內(nèi)存中,所以才能實(shí)現(xiàn)高性能的目的,提高吞吐率。此外,這個(gè)樹(shù)狀模型還有助于集群環(huán)境下的數(shù)據(jù)同步,下面就來(lái)了解一下ZooKeeper的集群結(jié)構(gòu)。

    ZooKeeper的集群結(jié)構(gòu)

    ZooKeeper并非采用經(jīng)典的分布式一致性協(xié)議Paxos,而是參考了Paxos協(xié)議,設(shè)計(jì)了一款更加輕量級(jí)的協(xié)議,名為Zab(ZooKeeper Atomic Broadcast原子廣播協(xié)議)。Zab協(xié)議分為兩個(gè)階段:Leader Election(領(lǐng)導(dǎo)選舉)與Atomic Broadcast(原子廣播)。當(dāng)ZooKeeper集群?jiǎn)?dòng)時(shí),將會(huì)選舉出一臺(tái)節(jié)點(diǎn)為L(zhǎng)eader(領(lǐng)導(dǎo)),而其他節(jié)點(diǎn)均為Follower(追隨者)。當(dāng)Leader節(jié)點(diǎn)出現(xiàn)故障時(shí),會(huì)自動(dòng)選舉出行的Leader節(jié)點(diǎn)并讓所有節(jié)點(diǎn)恢復(fù)到一個(gè)正常的狀態(tài),這就是領(lǐng)導(dǎo)選舉階段。當(dāng)領(lǐng)導(dǎo)選舉階段完畢后,將進(jìn)入原子廣播階段,該階段同步Leader節(jié)點(diǎn)與各個(gè)Follower節(jié)點(diǎn)之間的數(shù)據(jù),確保Leader與Follower節(jié)點(diǎn)具有相同的狀態(tài)。所有的寫(xiě)操作都會(huì)發(fā)送到Leader節(jié)點(diǎn),并通過(guò)廣播的方式將數(shù)據(jù)同步到其他Follower節(jié)點(diǎn)。
    一個(gè)ZooKeeper集群通常由一組節(jié)點(diǎn)組成,在一般情況下,3~5個(gè)節(jié)點(diǎn)就可以組成一個(gè)可用的ZooKeeper集群,理論上,節(jié)點(diǎn)越多越好。
    組成ZooKeeper集群的每個(gè)結(jié)點(diǎn)都會(huì)在內(nèi)存中維護(hù)當(dāng)前服務(wù)器的狀態(tài),并且每個(gè)結(jié)點(diǎn)之間都會(huì)保持相互的通信,目的就是告訴其他節(jié)點(diǎn)“自己還活著”。需要注意的是,只要集群中存在超過(guò)“半數(shù)以上”的結(jié)點(diǎn)可以正常工作,那么整個(gè)集群就能夠正常的對(duì)外提供服務(wù)。因此,我們一般提供奇數(shù)個(gè)節(jié)點(diǎn),比較節(jié)省資源。此外,ZooKeeper客戶(hù)端可以選擇集群中任意一個(gè)節(jié)點(diǎn)來(lái)建立鏈接,而一旦客戶(hù)端與某個(gè)節(jié)點(diǎn)之間斷開(kāi)鏈接,客戶(hù)端會(huì)自動(dòng)鏈接到集群中的其他節(jié)點(diǎn)。

    如何使用ZooKeeper

    由于ZooKeeper是由Java語(yǔ)言開(kāi)發(fā)的,因此在使用它之前,需要安裝JDK運(yùn)行環(huán)境,在生產(chǎn)環(huán)境下官方建議JDK需要1.6版本或以上,并建議使用Oracle發(fā)布的JDK,而并非開(kāi)源社區(qū)的OpenJDK。雖然在Linux、Windows、Mac OSX操作系統(tǒng)上都可以使用ZooKeeper,不過(guò)官方建議大家使用Linux操作系統(tǒng)作為生產(chǎn)環(huán)境。

    運(yùn)行ZooKeeper

    我們需要從ZooKeeper官方網(wǎng)站下載它的安裝包,該安裝包實(shí)際上就是一個(gè)壓縮包,加壓后可以使用。建議在生產(chǎn)環(huán)境下使用stable版本。

  • 第一步:修改ZooKeeper配置文件
    ZooKeeper提供了一份名為:zoo_sample.cfg的示例配置文件,我們必須在次基礎(chǔ)上進(jìn)行調(diào)整,才能成功運(yùn)行ZooKeeper。
    我們只需要復(fù)制conf目錄下的zoo_sample.cfg文件,并將其命名為zoo.cfg即可,就像下面這樣:

    cp conf/zoo_sample.cfg conf/zoo.cfg

    該配置文件中帶有大量的注釋,便于我們更加清晰的了解到這些配置是做什么的,將這些注釋全部去掉之后,可以看到下面的5個(gè)重要配置:

    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/tmp/zookeeper
    clientPort=2181

    下面我們對(duì)這些配置項(xiàng)進(jìn)行解釋:

    • tickTime:稱(chēng)之為“滴答時(shí)間”,用于配置ZooKeeper中最小時(shí)間單元長(zhǎng)度,實(shí)際上ZooKeeper中很多運(yùn)行時(shí)間的時(shí)間間隔都是使用tickTime的倍數(shù)來(lái)表示的。例如,ZooKeeper中會(huì)話(huà)的最小超時(shí)時(shí)間默認(rèn)兩倍的tickTime。該配置的默認(rèn)值是3000,單位為毫秒。
    • initLimit:用于配置Leader節(jié)點(diǎn)等待Follower節(jié)點(diǎn)啟動(dòng)并完成數(shù)據(jù)同步的時(shí)間。Follower節(jié)點(diǎn)在啟動(dòng)過(guò)程中會(huì)與leader節(jié)點(diǎn)建立鏈接并完成數(shù)據(jù)同步,從而確定自己對(duì)外提供服務(wù)的起始狀態(tài),Leader節(jié)點(diǎn)允許Follower節(jié)點(diǎn)在initLimit時(shí)間內(nèi)完成這個(gè)工作。該配置的默認(rèn)值為10,即10*tickTime。通常情況下,我們不太注意這個(gè)配置項(xiàng),這個(gè)使用默認(rèn)值即可。如果隨著ZooKeeper集群管理的數(shù)量不斷增大,Follower節(jié)點(diǎn)在啟動(dòng)的時(shí)候,從Leader節(jié)點(diǎn)上進(jìn)行數(shù)據(jù)同步的時(shí)間也會(huì)相應(yīng)變長(zhǎng),于是無(wú)法在短時(shí)間內(nèi)完成數(shù)據(jù)同步,在這種情況下,有必要適當(dāng)調(diào)大這個(gè)參數(shù)。
    • syncLimit:用于配置Leader節(jié)點(diǎn)和Follower節(jié)點(diǎn)之間進(jìn)行“心跳檢測(cè)”的最大延時(shí)時(shí)間。在ZooKeeper集群運(yùn)行過(guò)程中。Leader節(jié)點(diǎn)會(huì)與所有的Follower節(jié)點(diǎn)進(jìn)行心跳檢測(cè)來(lái)確定該節(jié)點(diǎn)是否存活。如果Leader在syncLimit時(shí)間內(nèi)無(wú)法獲取Follower節(jié)點(diǎn)的心跳檢測(cè)響應(yīng),那么Leader節(jié)點(diǎn)就會(huì)認(rèn)為該Follower節(jié)點(diǎn)已經(jīng)脫離了與自己的同步,該配置的默認(rèn)項(xiàng)為5,即5*tickTime。
    • dataDir:用于配置當(dāng)前ZooKeeper服務(wù)器存儲(chǔ)快照的文件的目錄,不建議將其指定到/tmp目錄下,因?yàn)樵撃夸浀奈募赡鼙蛔詣?dòng)刪除。在ZooKeeper集群環(huán)境中。將生成一個(gè)名為myid的文件,該文件用于存放ZooKeeper集群節(jié)點(diǎn)的ID,我們需要保證在整個(gè)集群環(huán)境中,整個(gè)ID是唯一的。
    • clientPort:用于配置當(dāng)前ZooKeeper服務(wù)器對(duì)外暴露的端口,客戶(hù)端會(huì)通過(guò)該端口在ZooKeeper服務(wù)器上建立鏈接并創(chuàng)建會(huì)話(huà),一般設(shè)置為2181。每臺(tái)ZooKeeper服務(wù)器都可以配置任何可用的端口,實(shí)際上,集群中的所有服務(wù)器也無(wú)需使用相同的clientPort。
  • 第二步:啟動(dòng)ZooKeeper服務(wù)器
    啟動(dòng)ZooKeeper服務(wù)器非常的簡(jiǎn)單,只需要執(zhí)行ZooKeeper提供的腳本即可。

    bin/zkServer.sh start

    執(zhí)行以上腳本,將在后臺(tái)啟動(dòng)ZooKeeper服務(wù)器。此外,還可以使用start-foreground參數(shù),用于在前臺(tái)啟動(dòng)ZooKeeper服務(wù)器,此時(shí)我們將看到ZooKeeper的控制臺(tái),隨后可以在控制臺(tái)中看到許多重要的日志。
    實(shí)際上,我們可以直接執(zhí)行zkServer.sh腳本來(lái)獲取相關(guān)的使用幫助。

    bin/zkServer.sh

  • 第三步,驗(yàn)證ZooKeeper服務(wù)是否有效
    可以執(zhí)行如下腳本來(lái)獲取ZooKeeper的服務(wù)狀態(tài):

    bin/skServer.sh status

  • 使用ZooKeeper搭建集群環(huán)境

    我們以三個(gè)節(jié)點(diǎn)為例,搭建一個(gè)ZooKeeper集群環(huán)境。通過(guò)客戶(hù)端鏈接任意一個(gè)節(jié)點(diǎn),隨后可做一些數(shù)據(jù)變更,并觀察節(jié)點(diǎn)之間是否會(huì)進(jìn)行數(shù)據(jù)同步。
    節(jié)點(diǎn)可以分布在不同的機(jī)器上,當(dāng)然也可以在本地搭建一個(gè)集群環(huán)境,只是需要使用不用的端口,以防止端口被占用而導(dǎo)致沖突。像這類(lèi)在本地搭建的集群環(huán)境,并非真正意義上的“集群模式”,稱(chēng)為“偽集群模式”,其本質(zhì)還是集群模模式,只不過(guò)在單機(jī)下單件而已。
    為了搭建方便,下面我們?cè)诒镜卮罱ㄒ粋€(gè)為集群模式的ZooKeeper環(huán)境。

  • 第一步:修改ZooKeeper配置文件
    我們以第一個(gè)節(jié)點(diǎn)為例,配置如下:

    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/tmp/zookeeper1
    clientPort=2181
    server.1=127.0.0.0:2888:3888
    server.2=127.0.0.0:2889:3889
    server.3=127.0.0.0:2890:3890

    首先,我們指定了dataDir配置,表示ZooKeeper數(shù)據(jù)目錄所存放的地方,需要注意的是,請(qǐng)不要在生產(chǎn)環(huán)境下使用/tmp目錄。
    隨后,我們添加了一組server配置,表示集群中所包含的三個(gè)節(jié)點(diǎn),需要注意的是,server配置需要滿(mǎn)足一定的格式:

    server.<id>=<ip>:<port1>:<port2>

    下面我們對(duì)以上格式進(jìn)行詳細(xì)解釋:

    • id:表示節(jié)點(diǎn)編號(hào),表示該節(jié)點(diǎn)在集群中的唯一編號(hào),取值范圍是1~255之間的整數(shù)。需要注意的是,我們必須在dataDir目錄下創(chuàng)建一個(gè)名為myid的文件,其內(nèi)容為該節(jié)點(diǎn)的編號(hào)。例如,針對(duì)第一個(gè)節(jié)點(diǎn)而言,我們需要?jiǎng)?chuàng)建一個(gè)/tmp/zookeeper1/myid文件,該文件內(nèi)容為1,其他節(jié)點(diǎn)也需要同樣的操作。
    • ip:表示該節(jié)點(diǎn)所在的IP地址,本地為127.0.0.0或localhost
    • port1:表示Leader節(jié)點(diǎn)與Follower節(jié)點(diǎn)進(jìn)心跳檢測(cè)與數(shù)據(jù)同步時(shí)所使用的端口。
    • port2:表示進(jìn)行領(lǐng)導(dǎo)選舉過(guò)程中,用于投票通訊的端口。

    需要主要的是,在真正的集群環(huán)境中,clientPort,Port1,Port2可以配置的完全一樣,因?yàn)榧褐械拿總€(gè)節(jié)點(diǎn)都分布在不同的機(jī)器上,每個(gè)機(jī)器都擁有自己的IP地址,端口也不會(huì)被其他幾點(diǎn)占用。
    參照上面的做法,對(duì)其他兩個(gè)結(jié)點(diǎn)也做同樣的配置后,一個(gè)“偽集群”環(huán)境就搭建完畢了,它擁有“真集群”的所有特性。需要注意的是,對(duì)于“偽集群”環(huán)境而言,在每個(gè)ZooKeeper節(jié)點(diǎn)中,zoo.cfg配置文件中的dataDir與clientPort需要保持不同,對(duì)于“真集群”而言,dataDir、clientPort以及Port1和Port2都可以相同。
    所有的結(jié)點(diǎn)都配置完畢了之后,我們即可以啟動(dòng)ZooKeeper集群。

  • 第二步:啟動(dòng)ZooKeeper集群
    與單機(jī)模式啟動(dòng)的方法相同,只需要一次啟動(dòng)所有的ZooKeeper節(jié)點(diǎn)即可啟動(dòng)整個(gè)集群。我們可以一個(gè)個(gè)手動(dòng)去啟動(dòng),當(dāng)然,也可以寫(xiě)一個(gè)腳本去一次性啟動(dòng)。

  • 第三步:檢驗(yàn)ZooKeeper集群環(huán)境是否有效
    同樣可以通過(guò)zkServer.sh腳本與telnet命令來(lái)查看每個(gè)節(jié)點(diǎn)的狀態(tài),此時(shí)會(huì)看到“Mode:leader”或者“Mode:Follower”的信息,表明該節(jié)點(diǎn)是Leader還是Follower。
    ZooKeeper提供了一系列的腳本程序,他們?nèi)看娣旁赽in目錄下,例如:

    • zkServer.sh用于啟動(dòng)ZooKeeper服務(wù)器。
    • zkCli.sh用于鏈接ZooKeeper服務(wù)器的命令行客戶(hù)端。
    • zkCleanup.sh用于清理ZooKeeper的歷史數(shù)據(jù),包括事務(wù)日志文件與快照數(shù)據(jù)文件。
    • zkEnv.sh用于設(shè)置ZooKeeper的環(huán)境變量。

    我們可以使用zkCli.sh腳本輕松鏈接ZooKeeper服務(wù)器,實(shí)際上它就是一個(gè)命令行客戶(hù)端。下面我們來(lái)學(xué)習(xí)如何使用zkCli.sh鏈接ZooKeeper服務(wù)器,并使用ZooKeeper提供的客戶(hù)端命令來(lái)完成一系列的操作。

  • 使用命令行客戶(hù)端鏈接ZooKeeper

    當(dāng)ZooKeepe服務(wù)器正常啟動(dòng)后,我們可以使用ZooKeeper自帶的zkCli.sh腳本,作為命令行客戶(hù)端來(lái)鏈接ZooKeeper。使用方法非常的簡(jiǎn)單,若鏈接的是本地的ZooKeeper,則只需要執(zhí)行一下腳本即可:

    bin/zkCli.sh

    若想在本地鏈接遠(yuǎn)程的ZooKeeper,則在zkCli.sh腳本中添加-server選項(xiàng)即可,例如:

    bin/zkCli.sh -server <ip>:<port>

    當(dāng)通過(guò)命令行成功鏈接ZooKeeper后,我們就可以輸入相關(guān)的命令來(lái)操作ZooKeeper了。有一個(gè)小技巧,當(dāng)輸入help命令(或者其他非法命令)后,將輸出ZooKeeper相關(guān)客戶(hù)端命令的幫助。

    使用java客戶(hù)端鏈接ZooKeeper

    ZooKeeper官方提供了Java客戶(hù)端的API,首先我們可以通過(guò)添加如下的maven依賴(lài)來(lái)獲取ZooKeeper客戶(hù)端jar包:

    <dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.8</version> </dependency>

    隨后我們寫(xiě)一段簡(jiǎn)單的代碼,用于鏈接ZooKeeper,后面我們將基于此代碼,針對(duì)ZooKeeper客戶(hù)端的常用操作逐一進(jìn)行探索。代碼如下:

    import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper;import java.util.concurrent.CountDownLatch;public class ZooKeeperDemo{private static final String CONNECTION_STRING="127.0.0.1:2181";private static final int SESSION_TIMEOUT=5000;private static CountDownLatch latch = new CountDownLatch(1);public static void mian(String[] args)throws Exception{//鏈接ZooKeeperZooKeeper zk = new ZooKeeper(CONNECTION_STRING,SESSION_TIMEOUT,new Watcher(){@Overridepublic void process(WatchedEvent event){if(event.getState() == Event.KeeperState.SyncConnected){latch.countDown();}}})latch.await();//獲取ZooKeeper客戶(hù)端對(duì)象System.out.println(zk); } }

    我們需要?jiǎng)?chuàng)建一個(gè)ZooKeeper對(duì)象(對(duì)象名為zk),他的本質(zhì)是對(duì)ZooKeeper會(huì)話(huà)的封裝,后續(xù)的所有操作都在該會(huì)話(huà)對(duì)象上完成。
    創(chuàng)建zk對(duì)象需要以下三個(gè)參數(shù):
    ZooKeeper(String connectString,int sessionTimeout,Watcher watcher);

    • connectString:表示鏈接的字符串,需要傳入鏈接ZooKeeper的ip與port,格式為ip:port。當(dāng)鏈接ZooKeeper集群時(shí),可同時(shí)添加集群中多個(gè)節(jié)點(diǎn)并用逗號(hào)分隔,格式為:ip1:port1,ip2:port2。。。
    • sessionTimeout:表示會(huì)話(huà)的超時(shí)時(shí)間,以毫秒為單位。在一個(gè)會(huì)話(huà)期內(nèi),ZooKeeper客戶(hù)端與服務(wù)器之間通過(guò)“心跳檢測(cè)”來(lái)維持會(huì)話(huà)的有效性,也就是說(shuō),一旦在sessionTimeout時(shí)間內(nèi)沒(méi)有進(jìn)行有效的心跳檢測(cè),會(huì)話(huà)將會(huì)失效。
    • watcher:表示監(jiān)視器接口,我們需要實(shí)現(xiàn)該接口的process()回調(diào)方法,并監(jiān)視SyncConnected事件,在java中正是用匿名內(nèi)部類(lèi)的方式來(lái)實(shí)現(xiàn)異步回調(diào)過(guò)程的。

    由于建立ZooKeeper會(huì)話(huà)的過(guò)程是異步的,也就是說(shuō),當(dāng)構(gòu)造完成zk對(duì)象之后,線(xiàn)程將繼續(xù)執(zhí)行后續(xù)的代碼,但此時(shí)會(huì)話(huà)可能尚未建立完畢。因此,我們需要使用CountDownLatch工具,當(dāng)創(chuàng)建zk對(duì)象完畢后,立即調(diào)用latch.await()方法(關(guān)閉閥門(mén)),當(dāng)使用線(xiàn)程處于等待狀態(tài),等待SyncConnected事件到來(lái)時(shí),在執(zhí)行l(wèi)atch.countDown()方法(打開(kāi)閥門(mén)),此時(shí)會(huì)話(huà)已經(jīng)創(chuàng)建完畢,接下來(lái)當(dāng)前線(xiàn)程就可以繼續(xù)執(zhí)行后續(xù)的代碼了。
    現(xiàn)在zk對(duì)象已經(jīng)創(chuàng)建完畢,已經(jīng)成功鏈接ZooKeeper服務(wù)器,下面所有的操作將會(huì)在該會(huì)話(huà)中進(jìn)行,我們只需要調(diào)用zk對(duì)象的相關(guān)API即可。

    使用Node.js客戶(hù)端鏈接ZooKeeper

    我們?cè)贜PM官網(wǎng)上,如果輸入“Zookeeper”關(guān)鍵字,將會(huì)看到大量的ZooKeeper客戶(hù)端,業(yè)界評(píng)價(jià)比較好的是node-zookeeper-client,他的API命名習(xí)慣于java的非常類(lèi)似,下面我們就對(duì)其基本用法做出簡(jiǎn)單介紹。
    首先我們通過(guò)NPM安裝note-zookeeper-client模塊:

    npm install node-zookeeper-client

    隨后我們寫(xiě)一段簡(jiǎn)單的代碼,用于鏈接ZooKeeper,后面我們將基于該代碼,這對(duì)ZooKeeper客戶(hù)端的常用操作逐一進(jìn)行探索。代碼如下:

    var zookeeper = require('node-zookeeper-client');var CONNECTION_STRING = 'localhost:2181'; var OPTIONS = {sessionTimeout:5000 }; var zk = zookeeper.createClient(CONNECTION_STRING,OPTIONS); zk.on('connected',function(){console.log(zk);zk.close(); }); zk.connect();

    我們需要加載node-zookeeper-client模塊,并創(chuàng)建ZooKeeper客戶(hù)端對(duì)象(對(duì)象名為zk),此時(shí)需要傳入“鏈接字符串”與“相關(guān)選項(xiàng)”(包括“會(huì)話(huà)超時(shí)時(shí)間”)。隨后需要監(jiān)聽(tīng)connected事件,并調(diào)用zk.connect()方法來(lái)鏈接ZooKeeper服務(wù)器。當(dāng)觸發(fā)connected事件時(shí),說(shuō)明客戶(hù)端已經(jīng)鏈接成功了ZooKeeper服務(wù)器,在回調(diào)函數(shù)中可以將zk對(duì)象輸出至控制臺(tái),我們此時(shí)可以運(yùn)行一下該程序并觀察控制臺(tái)中zk對(duì)象的輸出情況。
    若zk對(duì)象可以正常輸出,說(shuō)明可以連接ZooKeeper服務(wù)器并建立了正常的會(huì)話(huà),下面所有的操作將在該會(huì)話(huà)中進(jìn)行,我們只需要調(diào)用zk對(duì)象的相關(guān)API即可。與java客戶(hù)端API不同的是,Node.js客戶(hù)端僅提供了異步方式,我們不能通過(guò)同步來(lái)調(diào)用他。

    實(shí)現(xiàn)服務(wù)注冊(cè)組件

    服務(wù)注冊(cè)組件即Service Registry(服務(wù)注冊(cè)表),他內(nèi)部有一個(gè)數(shù)據(jù)結(jié)構(gòu),用于儲(chǔ)存已發(fā)布服務(wù)的信息。

    設(shè)計(jì)服務(wù)注冊(cè)表數(shù)據(jù)結(jié)構(gòu)

    通過(guò)ZooKeeper的學(xué)習(xí),我們可以了解到,他內(nèi)部提供了一個(gè)基于ZNode節(jié)點(diǎn)的樹(shù)狀模型,根節(jié)點(diǎn)為“/”,我們可以在根節(jié)點(diǎn)下方擴(kuò)展任意的子節(jié)點(diǎn),其子節(jié)點(diǎn)也分為四種創(chuàng)建模式,包括:持久節(jié)點(diǎn)、持久順序結(jié)點(diǎn)、臨時(shí)結(jié)點(diǎn)、臨時(shí)順序結(jié)點(diǎn)。
    似乎可以借助ZNode樹(shù)狀模型來(lái)存儲(chǔ)服務(wù)配置,那么應(yīng)該如何設(shè)計(jì)呢?
    我們不妨先定義一個(gè)根節(jié)點(diǎn),由于根節(jié)點(diǎn)下會(huì)有其他子節(jié)點(diǎn),因此根節(jié)點(diǎn)一定是持久節(jié)點(diǎn)的(ZooKeeper只有持久節(jié)點(diǎn)才會(huì)有子節(jié)點(diǎn)),而且根節(jié)點(diǎn)還必須只有一個(gè)。
    我們?cè)俑?jié)點(diǎn)下可以添加若干子節(jié)點(diǎn),可以用服務(wù)名稱(chēng)作為這些節(jié)點(diǎn)的名稱(chēng)。為了便于描述,不妨將此類(lèi)節(jié)點(diǎn)稱(chēng)為“服務(wù)節(jié)點(diǎn)”。此外,為了服務(wù)的高可用性,我們可能發(fā)布多個(gè)相同功能的服務(wù),因此服務(wù)注冊(cè)表中會(huì)存在一些同名的服務(wù),但是服務(wù)節(jié)點(diǎn)又不允許重名的(這是ZNode樹(shù)狀節(jié)點(diǎn)限制的),因此我們要在服務(wù)節(jié)點(diǎn)下在添加一級(jí)節(jié)點(diǎn),所以服務(wù)節(jié)點(diǎn)也是持久的。
    我們?cè)賮?lái)分析下服務(wù)節(jié)點(diǎn)下面的子節(jié)點(diǎn),他們實(shí)際上都對(duì)應(yīng)了某一特定的服務(wù),我們需要將服務(wù)配置存放在該節(jié)點(diǎn)中。簡(jiǎn)單情況下,服務(wù)配置中可以存放服務(wù)的IP與端口號(hào)。為了便于描述,我們不妨將該節(jié)點(diǎn)稱(chēng)之為“地址節(jié)點(diǎn)”。一旦某個(gè)服務(wù)成功注冊(cè)到了ZooKeeper中,ZooKeeper服務(wù)器就會(huì)與該服務(wù)所在的客戶(hù)端進(jìn)行心跳檢測(cè),如果某個(gè)服務(wù)出現(xiàn)了故障,心跳檢測(cè)就會(huì)失效,客戶(hù)端將自動(dòng)斷開(kāi)與服務(wù)端的對(duì)話(huà)。對(duì)應(yīng)的節(jié)點(diǎn)也及時(shí)從ZNode樹(shù)狀模型中刪除,然而如果注冊(cè)了多個(gè)相同的服務(wù),這樣的地址節(jié)點(diǎn)就可能會(huì)有多個(gè),因此地址節(jié)點(diǎn)必須為臨時(shí)且順序的。

    微服務(wù)封裝

    我們使用SpringBoot開(kāi)發(fā)了許多服務(wù),每個(gè)服務(wù)都是以jar包的形式存在,可將這些jar包部署到不同的服務(wù)器上面,并通過(guò)java -jar的命令來(lái)運(yùn)行這些服務(wù)。當(dāng)服務(wù)啟動(dòng)后,會(huì)將自身的配置信息注冊(cè)到“服務(wù)注冊(cè)表”中。所有的客戶(hù)端請(qǐng)求都會(huì)進(jìn)入“服務(wù)網(wǎng)關(guān)”,服務(wù)網(wǎng)關(guān)首先從服務(wù)注冊(cè)表中根據(jù)當(dāng)前請(qǐng)求中的服務(wù)名稱(chēng)來(lái)獲取對(duì)應(yīng)的服務(wù)配置(該過(guò)程成為“服務(wù)發(fā)現(xiàn)”),隨后服務(wù)網(wǎng)關(guān)通過(guò)服務(wù)配置直接調(diào)用已發(fā)布的服務(wù)(該過(guò)程稱(chēng)之為“反向代理”)。
    這樣的架構(gòu)看起來(lái)不錯(cuò),但是我們發(fā)現(xiàn)維護(hù)并管理每個(gè)服務(wù)會(huì)帶來(lái)巨大的成本。比如,我們每次發(fā)布一個(gè)服務(wù)都必須做三件事情:編譯、打包、部署。這三件事看似容易,實(shí)際上卻想當(dāng)?shù)姆爆?#xff0c;尤其是服務(wù)數(shù)量較多的場(chǎng)景,其實(shí)我們想要的只是一個(gè)可運(yùn)行的jar包而已。再比如,在微服務(wù)架構(gòu)中,每個(gè)服務(wù)可能由不同的編程語(yǔ)言來(lái)實(shí)現(xiàn),運(yùn)行服務(wù)還需要不同的環(huán)境,想要讓服務(wù)跑起來(lái),必須先安裝支持他的運(yùn)行環(huán)境,然而安裝環(huán)境往往比運(yùn)行服務(wù)更加的繁瑣。
    面對(duì)這些問(wèn)題,我們需要想辦法將服務(wù)及運(yùn)行環(huán)境加以封裝,并確保將這個(gè)封裝后的產(chǎn)物作為我們的交付物,這個(gè)交付物可隨時(shí)構(gòu)建、裝載、運(yùn)行。Docker正是為此而生的。

    Docker是什么

    Docker在英語(yǔ)里面是“碼頭工人”的意思,大家可以想象,碼頭上有很多的工人,他們正在忙于裝載貨物。首先將貨物放入集裝箱中,然后將集裝箱放在貨船上,貨船將這些集裝箱以及其他的貨物送到指定的目的地。

    Docker簡(jiǎn)介

    在2013年,dotCloud公司發(fā)布了一款名為Docker的開(kāi)源軟件,僅花了一年左右的時(shí)間,Docker幾乎動(dòng)搖了傳統(tǒng)虛擬化技術(shù)的統(tǒng)治地位,越來(lái)越多的公司開(kāi)始逐步使用Docker來(lái)替換現(xiàn)有的虛擬化技術(shù)。正式因?yàn)镈ocker太紅了,就連dotCloud公司也因此而改名為Docker公司了,并給予Docker推出了一系列的相關(guān)生態(tài)產(chǎn)品。比如Docker Engine、Docker Machine、Docker Toolbox、Docker Compose、Docker Hub、Docker Registry、Docker Swarm、Docker Notary、Docker Cloud、Docker Store等。
    Docker源碼地址:https://github.com/docker/docker
    Docker的圖標(biāo)就很生動(dòng)的表達(dá)了他的含義,是一直可愛(ài)的鯨魚(yú),拖著許多的集裝箱,漂浮在云上。在Docker的世界中,這只鯨魚(yú)就是Docker Engine(Docker引擎),上面一個(gè)個(gè)的集裝箱就是Docker容器(Docker Container),Docker引擎可以運(yùn)行在基于Docker的云平臺(tái)(Docker Cloud)上。
    這里有一些概念,做一下解釋:

  • Docker引擎(Docker Engine)
    Docker鏡像可以理解為一個(gè)運(yùn)行在服務(wù)器上的后臺(tái)進(jìn)程,也稱(chēng)之為Docker Daemon,還有很多人稱(chēng)他為Docker服務(wù),因?yàn)樗举|(zhì)就是一個(gè)服務(wù),只要我們啟動(dòng)該服務(wù),我們就能隨時(shí)使用它。我們可以通過(guò)Docker命令客戶(hù)端發(fā)送相關(guān)的Docker命令,并與Docker引擎進(jìn)行通信。
  • Docker客戶(hù)端(Docker Client)
    實(shí)際上Docker客戶(hù)端有兩種,一種是我們剛剛提到的Docker命令行客戶(hù)端,只要我們打開(kāi)命令終端窗口,輸入相關(guān)的Docker 命令,就能操作Docker引擎。另一種Docker客戶(hù)端是REST API客戶(hù)端,我們一般會(huì)在程序中通過(guò)REST API與Docker引擎發(fā)生交互。
  • Docker鏡像(Docker Images)
    Docker鏡像有點(diǎn)類(lèi)似于我們?cè)?jīng)使用的光盤(pán),光盤(pán)上刻錄了數(shù)據(jù),我們只需要將光盤(pán)放入光驅(qū)中,就能讀取光盤(pán)中的數(shù)據(jù)。同樣,我們只需要獲取Docker鏡像(光盤(pán)),就能載入到Docker引擎(光驅(qū))中。并運(yùn)行Docker鏡像中的程序。一般情況下我們首先要將程序打包到Docker鏡像中,隨后才能將Docker鏡像交給其他人使用。
  • Docker容器(Docker Containers)
    當(dāng)我們獲取到Docker鏡像后,可隨時(shí)運(yùn)行Docker鏡像,此時(shí)便會(huì)啟動(dòng)一個(gè)Docker容器,該容器中將運(yùn)行鏡像中封裝的程序。如果我們將Docker鏡像理解為java類(lèi)的話(huà),那么Docker容器就相當(dāng)于java實(shí)例。在同一個(gè)Docker鏡像上理論上是可以運(yùn)行無(wú)數(shù)個(gè)Docker容器的。
  • Docker鏡像注冊(cè)中心(Docker Registry)
    Docker官方提供了一個(gè)叫做DockerHub的鏡像注冊(cè)中心(Docker Registry),用于放公開(kāi)和私有的Docker鏡像倉(cāng)庫(kù)(Docker Responsitory)。也就是說(shuō),我們隨時(shí)可以通過(guò)Docker Hub拉去(下載)Docker鏡像,也可以自由的將自己創(chuàng)建的Docker鏡像推送(上傳)到DockerHub上去。
  • 虛擬機(jī)與Docker對(duì)比

    Docker本質(zhì)上為我們提供了一個(gè)“沙箱(Sandbox)”環(huán)境,它能將應(yīng)用程序進(jìn)行封裝,并提供了與虛擬機(jī)相似的隔離性,但這種隔離性是想當(dāng)輕量的。那么虛擬機(jī)與Docker有什么區(qū)別呢?一起來(lái)討論下。
    當(dāng)我們需要在宿主機(jī)上運(yùn)行一個(gè)虛擬操作系統(tǒng)時(shí),首先需要安裝一個(gè)虛擬機(jī)軟件,常用的虛擬機(jī)軟件比如Oracle VirtualBox或者VMware等,隨后我們可以使用虛擬鏡像文件,在虛擬機(jī)上安裝虛擬操作系統(tǒng)。此時(shí),虛擬軟件需要模擬硬件與網(wǎng)絡(luò)資源,會(huì)占用大量的系統(tǒng)開(kāi)銷(xiāo)。一般情況下,在一臺(tái)普通的服務(wù)器上,最多只能啟動(dòng)十幾個(gè)虛擬機(jī),而且虛擬機(jī)的啟動(dòng)一般要幾分鐘甚至更長(zhǎng)時(shí)間。
    若我們使用Docker虛擬化技術(shù),則只需要在宿主機(jī)上安裝一個(gè)Docker引擎,隨后可以從Docker鏡像倉(cāng)庫(kù)中下載所需的Docker鏡像,并啟動(dòng)相應(yīng)的Docker容器。此時(shí),Docker引擎完全利用宿主機(jī)硬件與網(wǎng)絡(luò)資源,占用的系統(tǒng)開(kāi)銷(xiāo)較少。一般情況下,在一臺(tái)普通的服務(wù)器上,可以啟動(dòng)上千個(gè)Docker容器。

    Docker的特點(diǎn)

    Docker是通過(guò)在底層上封裝了Linux容器技術(shù)(LXC)來(lái)實(shí)現(xiàn)的,換句話(huà)說(shuō),Docker沒(méi)有創(chuàng)造出任何新的技術(shù),僅僅只是“新瓶裝老酒”而已。下面歸納了Docker的四大特點(diǎn):

  • 快速運(yùn)行
    啟動(dòng)虛擬機(jī)需要幾分鐘,而啟動(dòng)Docker只需要幾秒鐘。
  • 節(jié)省資源
    Docker直接運(yùn)行在Docker引擎上,可以直接利用宿主硬件資源,無(wú)需占用過(guò)多的系統(tǒng)資源。
  • 便于交付
    傳統(tǒng)軟件交付物是程序,而在Docker時(shí)代的交付物卻是鏡像,鏡像不僅封裝了程序,還包含運(yùn)行程序所需的相關(guān)環(huán)境。
  • 容易管理
    可以通過(guò)Docker客戶(hù)端直接操作Docker引擎,非常方便的管理Docker鏡像與容器。
  • 微服務(wù)的部署

    我們使用Git管理代碼,使用Maven構(gòu)建項(xiàng)目,使用Docker封裝服務(wù),這些事情都需要手工的方式去一步步的執(zhí)行,能否有快捷的方式呢?Jenkins就是這中快捷方式

    Jenkins簡(jiǎn)介

    在軟件行業(yè)發(fā)展中,持續(xù)集成(Continuous Integration,簡(jiǎn)稱(chēng)CI)是利用一系列的工具、方法與規(guī)則,快速的構(gòu)建代碼,并自動(dòng)的進(jìn)行測(cè)試,從而完成代碼開(kāi)發(fā)的效率和質(zhì)量。Jenkins是一款持續(xù)集成軟件,擁有簡(jiǎn)單的安裝、開(kāi)箱即用、易于管理、易于維護(hù)、插件擴(kuò)展等特性。只需要一個(gè)java的運(yùn)行環(huán)境,就能將Jenkins跑起來(lái),可以通過(guò)圖形化界面為每個(gè)項(xiàng)目創(chuàng)建對(duì)應(yīng)的構(gòu)建任務(wù)(也稱(chēng)為“構(gòu)建作業(yè)”)。Jenkins可以連接我們的代碼倉(cāng)庫(kù)系統(tǒng),從中獲取源碼并自動(dòng)完成構(gòu)建,當(dāng)創(chuàng)建完畢后,還能執(zhí)行一些后續(xù)的任務(wù),比如:生成單元測(cè)試報(bào)告、歸檔程序包、部署程序包到Maven倉(cāng)庫(kù)、記錄文件電子指紋、發(fā)送郵件通知等一系列的操作。為提高持續(xù)集成的執(zhí)行效率,Jenkins支持主從(Master-Slave)運(yùn)行模式,一臺(tái)Master機(jī)器可以控制多臺(tái)Slave機(jī)器,構(gòu)件任務(wù)可并行在多臺(tái)Slave機(jī)器上執(zhí)行。

    總結(jié)

    以上是生活随笔為你收集整理的轻量级微服务架构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    国产精品久久久久影院嫩草 | 亚洲va欧美va天堂v国产综合 | 久久亚洲国产成人精品性色 | 荫蒂被男人添的好舒服爽免费视频 | 免费人成在线观看网站 | 欧洲vodafone精品性 | 熟女俱乐部五十路六十路av | 永久免费观看美女裸体的网站 | 久久久久久久久888 | 无码精品人妻一区二区三区av | 亚洲精品www久久久 | 国产精品久久精品三级 | 久久伊人色av天堂九九小黄鸭 | 国产av一区二区三区最新精品 | 六十路熟妇乱子伦 | 97夜夜澡人人爽人人喊中国片 | 小鲜肉自慰网站xnxx | 狠狠色欧美亚洲狠狠色www | 亚洲国产欧美国产综合一区 | 久久亚洲中文字幕精品一区 | 99久久精品午夜一区二区 | 国产猛烈高潮尖叫视频免费 | 色五月五月丁香亚洲综合网 | 国产亚洲人成在线播放 | 色婷婷av一区二区三区之红樱桃 | 亚洲爆乳精品无码一区二区三区 | a国产一区二区免费入口 | 国产午夜亚洲精品不卡下载 | 99久久亚洲精品无码毛片 | 久久精品国产大片免费观看 | а√资源新版在线天堂 | 国产亚洲人成a在线v网站 | 国产农村乱对白刺激视频 | 国产一区二区三区影院 | √天堂资源地址中文在线 | 国产亚洲欧美在线专区 | 成 人 网 站国产免费观看 | 一区二区三区高清视频一 | 双乳奶水饱满少妇呻吟 | 国产精品自产拍在线观看 | 高潮毛片无遮挡高清免费 | 99久久人妻精品免费一区 | 国产亚洲精品精品国产亚洲综合 | 色综合天天综合狠狠爱 | 国产国产精品人在线视 | 国产av无码专区亚洲awww | 国产一区二区三区四区五区加勒比 | 无码av免费一区二区三区试看 | 欧美日韩视频无码一区二区三 | 天天摸天天透天天添 | 天堂一区人妻无码 | 久久综合网欧美色妞网 | 成年美女黄网站色大免费视频 | 欧美三级a做爰在线观看 | 欧美激情综合亚洲一二区 | 欧美xxxx黑人又粗又长 | 色五月丁香五月综合五月 | 男女作爱免费网站 | 午夜精品一区二区三区的区别 | 亚洲国产精品一区二区美利坚 | 国产精品鲁鲁鲁 | 又大又硬又爽免费视频 | 好屌草这里只有精品 | 国产精品无码久久av | 青青久在线视频免费观看 | 伊在人天堂亚洲香蕉精品区 | 国产亚洲精品久久久久久 | 国产精品免费大片 | 一本色道婷婷久久欧美 | a国产一区二区免费入口 | 日本免费一区二区三区最新 | 无套内谢的新婚少妇国语播放 | 成人免费视频在线观看 | 国产精华av午夜在线观看 | 伊人久久大香线蕉午夜 | 成人一在线视频日韩国产 | 色婷婷av一区二区三区之红樱桃 | 蜜桃视频插满18在线观看 | 亚洲国产精品久久久天堂 | 午夜无码区在线观看 | 粗大的内捧猛烈进出视频 | 狠狠躁日日躁夜夜躁2020 | 黄网在线观看免费网站 | 中文字幕人妻无码一夲道 | 久久精品国产日本波多野结衣 | 亚洲综合伊人久久大杳蕉 | 乱中年女人伦av三区 | 日韩av无码一区二区三区不卡 | 国产精品久久精品三级 | 国产精品亚洲综合色区韩国 | 欧美成人高清在线播放 | 蜜桃臀无码内射一区二区三区 | 国产一精品一av一免费 | 无套内谢老熟女 | 国内丰满熟女出轨videos | 国产尤物精品视频 | 久久久久人妻一区精品色欧美 | 99麻豆久久久国产精品免费 | 亚洲精品国产精品乱码不卡 | 乱码av麻豆丝袜熟女系列 | 小泽玛莉亚一区二区视频在线 | 亚洲成av人影院在线观看 | 狂野欧美激情性xxxx | 精品国精品国产自在久国产87 | 最近的中文字幕在线看视频 | 日韩精品无码免费一区二区三区 | 成人欧美一区二区三区黑人免费 | 18精品久久久无码午夜福利 | 丰满护士巨好爽好大乳 | 婷婷五月综合激情中文字幕 | 麻豆国产97在线 | 欧洲 | 无码人妻少妇伦在线电影 | 国内精品九九久久久精品 | 国产麻豆精品一区二区三区v视界 | 两性色午夜免费视频 | 国产精品久久久 | 男人和女人高潮免费网站 | 色偷偷人人澡人人爽人人模 | 无码精品人妻一区二区三区av | 国产黄在线观看免费观看不卡 | 欧美性黑人极品hd | 亚洲欧美综合区丁香五月小说 | 国产av剧情md精品麻豆 | 欧美亚洲国产一区二区三区 | 天天燥日日燥 | 人妻少妇精品无码专区动漫 | 真人与拘做受免费视频 | 中文字幕色婷婷在线视频 | 成人无码视频免费播放 | 婷婷丁香五月天综合东京热 | 无遮挡啪啪摇乳动态图 | 99久久精品无码一区二区毛片 | 中文无码伦av中文字幕 | 在线欧美精品一区二区三区 | 久久久中文久久久无码 | 男女超爽视频免费播放 | 久久综合九色综合欧美狠狠 | 国产人成高清在线视频99最全资源 | 女人被男人躁得好爽免费视频 | 午夜肉伦伦影院 | 熟女俱乐部五十路六十路av | 99riav国产精品视频 | 少妇无套内谢久久久久 | 亚洲精品一区二区三区四区五区 | 国产偷自视频区视频 | 免费人成网站视频在线观看 | 亚洲性无码av中文字幕 | 国产特级毛片aaaaaaa高清 | 131美女爱做视频 | 在教室伦流澡到高潮hnp视频 | 国产亚洲欧美日韩亚洲中文色 | 国产 精品 自在自线 | 国产亚洲精品精品国产亚洲综合 | 麻豆果冻传媒2021精品传媒一区下载 | 永久免费精品精品永久-夜色 | 国产黄在线观看免费观看不卡 | 国产人妻精品午夜福利免费 | 人妻无码αv中文字幕久久琪琪布 | 欧洲欧美人成视频在线 | 中文无码伦av中文字幕 | 又大又黄又粗又爽的免费视频 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 国产午夜福利亚洲第一 | 特大黑人娇小亚洲女 | 亚洲中文字幕无码中文字在线 | 国内综合精品午夜久久资源 | 国产亚洲精品精品国产亚洲综合 | 久久国产精品偷任你爽任你 | 亚洲精品一区二区三区在线观看 | 久久精品99久久香蕉国产色戒 | а√天堂www在线天堂小说 | 中国女人内谢69xxxx | 亚洲精品美女久久久久久久 | 任你躁国产自任一区二区三区 | 牲欲强的熟妇农村老妇女视频 | 大肉大捧一进一出视频出来呀 | 色狠狠av一区二区三区 | 99久久久国产精品无码免费 | 亚洲国产精品无码一区二区三区 | 蜜桃视频插满18在线观看 | 免费男性肉肉影院 | 啦啦啦www在线观看免费视频 | 性欧美熟妇videofreesex | 色综合久久88色综合天天 | 久久久无码中文字幕久... | 亚洲午夜无码久久 | 日本又色又爽又黄的a片18禁 | 久久亚洲日韩精品一区二区三区 | 欧美精品在线观看 | 精品夜夜澡人妻无码av蜜桃 | 在线亚洲高清揄拍自拍一品区 | 亚洲 a v无 码免 费 成 人 a v | 无码精品人妻一区二区三区av | 97se亚洲精品一区 | 国产xxx69麻豆国语对白 | 国产精品99爱免费视频 | 日韩成人一区二区三区在线观看 | 国产做国产爱免费视频 | 久久久久久久人妻无码中文字幕爆 | 在线播放亚洲第一字幕 | 亚洲精品国产品国语在线观看 | 国产国语老龄妇女a片 | 国产suv精品一区二区五 | 精品国产福利一区二区 | а√天堂www在线天堂小说 | 国产午夜视频在线观看 | 疯狂三人交性欧美 | 无码成人精品区在线观看 | 亚洲 日韩 欧美 成人 在线观看 | 成 人 网 站国产免费观看 | 欧美黑人性暴力猛交喷水 | 亚洲aⅴ无码成人网站国产app | 狂野欧美性猛xxxx乱大交 | 亚洲欧美日韩综合久久久 | 67194成是人免费无码 | 中文字幕 人妻熟女 | 牲欲强的熟妇农村老妇女 | 精品午夜福利在线观看 | 久久久久久av无码免费看大片 | 99久久精品无码一区二区毛片 | 亚洲一区二区三区播放 | 国产片av国语在线观看 | 小泽玛莉亚一区二区视频在线 | 国产一区二区三区精品视频 | 老司机亚洲精品影院无码 | 丰满诱人的人妻3 | 久久久精品欧美一区二区免费 | 国产97在线 | 亚洲 | 国产9 9在线 | 中文 | 亚洲一区av无码专区在线观看 | 天天爽夜夜爽夜夜爽 | 狂野欧美性猛xxxx乱大交 | 国产一区二区三区日韩精品 | 成人女人看片免费视频放人 | 巨爆乳无码视频在线观看 | 呦交小u女精品视频 | 国产午夜亚洲精品不卡 | 亚洲国产精品久久久天堂 | 国产亚洲精品久久久ai换 | 中文字幕无码视频专区 | 亚洲综合伊人久久大杳蕉 | 欧美精品国产综合久久 | 亚洲精品成人av在线 | 无码任你躁久久久久久久 | 亚洲午夜无码久久 | 夜夜躁日日躁狠狠久久av | √天堂资源地址中文在线 | 免费国产黄网站在线观看 | 无码帝国www无码专区色综合 | 97人妻精品一区二区三区 | 无码成人精品区在线观看 | 黑人巨大精品欧美黑寡妇 | 日日躁夜夜躁狠狠躁 | 国产一区二区三区日韩精品 | 久久精品一区二区三区四区 | 亚洲国产欧美在线成人 | 中文字幕中文有码在线 | 无码毛片视频一区二区本码 | 亚洲日本va中文字幕 | 亚洲欧美综合区丁香五月小说 | 99在线 | 亚洲 | 超碰97人人做人人爱少妇 | 久久久久久久久888 | 美女扒开屁股让男人桶 | 爆乳一区二区三区无码 | 国产成人一区二区三区在线观看 | 日日鲁鲁鲁夜夜爽爽狠狠 | 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲日韩av一区二区三区四区 | 久久久精品成人免费观看 | 麻花豆传媒剧国产免费mv在线 | 中文字幕无码日韩欧毛 | 2019午夜福利不卡片在线 | 少妇人妻av毛片在线看 | 一二三四社区在线中文视频 | 无码av最新清无码专区吞精 | 久久午夜无码鲁丝片秋霞 | 人人爽人人澡人人高潮 | 亚洲七七久久桃花影院 | 又紧又大又爽精品一区二区 | 国内精品一区二区三区不卡 | 18精品久久久无码午夜福利 | 久久人人爽人人爽人人片av高清 | 久久视频在线观看精品 | 国产精品美女久久久久av爽李琼 | 国产福利视频一区二区 | 亚洲精品国产a久久久久久 | 少妇激情av一区二区 | 国产口爆吞精在线视频 | 国内丰满熟女出轨videos | 秋霞成人午夜鲁丝一区二区三区 | 国产偷国产偷精品高清尤物 | 初尝人妻少妇中文字幕 | 国产精品久久久久7777 | 免费国产黄网站在线观看 | 久久熟妇人妻午夜寂寞影院 | 国产av一区二区三区最新精品 | 免费播放一区二区三区 | 骚片av蜜桃精品一区 | 国产成人久久精品流白浆 | 精品一区二区三区无码免费视频 | 青草视频在线播放 | aⅴ亚洲 日韩 色 图网站 播放 | 在教室伦流澡到高潮hnp视频 | 国内揄拍国内精品少妇国语 | 国产高清av在线播放 | 亚洲va中文字幕无码久久不卡 | 女人被爽到呻吟gif动态图视看 | 国产亚洲视频中文字幕97精品 | 久久久久免费看成人影片 | 51国偷自产一区二区三区 | 18精品久久久无码午夜福利 | 国产亚洲精品久久久ai换 | 亚洲国产精品久久人人爱 | 亚洲色无码一区二区三区 | 国产精品va在线观看无码 | 图片区 小说区 区 亚洲五月 | 人妻中文无码久热丝袜 | 国精产品一品二品国精品69xx | 女人色极品影院 | 成人无码视频在线观看网站 | 人人妻人人藻人人爽欧美一区 | 丰满人妻翻云覆雨呻吟视频 | 中文字幕精品av一区二区五区 | 国产 精品 自在自线 | 青草青草久热国产精品 | 国色天香社区在线视频 | 国内少妇偷人精品视频 | 成人无码精品1区2区3区免费看 | 亚洲色大成网站www | 高清国产亚洲精品自在久久 | 丰满诱人的人妻3 | 人人妻人人澡人人爽欧美一区九九 | 国产一区二区三区日韩精品 | a片免费视频在线观看 | 强开小婷嫩苞又嫩又紧视频 | 啦啦啦www在线观看免费视频 | 在线欧美精品一区二区三区 | 亚洲区小说区激情区图片区 | 国产办公室秘书无码精品99 | 熟女少妇在线视频播放 | 久久精品无码一区二区三区 | 国产香蕉尹人综合在线观看 | 日本饥渴人妻欲求不满 | 亚洲欧洲中文日韩av乱码 | 国产成人无码av片在线观看不卡 | 正在播放老肥熟妇露脸 | 国产精品99爱免费视频 | 久久99久久99精品中文字幕 | 天天综合网天天综合色 | 国产三级久久久精品麻豆三级 | 精品国产青草久久久久福利 | 天堂亚洲2017在线观看 | 激情爆乳一区二区三区 | 欧美freesex黑人又粗又大 | 国产精品久久福利网站 | 亚洲色偷偷男人的天堂 | 国产成人一区二区三区在线观看 | 国产熟妇高潮叫床视频播放 | 国产va免费精品观看 | 中文字幕+乱码+中文字幕一区 | 欧美日韩在线亚洲综合国产人 | 亚洲综合另类小说色区 | 无码国产乱人伦偷精品视频 | 亚洲精品午夜无码电影网 | 精品日本一区二区三区在线观看 | 亚洲乱亚洲乱妇50p | 色一情一乱一伦一区二区三欧美 | 日韩欧美群交p片內射中文 | 精品国产一区av天美传媒 | 日韩人妻无码中文字幕视频 | 国内精品九九久久久精品 | 中文字幕无码日韩专区 | 四虎影视成人永久免费观看视频 | 四十如虎的丰满熟妇啪啪 | 国产av久久久久精东av | 中文字幕日产无线码一区 | 中文毛片无遮挡高清免费 | 在线观看免费人成视频 | 久久婷婷五月综合色国产香蕉 | 国产精品久久久久久久影院 | 日韩精品无码一区二区中文字幕 | 国产成人无码专区 | 亚洲人成无码网www | 日韩精品无码一区二区中文字幕 | 5858s亚洲色大成网站www | 丰满人妻被黑人猛烈进入 | 中文字幕色婷婷在线视频 | 又粗又大又硬毛片免费看 | 久久人人爽人人人人片 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 国产亚洲精品久久久久久大师 | 精品日本一区二区三区在线观看 | 久久99国产综合精品 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产 精品 自在自线 | 成人片黄网站色大片免费观看 | 99久久人妻精品免费二区 | 欧美日本日韩 | 日日麻批免费40分钟无码 | 午夜无码人妻av大片色欲 | 内射老妇bbwx0c0ck | 国产午夜无码精品免费看 | 欧美国产日韩亚洲中文 | 国产av无码专区亚洲a∨毛片 | 久久久久久久久888 | av人摸人人人澡人人超碰下载 | 乱码av麻豆丝袜熟女系列 | 亚洲精品一区二区三区大桥未久 | 亚洲一区二区三区无码久久 | 88国产精品欧美一区二区三区 | 又色又爽又黄的美女裸体网站 | 丰满人妻精品国产99aⅴ | 动漫av一区二区在线观看 | 男女爱爱好爽视频免费看 | 又粗又大又硬毛片免费看 | 一个人免费观看的www视频 | 国产猛烈高潮尖叫视频免费 | 亚洲欧美综合区丁香五月小说 | 99久久婷婷国产综合精品青草免费 | 丝袜美腿亚洲一区二区 | 蜜臀av无码人妻精品 | 精品无码国产自产拍在线观看蜜 | 久久99国产综合精品 | 国产高清av在线播放 | 青青草原综合久久大伊人精品 | 亚洲一区二区三区偷拍女厕 | 丝袜人妻一区二区三区 | 中文字幕无码免费久久99 | 国产综合久久久久鬼色 | 国产激情精品一区二区三区 | 久9re热视频这里只有精品 | 亚洲人成人无码网www国产 | 99er热精品视频 | 77777熟女视频在线观看 а天堂中文在线官网 | 粉嫩少妇内射浓精videos | 日日摸夜夜摸狠狠摸婷婷 | 99久久精品午夜一区二区 | 久久久久av无码免费网 | 亚洲成av人在线观看网址 | 亚洲国产精品久久久天堂 | 中文字幕av无码一区二区三区电影 | 亚洲精品国产品国语在线观看 | 亚洲经典千人经典日产 | 蜜桃视频插满18在线观看 | 极品尤物被啪到呻吟喷水 | 国产婷婷色一区二区三区在线 | 狠狠色丁香久久婷婷综合五月 | 亚洲爆乳无码专区 | 亚洲 a v无 码免 费 成 人 a v | 日韩精品无码一本二本三本色 | 国产精品亚洲а∨无码播放麻豆 | 亚洲另类伦春色综合小说 | 国产国产精品人在线视 | 免费网站看v片在线18禁无码 | 在线成人www免费观看视频 | 天天躁夜夜躁狠狠是什么心态 | 无码午夜成人1000部免费视频 | 国产精品丝袜黑色高跟鞋 | 国产一精品一av一免费 | 国产精品怡红院永久免费 | 俺去俺来也www色官网 | 国产无遮挡又黄又爽免费视频 | 日本欧美一区二区三区乱码 | 日本成熟视频免费视频 | 少妇厨房愉情理9仑片视频 | 天天拍夜夜添久久精品大 | 国产熟妇另类久久久久 | 99久久久国产精品无码免费 | av无码不卡在线观看免费 | 久久天天躁狠狠躁夜夜免费观看 | 牲欲强的熟妇农村老妇女视频 | 99久久婷婷国产综合精品青草免费 | 亚洲另类伦春色综合小说 | 久久久久国色av免费观看性色 | 欧美成人家庭影院 | 久久综合给合久久狠狠狠97色 | 久久久精品人妻久久影视 | 好男人社区资源 | 国产女主播喷水视频在线观看 | 国产精品久久久久影院嫩草 | 亚洲国产精品一区二区第一页 | 国产精品久久久一区二区三区 | 亚洲中文字幕无码一久久区 | 好男人社区资源 | 少女韩国电视剧在线观看完整 | 夜夜夜高潮夜夜爽夜夜爰爰 | 日本精品久久久久中文字幕 | 日韩av无码中文无码电影 | 日本饥渴人妻欲求不满 | 日本熟妇人妻xxxxx人hd | 成人无码视频在线观看网站 | 自拍偷自拍亚洲精品被多人伦好爽 | 精品一区二区不卡无码av | 久久97精品久久久久久久不卡 | 亚洲精品美女久久久久久久 | 久久99精品国产麻豆蜜芽 | 无码人妻丰满熟妇区五十路百度 | 成人欧美一区二区三区黑人 | 国产亚洲精品久久久久久大师 | 色综合天天综合狠狠爱 | 一本色道久久综合狠狠躁 | 久久人人爽人人人人片 | 亚洲成在人网站无码天堂 | 亚洲中文字幕在线无码一区二区 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲一区二区三区偷拍女厕 | 亚洲 欧美 激情 小说 另类 | 日产精品99久久久久久 | 欧美人与动性行为视频 | 亚洲色欲色欲欲www在线 | 伊人久久大香线蕉av一区二区 | 国产精品国产三级国产专播 | 欧美zoozzooz性欧美 | 欧美日韩精品 | 亚洲の无码国产の无码影院 | 无码国产激情在线观看 | 最近免费中文字幕中文高清百度 | 亚洲娇小与黑人巨大交 | 亚洲春色在线视频 | 亚洲爆乳大丰满无码专区 | 久久国产自偷自偷免费一区调 | 又大又黄又粗又爽的免费视频 | 粉嫩少妇内射浓精videos | 97久久国产亚洲精品超碰热 | 久久午夜无码鲁丝片秋霞 | 免费无码午夜福利片69 | 综合网日日天干夜夜久久 | 国产亚洲欧美日韩亚洲中文色 | 午夜精品一区二区三区在线观看 | 131美女爱做视频 | 亚洲国产精品美女久久久久 | 精品人妻人人做人人爽夜夜爽 | 丰满人妻被黑人猛烈进入 | 免费中文字幕日韩欧美 | 欧美国产日韩久久mv | 欧美日韩在线亚洲综合国产人 | 国产精品无套呻吟在线 | 久久无码人妻影院 | 强开小婷嫩苞又嫩又紧视频 | 色一情一乱一伦一区二区三欧美 | 欧美日韩色另类综合 | 帮老师解开蕾丝奶罩吸乳网站 | 欧美精品免费观看二区 | 一二三四在线观看免费视频 | 狠狠色丁香久久婷婷综合五月 | 中文字幕+乱码+中文字幕一区 | 亚洲人成影院在线无码按摩店 | 欧美性猛交xxxx富婆 | 国产av一区二区三区最新精品 | 国产精品.xx视频.xxtv | 无码帝国www无码专区色综合 | 无码精品国产va在线观看dvd | 色婷婷av一区二区三区之红樱桃 | 18精品久久久无码午夜福利 | 少妇厨房愉情理9仑片视频 | 久久精品中文字幕一区 | 高中生自慰www网站 | 日韩av无码一区二区三区 | 亚洲精品国产精品乱码视色 | 成人一区二区免费视频 | 波多野结衣一区二区三区av免费 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产福利视频一区二区 | 98国产精品综合一区二区三区 | 老熟女乱子伦 | 无码中文字幕色专区 | 亚洲狠狠婷婷综合久久 | 亚洲男女内射在线播放 | 亚洲 另类 在线 欧美 制服 | 国产在线精品一区二区高清不卡 | 日韩精品无码免费一区二区三区 | 欧美国产日产一区二区 | 曰本女人与公拘交酡免费视频 | 无码人妻出轨黑人中文字幕 | 国产成人一区二区三区在线观看 | 国产精品久久精品三级 | 国产精品igao视频网 | 日日橹狠狠爱欧美视频 | 亚洲乱码日产精品bd | 亚洲国产精品毛片av不卡在线 | 日韩欧美中文字幕公布 | 一区二区三区乱码在线 | 欧洲 | 无码人妻丰满熟妇区毛片18 | 女人和拘做爰正片视频 | 红桃av一区二区三区在线无码av | 精品夜夜澡人妻无码av蜜桃 | 成人av无码一区二区三区 | 亚无码乱人伦一区二区 | 色综合天天综合狠狠爱 | 成人av无码一区二区三区 | 正在播放东北夫妻内射 | 国产精品香蕉在线观看 | 亚洲无人区一区二区三区 | av香港经典三级级 在线 | 无码毛片视频一区二区本码 | 国产情侣作爱视频免费观看 | 国产美女精品一区二区三区 | 久久精品99久久香蕉国产色戒 | 色综合久久久无码中文字幕 | 蜜桃臀无码内射一区二区三区 | 免费人成网站视频在线观看 | 久久99久久99精品中文字幕 | 欧美国产日产一区二区 | 波多野结衣av一区二区全免费观看 | 国产成人av免费观看 | 大肉大捧一进一出视频出来呀 | 中文字幕无码人妻少妇免费 | 国产成人亚洲综合无码 | 久久国产精品_国产精品 | 久久亚洲a片com人成 | 欧美性生交xxxxx久久久 | 亚洲狠狠色丁香婷婷综合 | 亚洲日韩乱码中文无码蜜桃臀网站 | 成人影院yy111111在线观看 | 亚洲精品国偷拍自产在线麻豆 | 中文无码精品a∨在线观看不卡 | 一本精品99久久精品77 | 67194成是人免费无码 | 国产精品毛多多水多 | 99re在线播放 | 国产精品久久久久9999小说 | 国产口爆吞精在线视频 | 久久综合给合久久狠狠狠97色 | 又大又硬又爽免费视频 | 欧洲vodafone精品性 | 国产日产欧产精品精品app | 激情国产av做激情国产爱 | 红桃av一区二区三区在线无码av | 国产欧美亚洲精品a | 国产做国产爱免费视频 | 亚洲精品中文字幕久久久久 | 国内少妇偷人精品视频 | а√天堂www在线天堂小说 | 特级做a爰片毛片免费69 | 少妇无套内谢久久久久 | 扒开双腿吃奶呻吟做受视频 | 国产尤物精品视频 | 人人澡人人妻人人爽人人蜜桃 | 欧洲精品码一区二区三区免费看 | 76少妇精品导航 | 欧美 日韩 亚洲 在线 | 亚洲欧洲无卡二区视頻 | 18无码粉嫩小泬无套在线观看 | 午夜精品一区二区三区在线观看 | 九九久久精品国产免费看小说 | 亚洲国产欧美在线成人 | 99精品视频在线观看免费 | 亚洲码国产精品高潮在线 | 婷婷丁香五月天综合东京热 | 少妇性荡欲午夜性开放视频剧场 | 女人被男人躁得好爽免费视频 | 亚洲综合另类小说色区 | 无码国产乱人伦偷精品视频 | 欧美真人作爱免费视频 | 国产激情艳情在线看视频 | 给我免费的视频在线观看 | 久久精品女人天堂av免费观看 | 18黄暴禁片在线观看 | 97精品人妻一区二区三区香蕉 | 久久国产精品二国产精品 | 国产综合久久久久鬼色 | 熟妇激情内射com | 亚洲欧美日韩国产精品一区二区 | 青青青爽视频在线观看 | 久久国产精品_国产精品 | 久久zyz资源站无码中文动漫 | 2019午夜福利不卡片在线 | 性开放的女人aaa片 | 精品偷拍一区二区三区在线看 | 精品国产一区二区三区四区在线看 | 又大又硬又黄的免费视频 | 久久综合香蕉国产蜜臀av | 国产手机在线αⅴ片无码观看 | 成人试看120秒体验区 | 美女毛片一区二区三区四区 | 无遮挡国产高潮视频免费观看 | 久久99久久99精品中文字幕 | 97夜夜澡人人双人人人喊 | 欧美熟妇另类久久久久久不卡 | 国产精品18久久久久久麻辣 | 国产精品第一国产精品 | 性色欲情网站iwww九文堂 | 中文字幕人妻无码一区二区三区 | 国产艳妇av在线观看果冻传媒 | 欧美性生交xxxxx久久久 | 极品尤物被啪到呻吟喷水 | 国产精品第一区揄拍无码 | 99精品国产综合久久久久五月天 | 久久亚洲a片com人成 | 国产精品美女久久久久av爽李琼 | a片在线免费观看 | 精品国产一区二区三区四区在线看 | 国产熟妇高潮叫床视频播放 | 夜先锋av资源网站 | 大肉大捧一进一出视频出来呀 | 成 人影片 免费观看 | 国产精品久久久久影院嫩草 | 人妻aⅴ无码一区二区三区 | 天天摸天天碰天天添 | 麻豆果冻传媒2021精品传媒一区下载 | 18精品久久久无码午夜福利 | 中文字幕无码视频专区 | 中国女人内谢69xxxxxa片 | 日韩亚洲欧美精品综合 | 国产舌乚八伦偷品w中 | 国产一区二区三区精品视频 | 日韩精品a片一区二区三区妖精 | 西西人体www44rt大胆高清 | 免费人成在线观看网站 | 激情人妻另类人妻伦 | 中文字幕乱码中文乱码51精品 | 人妻天天爽夜夜爽一区二区 | 欧美自拍另类欧美综合图片区 | 秋霞成人午夜鲁丝一区二区三区 | 国产人妻精品一区二区三区 | 俺去俺来也在线www色官网 | 欧美日韩一区二区免费视频 | 日本精品高清一区二区 | 无码乱肉视频免费大全合集 | 精品无码国产自产拍在线观看蜜 | 亚洲天堂2017无码 | 亚洲日韩一区二区三区 | 欧美怡红院免费全部视频 | 波多野结衣乳巨码无在线观看 | 天堂在线观看www | 婷婷五月综合激情中文字幕 | 欧美日韩人成综合在线播放 | 国产精品爱久久久久久久 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 国产办公室秘书无码精品99 | 国产亲子乱弄免费视频 | 久久人人爽人人爽人人片av高清 | 18黄暴禁片在线观看 | 日韩人妻无码一区二区三区久久99 | 成人亚洲精品久久久久软件 | 一本久久a久久精品vr综合 | 亚洲天堂2017无码 | 精品无码av一区二区三区 | 一个人看的视频www在线 | 大胆欧美熟妇xx | 曰本女人与公拘交酡免费视频 | 红桃av一区二区三区在线无码av | 国产一区二区三区日韩精品 | 天堂а√在线中文在线 | 精品国产av色一区二区深夜久久 | 国产亚洲精品精品国产亚洲综合 | 欧美熟妇另类久久久久久不卡 | 在线播放亚洲第一字幕 | 内射后入在线观看一区 | 久久亚洲精品中文字幕无男同 | 日本大乳高潮视频在线观看 | 中文字幕亚洲情99在线 | 中文字幕无码免费久久99 | 激情综合激情五月俺也去 | 嫩b人妻精品一区二区三区 | 国产精品无码永久免费888 | 狠狠亚洲超碰狼人久久 | 无码av中文字幕免费放 | 小鲜肉自慰网站xnxx | 久久午夜无码鲁丝片午夜精品 | 国产肉丝袜在线观看 | 久久久中文久久久无码 | 久久久www成人免费毛片 | 久久久久人妻一区精品色欧美 | 成在人线av无码免观看麻豆 | 国产成人一区二区三区在线观看 | 131美女爱做视频 | 高潮毛片无遮挡高清免费 | 无码午夜成人1000部免费视频 | 亚洲综合在线一区二区三区 | 亚洲熟妇色xxxxx亚洲 | 久久综合狠狠综合久久综合88 | 欧美日韩一区二区免费视频 | 亚洲日韩av一区二区三区四区 | 国产无遮挡又黄又爽免费视频 | 国产精品无码成人午夜电影 | 秋霞特色aa大片 | 99久久久无码国产精品免费 | 亚洲日韩乱码中文无码蜜桃臀网站 | 一本久道久久综合狠狠爱 | 亚洲狠狠色丁香婷婷综合 | 99久久久无码国产aaa精品 | 亚洲精品国产a久久久久久 | 国产xxx69麻豆国语对白 | 亚洲欧美日韩国产精品一区二区 | 国产精品免费大片 | 成人性做爰aaa片免费看 | 1000部啪啪未满十八勿入下载 | 亚洲一区二区三区在线观看网站 | 一二三四在线观看免费视频 | 国产成人无码区免费内射一片色欲 | 综合激情五月综合激情五月激情1 | 亚洲精品国偷拍自产在线观看蜜桃 | 亚洲中文字幕久久无码 | 成熟女人特级毛片www免费 | 日本护士xxxxhd少妇 | 女高中生第一次破苞av | 亚洲天堂2017无码中文 | 国产猛烈高潮尖叫视频免费 | 国产成人无码av一区二区 | 国产综合久久久久鬼色 | 日本一卡2卡3卡四卡精品网站 | 亚洲 日韩 欧美 成人 在线观看 | 性欧美videos高清精品 | 天天av天天av天天透 | 99久久无码一区人妻 | 强辱丰满人妻hd中文字幕 | 欧美国产日韩久久mv | 伊人色综合久久天天小片 | 亚洲无人区一区二区三区 | 国产午夜视频在线观看 | 天天av天天av天天透 | 人妻少妇精品视频专区 | 亚洲日本在线电影 | 97久久国产亚洲精品超碰热 | 欧洲精品码一区二区三区免费看 | 131美女爱做视频 | 丰满护士巨好爽好大乳 | 久久精品人妻少妇一区二区三区 | 水蜜桃亚洲一二三四在线 | 大地资源中文第3页 | 亚洲日韩av一区二区三区四区 | 国模大胆一区二区三区 | 国产午夜手机精彩视频 | 人妻插b视频一区二区三区 | 亚洲中文字幕在线观看 | 99久久精品午夜一区二区 | 欧美精品国产综合久久 | 少妇无码av无码专区在线观看 | 丰满少妇熟乱xxxxx视频 | 在教室伦流澡到高潮hnp视频 | 亚洲阿v天堂在线 | 成人欧美一区二区三区黑人免费 | 成人精品视频一区二区三区尤物 | 国产内射老熟女aaaa | 国产在线aaa片一区二区99 | 国产人妻久久精品二区三区老狼 | 日本丰满护士爆乳xxxx | 精品国产一区av天美传媒 | 久久人妻内射无码一区三区 | 亚洲色偷偷偷综合网 | 欧美成人高清在线播放 | 国产精品久久国产精品99 | 成人欧美一区二区三区黑人 | 97久久国产亚洲精品超碰热 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产黄在线观看免费观看不卡 | 久久久久久av无码免费看大片 | 成人无码精品一区二区三区 | 久久亚洲日韩精品一区二区三区 | 久在线观看福利视频 | 亚洲午夜久久久影院 | 初尝人妻少妇中文字幕 | 麻豆国产人妻欲求不满 | 黑人巨大精品欧美一区二区 | 婷婷色婷婷开心五月四房播播 | 婷婷综合久久中文字幕蜜桃三电影 | 噜噜噜亚洲色成人网站 | 亚洲精品一区二区三区大桥未久 | 日本肉体xxxx裸交 | 久久久中文字幕日本无吗 | 亚洲精品一区二区三区四区五区 | 99久久久无码国产aaa精品 | 又大又黄又粗又爽的免费视频 | 国产人妻精品午夜福利免费 | 亚洲а∨天堂久久精品2021 | 亚洲中文字幕va福利 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 天天躁夜夜躁狠狠是什么心态 | 大肉大捧一进一出好爽视频 | 香蕉久久久久久av成人 | 噜噜噜亚洲色成人网站 | 亚洲 欧美 激情 小说 另类 | 国产亚洲欧美日韩亚洲中文色 | 熟女少妇在线视频播放 | а√天堂www在线天堂小说 | 精品一区二区三区无码免费视频 | 亚洲国产成人a精品不卡在线 | 国产国产精品人在线视 | 久久99热只有频精品8 | 国产偷国产偷精品高清尤物 | 精品国产国产综合精品 | 亚洲欧美精品aaaaaa片 | 免费无码av一区二区 | 色婷婷综合激情综在线播放 | 人妻少妇精品视频专区 | 亚洲午夜无码久久 | 久久99久久99精品中文字幕 | 秋霞成人午夜鲁丝一区二区三区 | 日日橹狠狠爱欧美视频 | 免费无码av一区二区 | 俺去俺来也在线www色官网 | 亚洲成色在线综合网站 | 国产精品久久国产精品99 | 又色又爽又黄的美女裸体网站 | 极品尤物被啪到呻吟喷水 | 99久久精品午夜一区二区 | 亚洲国产欧美日韩精品一区二区三区 | 国产精品无套呻吟在线 | 国产 浪潮av性色四虎 | √天堂中文官网8在线 | 国产亚洲精品久久久久久国模美 | 国内精品九九久久久精品 | 亚洲а∨天堂久久精品2021 | 人妻少妇精品无码专区动漫 | 欧美熟妇另类久久久久久多毛 | 又色又爽又黄的美女裸体网站 | 日本乱人伦片中文三区 | 国产精品福利视频导航 | 亚洲精品成人av在线 | 免费观看又污又黄的网站 | 香蕉久久久久久av成人 | 国产精品久久久久9999小说 | 女人被爽到呻吟gif动态图视看 | 男女作爱免费网站 | 中文字幕乱妇无码av在线 | 成人无码精品一区二区三区 | 日日麻批免费40分钟无码 | 国产精品久久国产三级国 | 一本久道久久综合狠狠爱 | 亚洲热妇无码av在线播放 | 四虎国产精品免费久久 | 夜夜躁日日躁狠狠久久av | 精品国偷自产在线 | 丰满人妻一区二区三区免费视频 | 日日碰狠狠躁久久躁蜜桃 | 精品人人妻人人澡人人爽人人 | 人人妻人人澡人人爽欧美一区 | 欧美激情内射喷水高潮 | 国产电影无码午夜在线播放 | 精品无码av一区二区三区 | 国内揄拍国内精品少妇国语 | 精品无码成人片一区二区98 | 欧美老妇交乱视频在线观看 | 中文亚洲成a人片在线观看 | 成人欧美一区二区三区黑人 | 全黄性性激高免费视频 | 日本熟妇大屁股人妻 | 清纯唯美经典一区二区 | 最近中文2019字幕第二页 | 亚洲色成人中文字幕网站 | 中文字幕无线码免费人妻 | 欧美亚洲日韩国产人成在线播放 | 国产香蕉尹人视频在线 | 中文字幕久久久久人妻 | 娇妻被黑人粗大高潮白浆 | 成年女人永久免费看片 | 51国偷自产一区二区三区 | 丰满人妻精品国产99aⅴ | 无码国内精品人妻少妇 | 思思久久99热只有频精品66 | 中文字幕无码日韩欧毛 | 色欲av亚洲一区无码少妇 | 日韩av无码一区二区三区 | 99国产精品白浆在线观看免费 | 欧美一区二区三区视频在线观看 | 日日摸夜夜摸狠狠摸婷婷 | 露脸叫床粗话东北少妇 | 亚洲s码欧洲m码国产av | 国产精品对白交换视频 | 国内少妇偷人精品视频 | 动漫av网站免费观看 | 欧美精品免费观看二区 | 理论片87福利理论电影 | 曰韩无码二三区中文字幕 | 樱花草在线播放免费中文 | 久久精品国产一区二区三区肥胖 | 免费看男女做好爽好硬视频 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 精品国产一区二区三区av 性色 | 日本精品久久久久中文字幕 | 未满成年国产在线观看 | 永久免费观看美女裸体的网站 | 色五月五月丁香亚洲综合网 | 成人无码视频免费播放 | 老司机亚洲精品影院 | 在线看片无码永久免费视频 | 精品久久久久久亚洲精品 | 国产97色在线 | 免 | 色老头在线一区二区三区 | 亚洲日韩av片在线观看 | 麻豆精品国产精华精华液好用吗 | 亚洲日韩av片在线观看 | 无码一区二区三区在线 | 波多野结衣av在线观看 | 欧美三级不卡在线观看 | 国产三级精品三级男人的天堂 | 亚洲天堂2017无码 | 丰满少妇熟乱xxxxx视频 | 亚洲小说图区综合在线 | 欧美高清在线精品一区 | 小鲜肉自慰网站xnxx | 国产熟妇高潮叫床视频播放 | 国产成人无码专区 | 人人妻人人澡人人爽欧美一区 | 日韩人妻少妇一区二区三区 | 色婷婷久久一区二区三区麻豆 | 久久久精品成人免费观看 | 久久国产精品精品国产色婷婷 | 国产一区二区不卡老阿姨 | 亚洲 a v无 码免 费 成 人 a v | 正在播放老肥熟妇露脸 | 欧美乱妇无乱码大黄a片 | 色婷婷av一区二区三区之红樱桃 | 十八禁视频网站在线观看 | 国产人妻人伦精品1国产丝袜 | 性生交大片免费看l | 精品欧洲av无码一区二区三区 | √8天堂资源地址中文在线 | 国产色精品久久人妻 | 午夜丰满少妇性开放视频 | 国产一区二区不卡老阿姨 | 国产乱人伦偷精品视频 | 亚洲综合无码久久精品综合 | 日韩亚洲欧美中文高清在线 | 2020最新国产自产精品 | 97精品国产97久久久久久免费 | 一区二区三区高清视频一 | 久久国产精品偷任你爽任你 | 99麻豆久久久国产精品免费 | 午夜男女很黄的视频 | 日本熟妇人妻xxxxx人hd | 久久综合九色综合欧美狠狠 | 夜夜夜高潮夜夜爽夜夜爰爰 | 国产办公室秘书无码精品99 | 国产精品va在线播放 | 亚洲一区二区三区国产精华液 | 色综合视频一区二区三区 | 亚洲午夜久久久影院 | 国产农村乱对白刺激视频 | 国产无套内射久久久国产 | 超碰97人人做人人爱少妇 | 日本一区二区三区免费播放 | 精品乱码久久久久久久 | 无码人妻av免费一区二区三区 | 色偷偷人人澡人人爽人人模 | 夫妻免费无码v看片 | 欧美人妻一区二区三区 | 亚洲精品成人福利网站 | 国产偷自视频区视频 | 亚洲大尺度无码无码专区 | 亚洲精品www久久久 | 欧美 日韩 亚洲 在线 | 天干天干啦夜天干天2017 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产电影无码午夜在线播放 | 久久精品视频在线看15 | 中文亚洲成a人片在线观看 | 中文字幕人妻无码一夲道 | 搡女人真爽免费视频大全 | 麻花豆传媒剧国产免费mv在线 | 无码av岛国片在线播放 | 国产成人精品一区二区在线小狼 | 中文字幕乱码亚洲无线三区 | a片在线免费观看 | 天堂在线观看www | 久久久国产一区二区三区 | 俺去俺来也www色官网 | 一本色道久久综合亚洲精品不卡 | 久久无码专区国产精品s | 欧美激情综合亚洲一二区 | 国内少妇偷人精品视频免费 | 人妻少妇精品无码专区二区 | 5858s亚洲色大成网站www | 亚洲码国产精品高潮在线 | 中文字幕精品av一区二区五区 | 无码国产激情在线观看 | 丰腴饱满的极品熟妇 | 亚洲精品中文字幕久久久久 | 一本大道伊人av久久综合 | 国产成人无码午夜视频在线观看 | 99久久精品日本一区二区免费 | 国产在线精品一区二区三区直播 | 日本欧美一区二区三区乱码 | 自拍偷自拍亚洲精品被多人伦好爽 | 国产电影无码午夜在线播放 | 亚洲欧美中文字幕5发布 | 性色av无码免费一区二区三区 | 成人毛片一区二区 | 在线欧美精品一区二区三区 | 久久久婷婷五月亚洲97号色 | 粗大的内捧猛烈进出视频 | 亚洲小说图区综合在线 | 日韩 欧美 动漫 国产 制服 | 夜先锋av资源网站 | 久久久亚洲欧洲日产国码αv | 日韩精品a片一区二区三区妖精 | 377p欧洲日本亚洲大胆 | 扒开双腿吃奶呻吟做受视频 | 在线观看欧美一区二区三区 | 亚洲娇小与黑人巨大交 | 波多野结衣一区二区三区av免费 | 国产偷自视频区视频 | 精品国产麻豆免费人成网站 | 一本久道高清无码视频 | 国产人妻精品一区二区三区 | 97精品国产97久久久久久免费 | 国产农村乱对白刺激视频 | 欧美老人巨大xxxx做受 | 无码人妻精品一区二区三区不卡 | 国产网红无码精品视频 | 国产女主播喷水视频在线观看 | 无码av免费一区二区三区试看 | 日韩精品一区二区av在线 | 中文字幕无码日韩欧毛 | 亚洲色欲色欲欲www在线 | 亚洲精品国产品国语在线观看 | 国内老熟妇对白xxxxhd | 强伦人妻一区二区三区视频18 | 2019午夜福利不卡片在线 | 国产精品无码mv在线观看 | 无码乱肉视频免费大全合集 | 狠狠色欧美亚洲狠狠色www | 日本乱人伦片中文三区 | 亚洲熟悉妇女xxx妇女av | 97久久精品无码一区二区 | 中文字幕人妻无码一夲道 | 国产成人无码av一区二区 | 亚洲国产成人a精品不卡在线 | 国产成人无码a区在线观看视频app | 精品无码一区二区三区爱欲 | 又紧又大又爽精品一区二区 | 国产成人综合色在线观看网站 | 亚洲色偷偷男人的天堂 | 福利一区二区三区视频在线观看 | 人妻少妇精品无码专区动漫 | 国内精品人妻无码久久久影院蜜桃 | 亚洲gv猛男gv无码男同 | 久久精品成人欧美大片 | 亚洲爆乳大丰满无码专区 | 久久久久久久久888 | 少妇人妻偷人精品无码视频 | 国产av一区二区三区最新精品 | 免费人成在线视频无码 | 中文字幕 亚洲精品 第1页 | 国产色在线 | 国产 | 女人色极品影院 | 无码人妻丰满熟妇区毛片18 | 久久久www成人免费毛片 | 国内丰满熟女出轨videos | 国产精品二区一区二区aⅴ污介绍 | 久久亚洲日韩精品一区二区三区 | 亚洲欧美国产精品专区久久 | 捆绑白丝粉色jk震动捧喷白浆 | 亚洲国产高清在线观看视频 | 亚洲第一网站男人都懂 | 大屁股大乳丰满人妻 | 真人与拘做受免费视频 | 亲嘴扒胸摸屁股激烈网站 | 午夜福利不卡在线视频 | 人妻无码久久精品人妻 | 欧美日韩一区二区三区自拍 | 日韩人妻无码一区二区三区久久99 | 中文字幕色婷婷在线视频 | 国产后入清纯学生妹 | 久久久久免费精品国产 | 一个人看的www免费视频在线观看 | 国产69精品久久久久app下载 | 亚洲成av人在线观看网址 | 国产超级va在线观看视频 | 野外少妇愉情中文字幕 | 青青久在线视频免费观看 | 久久精品视频在线看15 | 亚洲一区二区三区播放 | 日本精品高清一区二区 | 最近免费中文字幕中文高清百度 | 性做久久久久久久免费看 | 日本丰满护士爆乳xxxx | 学生妹亚洲一区二区 | 亚洲人成影院在线观看 | 亚洲国精产品一二二线 | 清纯唯美经典一区二区 | 人人妻人人澡人人爽精品欧美 | 麻豆国产人妻欲求不满谁演的 | 国产亚洲欧美日韩亚洲中文色 | 亚洲精品国偷拍自产在线麻豆 | 日本爽爽爽爽爽爽在线观看免 | 久久久久久久久蜜桃 | a片免费视频在线观看 | 欧美日本日韩 | 亚洲小说春色综合另类 | 欧美日本日韩 | 久久精品人人做人人综合试看 | 欧美老熟妇乱xxxxx | 99riav国产精品视频 | 青青青爽视频在线观看 | 秋霞特色aa大片 | 又粗又大又硬毛片免费看 | 美女极度色诱视频国产 | 亚洲精品成人av在线 | 四虎永久在线精品免费网址 | 红桃av一区二区三区在线无码av | 国产精品爱久久久久久久 | 中文字幕中文有码在线 | 久久久久久久女国产乱让韩 | www国产亚洲精品久久久日本 | 国产又爽又猛又粗的视频a片 | av无码电影一区二区三区 | 激情综合激情五月俺也去 | 亚洲欧美日韩成人高清在线一区 | 国产激情艳情在线看视频 | 日韩人妻系列无码专区 | 欧美午夜特黄aaaaaa片 | 国产人妻人伦精品 | 人人妻人人澡人人爽人人精品浪潮 | 波多野结衣高清一区二区三区 | 久久国产精品_国产精品 | 日本一卡二卡不卡视频查询 | 国产精品久久久午夜夜伦鲁鲁 | 成人精品视频一区二区 | 亚洲色偷偷男人的天堂 | 亚洲伊人久久精品影院 | 久久亚洲a片com人成 | 久久精品国产精品国产精品污 | 亚洲理论电影在线观看 | 成人无码视频在线观看网站 | 国产97色在线 | 免 | 图片区 小说区 区 亚洲五月 | 日本一区二区三区免费播放 | 国产亚洲精品久久久ai换 | 一区二区三区高清视频一 | 国产日产欧产精品精品app | 亚洲一区二区三区 | 正在播放老肥熟妇露脸 | 色五月五月丁香亚洲综合网 | 2020久久香蕉国产线看观看 | 动漫av一区二区在线观看 | 日本www一道久久久免费榴莲 | 麻豆国产97在线 | 欧洲 | 国产人成高清在线视频99最全资源 | 综合网日日天干夜夜久久 | 黄网在线观看免费网站 | 成人aaa片一区国产精品 | 国产xxx69麻豆国语对白 | 久久久久免费看成人影片 | 天天拍夜夜添久久精品 | 人妻体内射精一区二区三四 | 久久久国产精品无码免费专区 | 免费观看又污又黄的网站 | аⅴ资源天堂资源库在线 | 国产精品.xx视频.xxtv | 国产亚洲精品久久久久久久久动漫 | 国产情侣作爱视频免费观看 | 国产又爽又黄又刺激的视频 | 欧美日韩亚洲国产精品 | 人妻少妇精品视频专区 | 亚洲精品久久久久久久久久久 | 午夜精品一区二区三区的区别 | 自拍偷自拍亚洲精品被多人伦好爽 | 国产成人亚洲综合无码 | 亚洲精品一区三区三区在线观看 | 久久综合给合久久狠狠狠97色 | 中文字幕无线码免费人妻 | 97久久精品无码一区二区 | 国产无遮挡吃胸膜奶免费看 | 一本大道久久东京热无码av | 亚洲 激情 小说 另类 欧美 | 色婷婷香蕉在线一区二区 | 免费人成在线观看网站 | 一本大道久久东京热无码av | 国产一区二区三区影院 | 少妇被黑人到高潮喷出白浆 | 免费网站看v片在线18禁无码 | 人妻有码中文字幕在线 | 亚洲精品成人av在线 | 色狠狠av一区二区三区 | 日本精品人妻无码免费大全 | 人妻互换免费中文字幕 | 亚洲呦女专区 | 性欧美疯狂xxxxbbbb | 国产莉萝无码av在线播放 | 亚洲一区二区三区 | 日日碰狠狠丁香久燥 | 大肉大捧一进一出好爽视频 | 亚洲成av人综合在线观看 | 国产婷婷色一区二区三区在线 | 国内精品久久久久久中文字幕 | 亚洲gv猛男gv无码男同 | 亚洲精品无码人妻无码 | 国产精品18久久久久久麻辣 | 少妇性l交大片欧洲热妇乱xxx | 300部国产真实乱 | 国产人妻精品午夜福利免费 | 成人性做爰aaa片免费看不忠 | 欧美性猛交xxxx富婆 | 人人澡人人透人人爽 | 无码av中文字幕免费放 | 欧美老熟妇乱xxxxx | 少妇无套内谢久久久久 | 西西人体www44rt大胆高清 | 国产口爆吞精在线视频 | 1000部夫妻午夜免费 | 亚洲啪av永久无码精品放毛片 | 久久人人97超碰a片精品 | 永久免费观看国产裸体美女 | 天天躁夜夜躁狠狠是什么心态 | 色综合久久久久综合一本到桃花网 | 人人妻人人藻人人爽欧美一区 | 中文字幕日产无线码一区 | 高潮毛片无遮挡高清免费视频 | 国产97人人超碰caoprom | 成人一在线视频日韩国产 | 国产精品.xx视频.xxtv | 午夜精品一区二区三区在线观看 | 青青久在线视频免费观看 | 狠狠亚洲超碰狼人久久 | 精品夜夜澡人妻无码av蜜桃 | 成人欧美一区二区三区黑人免费 | 久久无码中文字幕免费影院蜜桃 | 啦啦啦www在线观看免费视频 | 一本大道久久东京热无码av | 牲欲强的熟妇农村老妇女视频 | 亚洲国产精品一区二区美利坚 | 亚洲成a人片在线观看无码3d | 久久久久久a亚洲欧洲av冫 | 亚洲成av人综合在线观看 | 精品成人av一区二区三区 | 欧美丰满老熟妇xxxxx性 | 最近的中文字幕在线看视频 | 国产成人人人97超碰超爽8 | 国产精品久久久久9999小说 | 乱码av麻豆丝袜熟女系列 | 无码播放一区二区三区 | 国产av剧情md精品麻豆 | 人妻少妇被猛烈进入中文字幕 | 久久婷婷五月综合色国产香蕉 | 国产精品亚洲а∨无码播放麻豆 | 欧美熟妇另类久久久久久不卡 | 国内少妇偷人精品视频免费 | 国产电影无码午夜在线播放 | 粗大的内捧猛烈进出视频 | 激情五月综合色婷婷一区二区 | v一区无码内射国产 | 亚洲无人区午夜福利码高清完整版 | 纯爱无遮挡h肉动漫在线播放 | 人人妻人人澡人人爽欧美精品 | √8天堂资源地址中文在线 | 色综合久久久无码网中文 | 国产午夜亚洲精品不卡下载 | 午夜理论片yy44880影院 | 午夜男女很黄的视频 | 狠狠色欧美亚洲狠狠色www | 亚洲男女内射在线播放 | 天天拍夜夜添久久精品 | 国产精品久久久久无码av色戒 | 成在人线av无码免观看麻豆 | 国产av一区二区三区最新精品 | 在线亚洲高清揄拍自拍一品区 | 免费乱码人妻系列无码专区 | 色一情一乱一伦一区二区三欧美 | 久久天天躁夜夜躁狠狠 | 天天摸天天碰天天添 | 中文字幕乱妇无码av在线 | 亚洲啪av永久无码精品放毛片 | 天海翼激烈高潮到腰振不止 | 亚洲色欲色欲天天天www | 亚洲熟女一区二区三区 | 国产精品无码一区二区三区不卡 | 中文无码精品a∨在线观看不卡 | 欧美亚洲日韩国产人成在线播放 | 午夜精品久久久久久久久 | 亚洲 日韩 欧美 成人 在线观看 | 性生交片免费无码看人 | 国产亚洲精品久久久久久久久动漫 | 丰满少妇人妻久久久久久 | 久久国产精品萌白酱免费 | 中文字幕av无码一区二区三区电影 | 亚洲爆乳精品无码一区二区三区 | 中文字幕av无码一区二区三区电影 | 亚洲欧洲日本无在线码 | 人人妻在人人 | 欧美乱妇无乱码大黄a片 | 老司机亚洲精品影院无码 | 又色又爽又黄的美女裸体网站 | 欧美国产日产一区二区 | 国产亚洲欧美在线专区 | 国产乱人无码伦av在线a | 亚洲人成网站在线播放942 | 夜先锋av资源网站 | 亚洲爆乳大丰满无码专区 | 精品无码av一区二区三区 | 无码国产色欲xxxxx视频 | 国产精品毛多多水多 | 亚洲无人区午夜福利码高清完整版 | 日日天干夜夜狠狠爱 | 纯爱无遮挡h肉动漫在线播放 | 国产精品无套呻吟在线 | а√资源新版在线天堂 | 亚洲成在人网站无码天堂 | 中文字幕无码乱人伦 | 男人的天堂av网站 | 日日噜噜噜噜夜夜爽亚洲精品 | 妺妺窝人体色www在线小说 | 少妇被黑人到高潮喷出白浆 | 日产精品高潮呻吟av久久 | 亚洲熟熟妇xxxx | 国产成人av免费观看 | 天堂亚洲免费视频 | 思思久久99热只有频精品66 | 无套内谢的新婚少妇国语播放 | 精品aⅴ一区二区三区 | 日韩av无码一区二区三区不卡 | 狠狠噜狠狠狠狠丁香五月 | 精品国产一区二区三区四区在线看 | 国产激情无码一区二区 | 久久国语露脸国产精品电影 | 中文字幕人成乱码熟女app | 成人免费无码大片a毛片 | 无套内谢的新婚少妇国语播放 | 久久精品国产99久久6动漫 | 国产两女互慰高潮视频在线观看 | 蜜臀aⅴ国产精品久久久国产老师 | 成人女人看片免费视频放人 | 妺妺窝人体色www在线小说 | 男女性色大片免费网站 | 国产农村乱对白刺激视频 | 久久精品中文字幕一区 | 日本护士xxxxhd少妇 | 午夜不卡av免费 一本久久a久久精品vr综合 | 一区二区三区高清视频一 | 青青久在线视频免费观看 | 久久精品无码一区二区三区 | a在线亚洲男人的天堂 | 亚洲人成无码网www | 国产精品va在线观看无码 | 夜夜影院未满十八勿进 | 久久久精品欧美一区二区免费 | 人妻少妇精品久久 | 精品久久久中文字幕人妻 | 99精品久久毛片a片 | 四虎影视成人永久免费观看视频 | 人妻体内射精一区二区三四 | 岛国片人妻三上悠亚 | 婷婷色婷婷开心五月四房播播 | 狠狠色欧美亚洲狠狠色www | 欧美放荡的少妇 | 美女毛片一区二区三区四区 | 午夜福利试看120秒体验区 | 伊人久久大香线焦av综合影院 | 夜夜影院未满十八勿进 | 亚洲欧美国产精品专区久久 | 欧洲精品码一区二区三区免费看 | 亲嘴扒胸摸屁股激烈网站 | 人妻少妇精品久久 | 亚洲人成影院在线无码按摩店 | 亚洲国精产品一二二线 | 精品国产青草久久久久福利 | 日韩成人一区二区三区在线观看 | 在线亚洲高清揄拍自拍一品区 | 色窝窝无码一区二区三区色欲 | 麻豆成人精品国产免费 | 天干天干啦夜天干天2017 | 一个人看的视频www在线 | 日本又色又爽又黄的a片18禁 | 国产在线一区二区三区四区五区 | 老头边吃奶边弄进去呻吟 | 色欲久久久天天天综合网精品 | 日韩精品乱码av一区二区 | 国产后入清纯学生妹 | 国产成人精品无码播放 | 国产高清不卡无码视频 | 国产人妻精品午夜福利免费 | 国产成人无码a区在线观看视频app | 无码吃奶揉捏奶头高潮视频 | 日本熟妇大屁股人妻 | 色诱久久久久综合网ywww | 男人的天堂2018无码 | 亚洲色大成网站www国产 | 2020久久超碰国产精品最新 | 久久精品国产精品国产精品污 | 亚洲色在线无码国产精品不卡 | 亚洲成熟女人毛毛耸耸多 | 久久精品一区二区三区四区 | 精品久久8x国产免费观看 | 亚洲精品成人av在线 | 男人扒开女人内裤强吻桶进去 | 亚洲人成无码网www | 亚洲の无码国产の无码影院 | 波多野结衣 黑人 | 久久午夜夜伦鲁鲁片无码免费 | 国产精品久久久一区二区三区 | 天下第一社区视频www日本 | 久久久国产精品无码免费专区 | 日韩精品无码一区二区中文字幕 | 色老头在线一区二区三区 | 性生交大片免费看l | 人妻有码中文字幕在线 | 四虎影视成人永久免费观看视频 | 国产农村妇女高潮大叫 | 亚洲色欲色欲欲www在线 | 成熟女人特级毛片www免费 | 欧美丰满老熟妇xxxxx性 | 亚洲小说图区综合在线 | 未满小14洗澡无码视频网站 | 午夜精品久久久久久久久 | 精品亚洲成av人在线观看 | 国产激情一区二区三区 | 精品欧美一区二区三区久久久 | 88国产精品欧美一区二区三区 | 久久97精品久久久久久久不卡 | 欧美乱妇无乱码大黄a片 | 亚洲成av人在线观看网址 | 人妻天天爽夜夜爽一区二区 | 人妻人人添人妻人人爱 | 国产精品igao视频网 | 国产内射爽爽大片视频社区在线 | 亚洲熟妇色xxxxx亚洲 | 人妻少妇精品无码专区二区 | 亚洲熟悉妇女xxx妇女av | 国产精品美女久久久网av | 亚洲人成网站色7799 | 无码人妻精品一区二区三区不卡 | 亚洲人成网站在线播放942 | 丰满人妻一区二区三区免费视频 | 久久精品一区二区三区四区 | 精品无码国产自产拍在线观看蜜 | 国产精品久久久久久亚洲毛片 | 欧美精品一区二区精品久久 | 国产两女互慰高潮视频在线观看 | 18黄暴禁片在线观看 | 少妇愉情理伦片bd | 强奷人妻日本中文字幕 | 蜜桃无码一区二区三区 | 人妻中文无码久热丝袜 | 99久久精品国产一区二区蜜芽 | 亚洲人亚洲人成电影网站色 | 在线成人www免费观看视频 | 久久人人爽人人爽人人片av高清 | 300部国产真实乱 | 中文字幕中文有码在线 | 亚洲乱码日产精品bd | 国产精品亚洲一区二区三区喷水 | 熟女俱乐部五十路六十路av | 1000部啪啪未满十八勿入下载 | 人人妻人人藻人人爽欧美一区 | 九九热爱视频精品 | 东北女人啪啪对白 | 亚洲欧美国产精品专区久久 | 国产亚洲美女精品久久久2020 | 亚洲中文字幕av在天堂 | 领导边摸边吃奶边做爽在线观看 | 超碰97人人做人人爱少妇 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 人妻互换免费中文字幕 | 国内精品人妻无码久久久影院蜜桃 | 超碰97人人做人人爱少妇 | 亚洲va欧美va天堂v国产综合 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 天天做天天爱天天爽综合网 | aa片在线观看视频在线播放 | 少妇性l交大片欧洲热妇乱xxx | 亚洲国产午夜精品理论片 | 麻豆av传媒蜜桃天美传媒 | 中文字幕av伊人av无码av | 国产精品人人爽人人做我的可爱 | 成人无码影片精品久久久 | 国内少妇偷人精品视频免费 | 欧美熟妇另类久久久久久多毛 | 欧美国产日产一区二区 | 国产精品视频免费播放 | 久久无码专区国产精品s | 亚洲精品成人av在线 | 日本精品久久久久中文字幕 | 欧洲极品少妇 | 国产成人久久精品流白浆 | 精品久久久无码中文字幕 | 天堂无码人妻精品一区二区三区 | 撕开奶罩揉吮奶头视频 | 在线观看欧美一区二区三区 | 日韩人妻无码中文字幕视频 | 99麻豆久久久国产精品免费 | 天下第一社区视频www日本 | 亚洲日本va午夜在线电影 | 欧美35页视频在线观看 | 久久无码中文字幕免费影院蜜桃 | 青草青草久热国产精品 | 亚洲日韩av一区二区三区中文 | 国产又粗又硬又大爽黄老大爷视 | 中文字幕无码视频专区 | 日本护士毛茸茸高潮 | 沈阳熟女露脸对白视频 | 欧美日韩亚洲国产精品 | 久久这里只有精品视频9 | 国产精品99久久精品爆乳 | 久久综合给久久狠狠97色 | 亚洲人成影院在线观看 | 一个人看的www免费视频在线观看 | 欧美日韩色另类综合 | 亚洲小说图区综合在线 | 久久亚洲日韩精品一区二区三区 | 亚洲综合在线一区二区三区 | 日本xxxx色视频在线观看免费 | 亚洲欧美精品伊人久久 | 99久久久无码国产精品免费 | 欧洲vodafone精品性 | 国产亲子乱弄免费视频 | 欧美激情一区二区三区成人 | 日欧一片内射va在线影院 | 一个人免费观看的www视频 | 噜噜噜亚洲色成人网站 | 福利一区二区三区视频在线观看 | 亚洲 激情 小说 另类 欧美 | 精品久久久无码人妻字幂 | 黄网在线观看免费网站 | 欧美人与禽zoz0性伦交 | 亚洲午夜无码久久 | 天天av天天av天天透 | 日韩人妻无码一区二区三区久久99 | 国内揄拍国内精品人妻 | 亚洲精品久久久久久久久久久 | 国产精品久久久久影院嫩草 | 牲欲强的熟妇农村老妇女视频 | 在线视频网站www色 | 免费看少妇作爱视频 | 国产精品99久久精品爆乳 | 精品aⅴ一区二区三区 | 1000部夫妻午夜免费 | 国精品人妻无码一区二区三区蜜柚 | 日日碰狠狠躁久久躁蜜桃 | 黑人巨大精品欧美一区二区 | 亚洲午夜福利在线观看 | 亚洲精品一区二区三区在线 | 国产精品久久久午夜夜伦鲁鲁 | 国产亚洲精品精品国产亚洲综合 | 亚洲国产av美女网站 | 国产在线精品一区二区三区直播 | 欧美国产日韩亚洲中文 | 久久国产自偷自偷免费一区调 | 亚洲国产午夜精品理论片 | 爽爽影院免费观看 | 美女张开腿让人桶 | 久久无码中文字幕免费影院蜜桃 | 内射白嫩少妇超碰 | 最近中文2019字幕第二页 | 无码人妻精品一区二区三区下载 | 欧美三级a做爰在线观看 | 人妻有码中文字幕在线 | 奇米影视7777久久精品人人爽 | 无码人妻av免费一区二区三区 | 全黄性性激高免费视频 | a在线亚洲男人的天堂 | 熟妇人妻中文av无码 | 中文字幕人妻无码一区二区三区 | 精品偷拍一区二区三区在线看 | 成人性做爰aaa片免费看不忠 | 图片区 小说区 区 亚洲五月 | 久久人人爽人人爽人人片av高清 | 国产成人精品无码播放 | 国产欧美熟妇另类久久久 | 午夜福利试看120秒体验区 | 蜜桃臀无码内射一区二区三区 | 国产激情艳情在线看视频 | 日本www一道久久久免费榴莲 | 国产国语老龄妇女a片 | 日本精品久久久久中文字幕 | 真人与拘做受免费视频 | 日韩av无码一区二区三区 | 久久久中文字幕日本无吗 | 免费观看的无遮挡av | 少妇性荡欲午夜性开放视频剧场 | 荫蒂添的好舒服视频囗交 | 色狠狠av一区二区三区 | 国产精品久久久av久久久 | 亚洲狠狠婷婷综合久久 | 欧美性黑人极品hd | 国产色视频一区二区三区 | av人摸人人人澡人人超碰下载 | 永久免费精品精品永久-夜色 | 亚洲熟熟妇xxxx | 日本欧美一区二区三区乱码 | 波多野42部无码喷潮在线 | 天海翼激烈高潮到腰振不止 | 人妻插b视频一区二区三区 | 色诱久久久久综合网ywww | 亚洲春色在线视频 |