分佈式總結

1、TOKENcss

  Token的特色: html

  1. 無狀態、可擴展
  2. 支持移動設備
  3. 跨程序調用
  4. 安全

  Token原理:前端

  1. 將荷載PAYLOAD以及HEADER信息進行Base64加密,造成密文payload密文,head密文。
  2. 將造成的密文用句號鏈接起來,用服務端密鑰進行HS256加密,生成簽名。
  3. 將前面的兩個密文後面用句號鏈接簽名造成最終的TOKEN返回給服務端。

  TOKEN的實現:java

  1. 用戶登陸校驗,校驗成功後就返回TOKEN給客戶端
  2. 客戶端收到數據後保存在客戶端
  3. 客戶端每次訪問API是攜帶TOKEN到服務器端
  4. 服務器端採用FILTER過濾器校驗。校驗成功則返回請求數據,校驗失敗則返回錯誤碼。

Token用在:登陸校驗。node

TOKENsession對比有更高的安全性,無狀態可擴展性和多平臺跨越的優勢。linux

TOKEN能夠完美解決跨站請求僞造,負載均衡,無狀態可擴展性等問題。ios

 

2、敏捷開發nginx

  敏捷開發是以人爲核心,迭代按部就班的開發方法。他不是一門技術,他是一種開發方式,也就是一種軟件開發流程。它採用的是迭代式開發。git

  三大核心角色:程序員

產品負責人:負責肯定產品功能和達到要求的標準。規定軟件發佈日期和交付內容,同時又權利接受拒絕開發成果。

流程管理員: 負責整個敏捷開發流程在項目中的順利實施和進行,以及與客戶溝通排除溝通障礙,使開發知足客戶需求。

開發團隊:負責開發工做。負責不一樣的技術方面,成員要求達到SPRINT的目標。

 

三個物件:

Productbacklog(產品待辦事項列表)、

Sprint backlog(迭代列表)

燃盡圖

四個會議:

Sprint計劃會議,每日例會

Sprint評審會議,sprint回顧會議

 

項目前:

  1. 敏捷開發需求分析
    2.  Product Backlog(產品需求列表)
    3.  Sprit計劃會議

項目中:

  1. print Backlog(迭代列表)
    2.  Daily Scrum Meeting(每日立會)
    3.  Sprint burn down(迭代週期燃盡圖)
    4.  版本迭代
    項目後:

  評審會議

總結會議

 

特色:

敏捷開發技術特色:

  1. 個體和交互賽過過程和工具
  2. 能夠工做的軟件賽過面面俱到的文檔
  3. 客戶合做賽過合同談判
  4. 相應變化賽過遵循計劃

 

優勢:

用戶參與其中,客戶滿意度高。

提升開發效率

市場快速反應能力高

缺點:

繁瑣,壓力大。

 

最小粒度:

什麼是服務:服務表明一個或一組相對較小且獨立的功能單元,是用戶能夠感知的最小功能集。登陸,添加用戶。。。。。。

基本服務就是最小服務,這種服務有比較高的重用性。

合成:基本服務簡單組合。

組合服務:算是最大力度服務,裏面基本服務關係受到工做流程控制。

粒度就是功能大小,粗粒度表示功能業務多相對重用性較低,細粒度表示功能簡單重用性高。

 

最大粒度:在一個抽象接口封裝了大塊的業務邏輯和能力。

優勢:減小了服務請求的交互次數,減小成本。

缺點:帶來更高的複雜性,交互大量數據,不能靈活適應需求變化,重用性低。

最小粒度:相對較小的功能單元,或交互少許數據。

優勢:靈活性強,重用性高

缺點,須要經過屢次服務交互才能實現。

特性:重用性、靈活性、性能

解決方案:

一、設計接口和實體類

二、統一管理設計模式

三、優化組件充足業務服務。

 

 

單點登陸(SSO):

單點登陸:就是用戶只需一次登陸就能夠訪問全部相互信任的應用系統。簡單來講就是一處登陸,到處登陸,一處註銷,到處註銷。

 

做用:使得用戶只要登陸了其中一個系統,就能夠訪問其餘相關係統,而不用進行身份驗證登陸。即用戶只要登錄系統一次,該用戶的身份信息就能夠被系統中的多個主機上的應用所識別,不須要在訪問每一個應用時再分別進行登錄。

 

系統應用中的概念:

主要用於多系統的繼承,即在多系統當中,用戶只須要用到一箇中央服務器,登陸一次就能夠訪問這些系統的任何一個,無需屢次登陸。目前流行的企業業務整合的解決方案之一。

單點登陸的組成
單點登陸(SSO)體系主要有3個 :
(1)多個用戶
(2)多個Web應用
(3)1SSO認證中心(也就是咱們的中央服務器)。   其中多個用戶訪問不一樣的Web應用,是否須要登 錄由SSO認證中心來控制。

 

單點登陸的實現方式
1. Cookie做爲憑證媒介 ;
2. 經過JSONP實現 ;
3. 經過頁面重定向的方式 ;
4.JWT+安全框架的實現方式
4. 使用獨立登陸系統 ;

 

單點登陸的兩種實現:

  1. redis實現單點登陸
  2. CAS中央認證明現單點登陸

 

Redis實現單點登陸 - 處理流程:
1、登陸頁面提交用戶名密碼。
2、登陸成功後生成tokenToken至關於原來的jsessionid,字符串,能夠使用uuid
3、把用戶信息保存到redisKey就是tokenvalue就是實體類對象轉換成json
4、使用String類型保存Session信息。能夠使用「前綴:token」爲key
5、設置key的過時時間。模擬Session的過時時間。通常半個小時。
6、把token寫入cookie中。
7Cookie須要跨域。
8Cookie的有效期。關閉瀏覽器失效。
9、登陸成功。

 

CAS中央認證:CAS SERVER CAS CLIENT

 

CAS SERVER負責對用戶的認證工做,會爲用戶簽發兩個重要的數據,登陸和服務。

CAS SERVER須要獨立部署。

 

CAS CLIENT負責處理對客戶端受保護的資源的訪問請求,要對請求方進行身份認證,重定向到CAS SERVER進行認證。以過濾方式保護受保護的資源。對於訪問受保護資源的請求,CAS CLIENT會分析請求中是否包含service ticket

 

Spring boot

Spring boot是一個很是好的微服務分佈式開發框架,能夠快速搭建一個系統。

 

Spring 4大核心:

  1. 自動配置
  2. 起步依賴
  3. 命令行界面
  4. Actuator

 

Springapplication的實現方法:

  1. 若是使用的是靜態run方法那麼首先要建立一個springapplication對象,他會提早作下面幾件事情:

根據classpath裏面是否存在某個特徵類來決定是否應該建立一個爲web應用使用的applicationcontext。  

使用springfactoriesLoader在應用的classpath中查找加載全部可用的applicationContextInitializer。  

使用springFactoriesLoader在應用的classpath中查找並加載全部可用ApplicationListener

推斷並設置main方法定義類。

  1. springapplication實例初始化完成並完成設置後,就開始執行run方法的邏輯,方法執行開始,首先遍歷執行全部經過springFactoriesLoder能夠查找到並加載的SpringApplicationRunlistener。調用它的started()方法,告訴SpringApplicationRunListenerspring boot開始執行。
  2. 建立並配置當前spring boot 應用將要使用的Environment。遍歷調用全部apringapplicationRunListenerenvironmentPrepared()方法,告訴他們當前springboot應用使用的Environment準備好了。若是springapplicationshowbanner屬性被設置爲true。則須要打印banner
  3. 根據用戶是否明確設置applicationContextClass類型以及初始化階段的推斷結果,決定改成當前SpringBoot應用建立什麼類型的ApplicationContext並建立完成,而後根據條件決定是否添加ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,固然最重要的是將以前準備好的Environment設置給建立好的ApplicationContext使用。
  4. ApplicationContext建立好以後,SpringApplication會再次藉助Spring-FactoriesLoader,查找並加載classpath中全部可用的ApplicationContext-Initialzer而後遍歷調用這些ApplicationContextInitializerinitialize(applicationContext)方法來對已經建立好的ApplicationContext進行進一步處理。
  5. 遍歷全部SpringApplicationRunListenercontextPrepared()方法。最核心的一步,將以前經過@EnableAutoConfiguration獲取的全部配置以及其餘形式的IOC容器配置加載到已經準備完畢的ApplicationContext。遍歷調用全部SpringApplicationRunListenercontextLoaded()方法。調用ApplicationContextrefresh()方法,完成IOC容器可用的最後一步,查找當前ApplicationContext中是否註冊有CommandLineRunner,若是有遍歷執行他們。

正常狀況下,遍歷執行SpringApplicationRunListenerfinished()方法,只不過這種狀況會將異常信息一併傳入處理。

 

Spring boot整合Redis

建立redis.properties配置文件。

而後建一個封裝redisTemplateredisutil

最後建一個redisconf便可實現使用redis

 

Spring boot 整合jpa

Jpa查詢:基本查詢分爲兩種,一種是spring data默認實現,一種是根據查詢方法來自動解析成SQL

  1. 繼承JpaRepositoy

經過繼承這個類來實現最基本的增刪改查。

  1. 自定義簡單查詢:

JPA這裏遵循的是約定大約配置的原則,就是遵循spring以及jpql定義的方法命名。Spring提供一套能夠經過命名規範進行查詢構建的機制,這套機制會把方法名過濾一些關鍵字,好比find...byread...byquery...byget...by。系統會根據關鍵字將命名解析成兩個子語句,第一個By是區分這兩個子語句的關鍵詞.這個BY以前的是查詢子語句(知名返回要查詢的對象),後面的部分是條件子語句。若是直接findby...返回的就是定義respository時指定的領域對象集合,同時jpql中也定義了豐富的關鍵字:andor等等...

Jpa關鍵註解一覽:

@Entity 聲明類爲實體或表。

@Table 聲明表名。

@Basic 指定非約束明確的各個字段。

@Embedded 指定類或它的值是一個可嵌入的類的實例的實體的屬性。

@Id 指定的類的屬性,用於識別(一個表中的主鍵)。

@GeneratedValue 指定如何標識屬性能夠被初始化,例如自動、手動、或從序列表中得到的值。

@Transient 指定的屬性,它是不持久的,即:該值永遠不會存儲在數據庫中。

@Column 指定持久屬性欄屬性。

@SequenceGenerator 指定在@GeneratedValue註解中指定的屬性的值。它建立了一個序列。

@TableGenerator 指定在@GeneratedValue批註指定屬性的值發生器。它創造了的值生成的表。

@AccessType 這種類型的註釋用於設置訪問類型。若是設置@AccessTypeFIELD),則能夠直接訪問變量而且不須要gettersetter,但必須爲public。若是設置@AccessTypePROPERTY),經過gettersetter方法訪問Entity的變量。

@JoinColumn 指定一個實體組織或實體的集合。這是用在多對一和一對多關聯。

@UniqueConstraint 指定的字段和用於主要或輔助表的惟一約束。

@ColumnResult 參考使用select子句的SQL查詢中的列名。

@ManyToMany 定義了鏈接表之間的多對多一對多的關係。

@ManyToOne 定義了鏈接表之間的多對一的關係。

@OneToMany 定義了鏈接表之間存在一個一對多的關係。

@OneToOne 定義了鏈接表之間有一個一對一的關係。

@NamedQueries 指定命名查詢的列表。

@NamedQuery 指定使用靜態名稱的查詢

And findByLastnameAndFirstname

Or findByLastnameOrFirstname

Is,Equals findByFirstnameIs,findByFirstnameEquals

Between findByStartDateBetween

LessThan findByAgeLessThan

LessThanEqual find ByAgeLessThanEqual

GreaterThan findByAgeGreaterThan

GreaterThanEqual findByAgeGreaterThanEqual

After findByStartDateAfter

Before findByStartDateBefore

IsNull findByAgeIsNull

IsNotNull,NotNull findByAge(Is)NotNull

Like findByFirstnameLike

NotLike findByFirstnameNotLike

StartingWith findByFirstnameStartingWith

EndingWith findByFirstnameEndingWith

Containing findByFirstnameContaining

OrderBy findByAgeOrderByLastnameDesc

Not findByLastnameNot

In findByAgeIn(Collection ages)

NotIn findByAgeNotIn(Collection age)

TRUE findByActiveTrue()

FALSE findByActiveFalse()

IgnoreCase findByFirstnameIgnoreCase

 

 

Spring經常使用註解:

@Configuration 等同於springXML配置文件;使用Java代碼能夠檢查類型安全。

@Controller:用於定義控制器類,在spring 項目中由控制器負責將用戶發來的URL請求轉發到對應的服務接口

service層),通常這個註解在類中,一般方法須要配合註解@RequestMapping

@RestController:用於標註控制層組件(struts中的action)@ResponseBody@Controller的合集。

@RequestMapping:提供路由信息,負責URLController中的具體函數的映射。

@Service:通常用於修飾service層的組件

@Autowired:自動導入依賴的bean

@Repository:使用@Repository註解能夠確保DAO或者repositories提供異常轉譯,這個註解修飾的DAO或者repositories類會被ComponetScan發現並配置,同時也不須要爲它們提供XML配置項。

@ControllerAdvice:包含@Component。能夠被掃描到。統一處理異常。

@ExceptionHandlerException.class):用在方法上面表示遇到這個異常就執行如下方法。

 

定時任務:

現實生活中咱們須要不少定製的任務,記住一些事情而後定時提醒咱們,好比鬧鐘。應用開發中也常常須要一些週期性的操做,這時候就用到定時任務。

實現定時任務的集中實現方法:

  1. java.util.Timer

Java自帶的方法,容許調度一個task任務。使用這種方法可讓你程序按照一個頻度執行,但不能在指定時間運行。Timertask類實現由timer安排的一次或重複執行的某我的物。每一個timer對象對應的是一個線程,所以計時器所執行的任務應該迅速完成否則會延遲後續的任務。

舉個栗子:

Timer  timer=new Timer();  

    MyTask myTask=new MyTask();  

    timer.schedule(myTask, 1000, 2000);

TimerTask類主要實現run()方法裏的業務邏輯,用法以下:

 

import java.text.SimpleDateFormat;  

import java.util.Date;  

import java.util.TimerTask;  

 

public class MyTask extends TimerTask {  

 

    @Override  

    public void run() {  

        // TODO Auto-generated method stub  

        SimpleDateFormat simpleDateFormat=null;  

        simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");  

        System.out.println("當前的系統時間爲:"+simpleDateFormat.format(new Date()));

 

 

    }  

}

Timer線程如何終止:

默認狀況下,建立的timer線程會一直執行,因此咱們有4中方法終止timer線程。

調用timercancle方法

timer線程設置成daemon線程,(new Timer(true)建立daemon線程),在jvm裏,若是全部用戶線程結束,那麼守護線程也會被終止,不過這種方法通常不用。

當全部任務執行結束後,刪除對應timer對象的引用,線程也會被終止。

調用System.exit方法終止程序

注意點:

每一個timer僅對惟一一個線程

Timer不保證任務執行的十分精確。

Timer類是線程安全的。

 

  1. 鏈接池實現定時任務:

出現緣由:

  1. timer之建立了一個線程,任務執行時間超過設置的時間將會出現問題。
  2. Timer建立的線程沒有處理異常,所以一旦拋出異常,該線程就馬上終止。

 

方法簡介

 

scheduleAtFixedRate(Runnable command,

                                long initialDelay,

                                  long period,

                                  TimeUnit unit)1234

 

上面的四個參數進行講解:

第一個command參數是任務實例,

第二個initialDelay參數是初始化延遲時間,

第三個period參數是間隔時間,

第四個unit參數是時間單元。

 

3.Spring-Task

Spring自帶的Task實現定時任務也有兩種方式,一種是xml配置的方式,一種是使用註解@Scheduled,無論是那種方式,首先都須要在xml開頭聲明task

 

Quartz

Quartz用一個jar文件,這個庫文件包括了全部quartz核心功能。這些功能主要經過接口是Scheduler接口。

quartz的原理不是很複雜,只要搞明白幾個概念,而後知道如何去啓動和關閉一個調度程序便可。

1Job

表示一個工做,要執行的具體內容。此接口中只有一個方法

void execute(JobExecutionContext context)

2JobDetail

JobDetail表示一個具體的可執行的調度程序,Job是這個可執行程調度程序所要執行的內容,另外JobDetail還包含了這個任務調度的方案和策略。

3Trigger表明一個調度參數的配置,何時去調。Scheduler能夠將Trigger綁定到某一JobDetail中,這樣當Trigger觸發時,對應的Job就被執行。一個Job能夠對應多個Trigger,但一個Trigger只能對應一個Job

4Calendarorg.quartz.Calendar是一些日曆特定時間點的集合, 一個Trigger能夠和多個Calendar關聯。

5.ThreadPoolScheduler使用一個線程池做爲任務運行的基礎設施,任務經過共享線程池中的線程提升運行效率

 

Quartz 中,有兩類線程,Scheduler 調度線程和任務執行線程,其中任務執行線程一般使用一個線程池維護一組線程

 

Spring boot實現定時任務:

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

     <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-devtools</artifactId>

        <optional>true</optional>

</dependency>

</dependencies>

 

而後在啓動類上面加上@EnableScheduling便可開啓定時任務(@EnableScheduling  註解,它的做用是發現註解 @Scheduled的任務並由後臺執行。沒有它的話將沒法執行定時任務)

建立定時任務實現類

 

安全框架Shiro

Shirojava的一個安全框架,功能強大,使用簡單的java安全框架,爲開發人員提供一個直觀而全面的認證,受權,加密以及繪畫管理解決方案。

爲何使用shiro

  1. 易於使用,提供易於理解的java security API
  2. 簡單的身份認證,支持多數據源(LDAP,JDBC,Kerberos)
  3. 支持一級緩存,以及提高應用程序的性能。
  4. Shiro乾淨的API和設計模式使它能夠方便與許多的其餘框架和應用進行集成。

 

 

Shiro的用途:

  1. 驗證用戶來覈實他們的身份
  2. 對用戶執行訪問控制,如:判斷用戶是否被分配了一個肯定的安全角色、判斷用戶是否被容許作某事。
  3. 在任何環境下使用sessionAPI,即便沒有webejb容器。
  4. 在身份驗證,訪問看哦內置期間或在會話的生命週期,對時間作出反應。
  5. 啓用單點登陸功能
  6. 數據加密,防止密碼明文儲存。

 

主要功能特色:

 

Authentication:身份認證/登陸,驗證用戶是否是擁有相應的身份。

Authorization:受權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即判斷用戶是否能作事情,常見的如:驗證某個用戶是否擁有某個角色。或者驗證某個用戶對某個資源是否具備某個權限;

Session Manager:會話管理,即用戶登陸後就是一次會話,在沒有退出以前,它的全部信息都在會話中;會話能夠是普通JavaSE環境的,也能夠是如Web環境的;

Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲;

Web SupportWeb支持,能夠很是容易的集成到Web環境;

Caching:緩存,好比用戶登陸後,其用戶信息、擁有的角色/權限沒必要每次去查,這樣能夠提升效率;

Concurrency:併發,shiro支持多線程應用的併發驗證,即如在一個線程中開啓另外一個線程,能把權限自動傳播過去;

Testing:提供測試支持;

Run As:容許一個用戶僞裝爲另外一個用戶(若是容許)的身份進行訪問;

Remember Me:記住我,這個是很是常見的功能,即一次登陸後,下次再來的話不用登陸了。

 

整體架構:

1) Subject:主體,表明了當前「用戶」。這個用戶不必定是一個具體的人,與當前應用交互的任何東西都是 Subject,如第三方進程,後臺帳戶等,它僅僅意味着「當前跟軟件交互的東西」。 Subjectshiro中是一個接口,接口中定義了不少認證授相關的方法,外部程序經過subject進行認證授,而subject是經過SecurityManager安全管理器進行認證受權 ,咱們能夠把 Subject 認爲是一個門面,SecurityManager 纔是實際的執行者。

2) SecurityManager:安全管理器。對所有的subject進行安全管理,Shiro框架的核心,即全部與安全有關的操做都會與 SecurityManager 交互。經過SecurityManager能夠完成subject的認證、受權等,實質上SecurityManager是經過Authenticator進行認證,經過Authorizer進行受權,經過SessionManager進行會話管理等。  SecurityManager是一個接口,繼承了Authenticator, Authorizer, SessionManager這三個接口

3) Realm:域。Shiro Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager 要驗證用戶身份,那麼它須要從 Realm 獲取相應的用戶進行比較以肯定用戶身份是否合法,也須要從 Realm 獲得用戶相應的角色/權限進行驗證用戶是否能進行操做。咱們能夠把 Realm 當作 DataSource,即安全數據源。

記住一點,Shiro不會去維護用戶、維護權限;這些須要咱們本身去設計/提供;而後經過相應的接口注入給Shiro便可。

也就是說對於咱們而言,最簡單的一個Shiro應用:

1、應用代碼經過Subject來進行認證和受權,而Subject又委託給SecurityManager

2、咱們須要給ShiroSecurityManager注入Realm,從而讓SecurityManager能獲得合法的用戶及其權限進行判斷。

內部結構:

 

1) Subject:主體,能夠看到主體能夠是任何與應用交互的「用戶」。

2) SecurityManager:它是 Shiro 的核心,全部具體的交互都經過 SecurityManager 進行控制。它管理着全部 Subject、且負責進行認證和受權、及會話、緩存的管理。

3) Authenticator:認證器,負責主體認證的,認證就是覈實用戶身份的過程。這個過程常見的例子是「用戶名/密碼」組合。多數用戶再登陸軟件系統時,一般會提供本身的用戶名和密碼,若是儲存在系統裏的密碼與用戶提供的匹配,他們就被認爲經過認證。

4) Authrizer:受權器,或者訪問控制器。它用來決定主體是否有權限進行相應的操做,即控制着用戶能訪問應用中的哪些功能。

5) Realm 能夠有1個或多個Realm,能夠認爲是安全實體數據源,即用於獲取安全實體的;能夠是JDBC實現,也能夠是LDAP實現,或者內存實現等等;由用戶提供;注意:Shiro不知道你的用戶/權限存儲在哪及以何種格式存儲;因此咱們通常在應用中都須要實現本身的Realm

6) SessionManager:即會話管理 ,shiro框架定義了一套會話管理,它不依賴web容器的session,因此shiro能夠使用在非web應用上,也能夠將分佈式應用的會話集中在一點管理,此特性可以使它實現單點登陸。

7) SessionDAO:用於會話的增刪改查。咱們能夠自定義 SessionDAO 的實現,控制session 存儲的位置。如經過 JDBC 寫到數據庫或經過 jedis 寫入 redis 中。另外SessionDAO 中能夠使用 Cache 進行緩存,以提升性能。

8) CacheManager:緩存管理器。它來管理如用戶、角色、權限等的緩存的。由於這些數據基本上不多去改變,放到緩存中後能夠提升訪問的性能。

9) Cryptography:密碼模塊,Shiro 提升了一些常見的加密組件用於如密碼加密/解密的。

 

環境配置:

<dependencies>  

    <dependency>  

        <groupId>junit</groupId>  

        <artifactId>junit</artifactId>  

        <version>4.9</version>  

    </dependency>  

    <dependency>  

        <groupId>commons-logging</groupId>  

        <artifactId>commons-logging</artifactId>  

        <version>1.1.3</version>  

    </dependency>  

    <dependency>  

        <groupId>org.apache.shiro</groupId>  

        <artifactId>shiro-core</artifactId>  

        <version>1.2.2</version>  

    </dependency>  

</dependencies>    

 

身份驗證:

 

驗證流程:

1、首先調用Subject.login(token)進行登陸,其會自動委託給Security Manager,調用以前必須經過SecurityUtils. setSecurityManager()設置;

2SecurityManager負責真正的身份驗證邏輯;它會委託給Authenticator進行身份驗證;

3Authenticator纔是真正的身份驗證者,Shiro API中核心的身份認證入口點,此處能夠自定義插入本身的實現;

4Authenticator可能會委託給相應的AuthenticationStrategy進行多Realm身份驗證,默認ModularRealmAuthenticator會調用AuthenticationStrategy進行多Realm身份驗證;

5Authenticator會把相應的token傳入Realm,從Realm獲取身份驗證信息,若是沒有返回/拋出異常表示身份驗證失敗了。此處能夠配置多個Realm,將按照相應的順序及策略進行訪問。

 

Springboot整合shiro

依賴:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
   <groupId>net.sourceforge.nekohtml</groupId>
   <artifactId>nekohtml</artifactId>
   <version>1.9.22</version>
</dependency>

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.0</version>
</dependency>

 

Shiro提供了完整的企業級會話管理功能,不依賴於底層容器(如web容器tomcat),無論JavaSE仍是JavaEE環境均可以使用,提供了會話管理、會話事件監聽、會話存儲/持久化、容器無關的集羣、失效/過時支持、對Web的透明支持、SSO單點登陸的支持等特性。即直接使用Shiro的會話管理能夠直接替換如Web容器的會話管理。0

Shiro的會話支持不只能夠在普通的JavaSE應用中使用,也能夠在JavaEE應用中使用,如web應用。且使用方式是一致的。 

 

登陸成功後使用Subject.getSession()便可獲取會話;其等價於Subject.getSession(true),即若是當前沒有建立Session對象會建立一個;另外Subject.getSession(false),若是當前沒有建立Session則返回null(不過默認狀況下若是啓用會話存儲功能的話在建立Subject時會主動建立一個Session)。

session.getId():獲取當前會話的惟一標識。

session.getHost():獲取當前Subject的主機地址,該地址是經過HostAuthenticationToken.getHost()提供的。

session.getTimeout();  

session.setTimeout(毫秒);   :獲取/設置當前Session的過時時間;若是不設置默認是會話管理器的全局過時時間。

 session.getStartTimestamp();  

session.getLastAccessTime();  

獲取會話的啓動時間及最後訪問時間;若是是JavaSE應用須要本身按期調用session.touch()去更新最後訪問時間;若是是Web應用,每次進入ShiroFilter都會自動調用session.touch()來更新最後訪問時間。    

session.touch();  

session.stop();   

更新會話最後訪問時間及銷燬會話;當Subject.logout()時會自動調用stop方法來銷燬會話。若是在web中,調用javax.servlet.http.HttpSession. invalidate()也會自動調用Shiro Session.stop方法進行銷燬Shiro的會話。 

 

session.setAttribute("key", "123");  

Assert.assertEquals("123", session.getAttribute("key"));  

session.removeAttribute("key");  

設置/獲取/刪除會話屬性;在整個會話範圍內均可以對這些屬性進行操做。 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

企業級搜索引擎Solr

Solr是企業級全文檢索工具,採用了詞源匹配和切分詞。提供了檢索功能的實現。

爲何使用solr

搜索關鍵字的時候要經過like去數據庫遍歷查詢每一個字,效率很低,並且有些是沒法查詢的。Solr作的事情就是分詞,而後去匹配分詞的詞中是否有你想搜的詞就行了,固然了,爲了提升這種檢索效率和內存節省底層作了很複雜的事情,能夠這麼簡單的認爲,全文搜索這件事情上數據庫是沒法知足的,數據庫自己不能實現分詞效果,而只能使用模糊查詢,可是模糊查詢很是低效,查詢速度比較慢,因爲在實際生活中,通常搜索是用的比較多的,這樣數據庫壓力天然就很大,因此咱們就讓供專業的solr來作搜索功能

全文檢索:

對文檔內容進行分詞,對分詞後的結果建立索引,而後經過對全部進行搜索的方式叫作全文檢索。

全文檢索至關於根據偏旁部首或拼音查字典同樣,在文檔不少狀況查找速度提升。

應用場景:對於數據量大,數據結構不固定的數據採用全文檢索。百度google等搜索引擎,電商網站都在使用全文檢索。

Lucene

Lucenceapache開發的一個全文檢索引擎工具包,他不是一個完整的全文檢索搜索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分着引擎。

Lucene是一個索引與搜索類庫,而不是一個完整的程序。

Solr簡介:

Solrapache的頂級開源項目,採用java開發,solr提供比lucene更豐富的查詢語言,同時實現了可配置,可擴展,並對索引搜索性能進行優化。是一個企業級搜索引擎。

Solr可獨立運行,solr提供了一個管理界面,經過管理界面能夠查詢solr的配置和運行狀況。

對比solrlucene

SolrLucene的本質區別有如下三點:搜索服務器,企業級和管理。Lucene本質上是搜索庫,不是獨立的應用程序,而Solr是。Lucene專一於搜索底層的建設,而Solr專一於企業應用。Lucene不負責支撐搜索服務所必須的管理,而Solr負責。因此說,一句話歸納Solr: SolrLucene面向企業搜索應用的擴展

Solr經過managed-schema的方式來配置Filed,與Lucene相比,這種方式更爲靈活。特別是在團隊開發中,更易於團隊協同做戰。並且solr還提供了Copy FieldDynamic Filed這兩種Lucene沒有的Filed,這使得文檔建模更爲靈活,功能更增強大。

做爲一個Web應用程序,solr能夠輕鬆地部署在JettyTomcatServlet服務器上。

 

Solr特性:

1.基於標準的開放接口:Solr搜索服務器支持經過XMLJSONHTTP查詢和獲取結果。

2.易管理:Solr能夠經過HTML頁面管理,Solr配置經過XML完成。

3.可伸縮性:可以有效地複製到另一個Solr搜索服務器。

4.靈活的插件體系:新功能可以以插件的形式方便的添加到Solr服務器上。

5.強大的數據導入功能:數據庫和其餘結構化數據源如今均可以導入、映射和轉化。

 

Solrj

Solrj是操做solrjava客戶端,提供了增刪改查solr索引的java接口。

SolrJ針對 Solr提供了Rest HTTP接口進行了封裝, SolrJ底層是經過使用httpClient中的方法來完成Solr的操做。

Solrj面對對象的思想,全部搜索條件均以setter屬性的方式設置到其封裝的對象中。可是,實際上仍是經過拼接URL的方式,走http請求的方式再請求Solr服務器。若是採用http直接訪問的方法,咱們必然會用到httpclient請求solr服務器。

依賴:

<dependency>

 <groupId>org.apache.solr</groupId>

 <artifactId>solr-solrj</artifactId>

 <version>7.4.0</version>

</dependency>

 

RabbitMQ(消息隊列):

(1) 先看幾個例子;

2.1異步處理

場景說明:用戶註冊後,須要發註冊郵件和註冊短信,傳統的作法有兩種1.串行的方式;2.並行的方式 
(1)串行方式:將註冊信息寫入數據庫後,發送註冊郵件,再發送註冊短信,以上三個任務所有完成後才返回給客戶端。 這有一個問題是,郵件,短信並非必須的,它只是一個通知,而這種作法讓客戶端等待沒有必要等待的東西. 

(2)並行方式:將註冊信息寫入數據庫後,發送郵件的同時,發送短信,以上三個任務完成後,返回給客戶端,並行的方式能提升處理的時間。 
 
假設三個業務節點分別使用50ms,串行方式使用時間150ms,並行使用時間100ms。雖然並性已經提升的處理時間,可是,前面說過,郵件和短信對我正常的使用網站沒有任何影響,客戶端沒有必要等着其發送完成才顯示註冊成功,英愛是寫入數據庫後就返回. 
(3)消息隊列  
引入消息隊列後,把發送郵件,短信不是必須的業務邏輯異步處理 
 
由此能夠看出,引入消息隊列後,用戶的響應時間就等於寫入數據庫的時間+寫入消息隊列的時間(能夠忽略不計),引入消息隊列後處理後,響應時間是串行的3倍,是並行的2倍。

2.2 應用解耦

場景:雙11是購物狂節,用戶下單後,訂單系統須要通知庫存系統,傳統的作法就是訂單系統調用庫存系統的接口. 
 
這種作法有一個缺點:

  • 當庫存系統出現故障時,訂單就會失敗。(這樣馬雲將少賺好多好多錢^ ^)

訂單系統和庫存系統高耦合
引入消息隊列 

訂單系統:用戶下單後,訂單系統完成持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功。

庫存系統:訂閱下單的消息,獲取下單消息,進行庫操做。 
就算庫存系統出現故障,消息隊列也能保證消息的可靠投遞,不會致使消息丟失(馬雲這下高興了).

 

庫存不夠的狀況:暫不討論

文檔:

關於秒殺的系統架構優化思路 http://www.cnblogs.com/chenpingzhao/p/6195788.html

淺談庫存扣減相關問題 https://blog.csdn.net/xiongyouqiang/article/details/79388120

2.3流量削峯

流量削峯通常在秒殺活動中應用普遍 
場景:秒殺活動,通常會由於流量過大,致使應用掛掉,爲了解決這個問題,通常在應用前端加入消息隊列。 
做用
1.能夠控制活動人數,超過此必定閥值的訂單直接丟棄(我爲何秒殺一次都沒有成功過呢^^) 
2.能夠緩解短期的高流量壓垮應用(應用程序按本身的最大處理能力獲取訂單) 
 
1.用戶的請求,服務器收到以後,首先寫入消息隊列,加入消息隊列長度超過最大值,則直接拋棄用戶請求或跳轉到錯誤頁面. 庫存不夠的狀況
2.秒殺業務根據消息隊列中的請求信息,再作後續處理.

 

別啥固定式使用場景了,說的透徹一點,他就是服務器之間通訊的,前面博文中提到的Httpclient也能夠作到,可是這個相對於其餘通訊在中間作了一箇中間倉庫。

  好處1:下降了兩臺服務器之間的耦合,哪怕是一臺服務器掛了,另一臺服務器也不會報錯或者休克,反正他監聽的是MQ,只要服務器恢復再從新連上MQ發送消息,監聽服務器就能再次接收。

  好處2MQ做爲一個倉庫,自己就提供了很是強大的功能,例如再也不是簡單的一對一功能,還能一對多,多對一,本身腦補保險箱場景,只要有特定的密碼,誰都能存,誰都能取。也就是說能實現羣發消息和以此衍生的功能。   

 

  好處3:如今廣泛化的持久化功能,當MQ掛掉能夠存儲在磁盤等下重啓恢復。(須要設置)

 

 

這裏提到了消息隊列,

什麼是消息隊列?

一、什麼是消息隊列?

《百度百科》

(1) 「消息隊列」(Message Queue)是在消息的傳輸過程當中保存消息的容器。

(2) 「消息」是在兩臺計算機間傳送的數據單位。消息能夠很是簡單,例如只包含文本字符串;也能夠更復雜,可能包含嵌入對象。

(3) 消息被髮送到隊列中。「消息隊列」是在消息的傳輸過程當中保存消息的容器。消息隊列管理器在將消息從它的源中繼到它的目標時充當中間人。隊列的主要目的是提供路由並保證消息的傳遞;若是發送消息時接收者不可用,消息隊列會保留消息,直到能夠成功地傳遞它。

(4) 消息隊列就是一個消息的鏈表。能夠把消息看做一個記錄,具備特定的格式以及特定的優先級。對消息隊列有寫權限的進程能夠向消息隊列中按照必定的規則添加新消息;對消息隊列有讀權限的進程則能夠從消息隊列中讀走消息。消息隊列是隨內核持續的。 -

 

 

什麼是MQ

 MQ全稱爲Message Queue, 消息隊列(MQ)是一種應用程序對應用程序的通訊方法。MQ是消費-生產者模型的一個典型的表明,一端往消息隊列中不斷寫入消息,而另外一端則能夠讀取隊列中的消息。

 

 

Jms

http://www.javashuo.com/article/p-koiwezog-dh.html

 

消息隊列:隊列,先進先出,數據結構,放消息的隊列。

 

 

二、爲何會須要消息隊列?

(1) 主要緣由是因爲在高併發環境下,因爲來不及同步處理,請求每每會發生堵塞,好比說,大量的insertupdate之類的請求同時到達MySQL,直接致使無數的行鎖表鎖,甚至最後請求會堆積過多,從而觸發too many connections錯誤。經過使用消息隊列,咱們能夠異步處理請求,從而緩解系統的壓力。

(2) 消息隊列使用消息將應用程序鏈接起來。這些消息經過像RabbitMQ這樣的消息代理服務器在應用程序之間路由,就像在應用程序中間放一個郵局。專一於程序之間的 消息通訊。

三、

消息隊列的應用場景:

異步處理

應用解耦

流量削峯

 

四、什麼是RabbitMQ

(1)  RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:PythonRuby.NETJavaJMSCPHPActionScriptXMPPSTOMP等,支持AJAX。用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。

(2) Erlang語言:是一種通用的面向併發的編程語言,具備併發性,分佈式、健壯性等特色,擅長處理併發。

 

(3) AMQP協議(Advanced Message Queuing Protocol

① AMQP,即Advanced Message Queuing Protocol,高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。消息中間件主要用於組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。 AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。通信的時候能夠使用TCP或者UDP,經常使用的仍是TCP。不限編程語言及系統。(TCPUDP屬於傳輸層(保證傳輸質量))

 

AMQP消息能以一對多的廣播方式進行路由,也能夠選擇一對一的方式路由。

② 

1) 一對一

③ 

1) 一對多

(4) RabbitMQ是一個在AMQP基礎上完成的,可複用的企業消息系統。

 

 

RabbitMQ系統架構:

 

 

五、概念

(1) 生產者(producer)建立消息.而後發佈(發送)到代理服務器(RabbitMQ)

(2) 什麼是消息呢?消息包含兩部份內容:有效載荷(payload)和標籤(label),有效載荷就是你想要傳輸的數據。它能夠是任何內容.一個 JSON數組或者是你最喜歡的任何東西,RabbitMQ不會在乎這些。標籤:它描述了有效載荷.而且 RabbitMQ用它來決定誰將得到消息的拷貝。

(3) 舉例來講,不一樣於 TCP協議的是.當你明確指定發送方和接收方時, AMQP只會用標答表述這條消息(一個交換器的名稱和可選的主題標記),而後把消息交由 RabbitRabbit會根據標籤把消息發送給感興趣的接收方。這種通訊方式是一種「發後即忘"fire-and-forget)的單向方式。眼下你只須要知道生產者會建立消息並設置標籤(見圖2)

 

(4) 消費者:消費者很容易理解。它們鏈接到代理服務器上,並訂閱到隊列( queue)上。把消息隊列想象成一個具名郵箱。每當消息到達特定的郵箱時, RabbitMQ會將其發送給其中一個訂閱的/監聽的消費者。當消費者接收到消息時,它只獲得消息的一部分:有效載荷。在消息路由過程當中,消息的標籤並無隨有效載荷一同傳遞。 RabbitMQ甚至不會告訴你是誰生產/發送了消息。就比如你拿起信件時,卻發現全部的信封都是空白的。想要知道這條消息是不是從 Millie姑媽發來的惟一方式是她在信裏簽了名。同理,若是須要明確知道是誰生產的 AMQP消息的話,就要看生產者是否把發送方信息放人有效載荷中。

 

 

 

整個過程其實很簡單:生產者建立消息,消費者接收這些消息。你的應用程序能夠做爲生產者,向其餘應用程序發送消息。或者做爲一個消費者,接收消息。也能夠在二者之間進行切換。不過在此以前,它必須先創建一條信道( channel)等等!什麼是信道呢?

 

信道(channel)

你必須首先鏈接到 Rabbit,才能消費或者發佈消息。你在應用程序和 Rabbit代理服務器之間建立一條 TCP鏈接。一旦 TCP鏈接打開(你經過了認證),應用程序就能夠建立一條 AMQP信道。信道是創建在「真實的" TCP鏈接內的虛擬鏈接。 AMQP命令都是經過信道發送出去的。每條信道都會被指派一個惟一 ID(AMQP庫會幫你記住 ID的)a不管是發佈消息、訂閱隊列或是接收消息,這些動做都是經過信道完成的。你也許會問爲何咱們須要信道呢?爲何不直接經過 TCP鏈接發送 AMQP命令呢7主要緣由在於對操做系統來講創建和銷燬 TCP會話是很是昂貴的開銷。假設應用程序從隊列消費消息,並根據服務需求合理調度線程。假設你只進行 TCP鏈接,那麼每一個線程都須要自行鏈接到 Rabbito也就是說高峯期有每秒成百上千條鏈接。這不只形成 TCP鏈接的巨大浪費,並且操做系統每秒也就只能創建這點數量的鏈接勹所以,你可能很快就碰到性能瓶頸了。若是咱們爲全部線程只使用一條 TCP鏈接以知足性能方面的要求,但又能確保每一個線程的私密性,就像擁有獨立鏈接同樣的話,那不就很是完美嗎?這就是要引人信道概念的緣由。線程啓動後,會在現成的鏈接上建立一條信道,也就得到了鏈接到 Rabbit上的私密通訊路徑,而不會給操做系統的 TCP棧形成額外負擔,如圖2.2所示。所以,你能夠每秒成百上千次地建立信道而不會影響操做系統。在一條 TCP鏈接上建立多少條信道是沒有限制的。把它想象成一束光纖電纜就能夠了。

RabbitMQ建議客戶端線程之間不要共用Channel,至少要保證共用Channel的線程發送消息必須是串行的,可是建議儘可能共用Connection.

 

Connection:鏈接,對於RabbitMQ而言,其實就是一個位於客戶端和Broker之間的TCP鏈接。

 

 

AMQP元素:交換器 隊列 綁定

 

 

生產者吧消息發送到交換機上,消息最終到達隊列,並被消費者接受。

綁定決定了消息如何從路由器路由到特定的隊列。

隊列:

消息就像具名郵箱,消息最終到達隊列中並等待消費。

從消息隊列中接受消息的方式:

1)經過 AMQP的 basic.consume命令訂閱。這樣作會將信道置爲接收模式,直到取消對隊列的訂閱爲止。訂閱了消息後,消費者在消費(或者拒絕)最近接收的那條消息後,就能從隊列中(可用的)自動接收下一條消息。若是消費者處理隊列消息,而且/或者須要在消息一到達隊列時就自動接收的話,你應該使用basic.consume

2)某些時候,你只想從隊列得到單條消息而不是持續訂閱。向隊列請求單條消息是經過 AMQP的 basic.get乜命令實現的。這樣作可讓消費者接收隊列中的下一條消息。若是要得到更多消息的話,須要再次發送 basic.get命令。你不該該將basic.get放在一個循環裏來替代basic.get。由於這樣作會影響 Rabbit的性能。大體上講, basic-get命令會訂閱消息,得到單條消息,而後取消訂閱。消費者理應始終使用 basic.consume來實現高吞吐量。

 

channel.basicConsume(TASK_QUEUE_NAME, false, consumer);

channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

具體看代碼。

 

關於消息去向的討論:

一、消息到無人訂閱的隊列

消息會一直在隊列中等待,一旦有消費者訂閱該隊列,隊列上的消息就會發給消費者。

2、多個消費者訂閱同一個消息隊列

循環發送。

假設有Query隊列,消費者A和消費者B訂閱到了Query隊列,當消息到達query隊列時:

(1)消息massage-a到達query

(2)RabbitMQmassage-a消息發送給A

(3)A確認收到了消息massage-a

(4)RabbitMQmassage-aquery中刪除

(5)消息message-b到達query隊列

(6)RabbitMQmassage-b發送給B

(7)B確認收到了消息massage-b

(8)RabbitMQmassage-bquery中刪除

 

 

消息的確認模式:

自動確認:

手動確認:

消費者監聽隊列的時候,有一個參數,若是爲flase 則爲手動模式。True是自動模式。

False必須作反饋。

 

 

 

消費者接受到消息必須進行確認。

消費者接收到的每一條消息都必須進行確認。消費者必須經過 AMQP的basic.ack命令顯式地向 RabbitMQ發送一個確認,或者在訂閱到隊列的時候就將auto_ack參數設置爲 true當設置auto_ack時,一旦消費者接收消息, RabbitMQ會自動視其確認了消息。須要記住的是,消費者對消息的確認和告訴生產者消息已經被接收了這兩件事絕不相關。所以,消費者經過確認命令告訴 RabbitMQ它已經正確地接收了消息,同時 RabbitMQ才能安全地把消息從隊列中刪除。

若是消費者收到一條消息,而後確認以前從 Rabbit斷開鏈接(或者從隊列上取消訂閱), RabbitMQ會認爲這條消息沒有分發,而後從新分發給下一個訂閱的消費者。若是你的應用程序崩潰了,這樣作能夠確保消息會被髮送給另外一個消費者進行處理。

另外一方面,若是應用程序有 bug而忘記確認消息的話, Rabbit將不會給該消費者發送更多消息了。這是由於在上一條消息被確認以前, Rabbit會認爲這個消費者並無準備好接收下一條消息。你能夠好好利用這一點。若是處理消息內容很是耗時,則你的應用程序能夠延遲確認該消息,直到消息處理完成。這樣能夠防止 Rabbit持續不斷的消息涌向你的應用而致使過載。

 

在收到消息後,若是你想要明確拒絕而不是確認收到該消息的話,該如何呢?舉例來講,假設在處理消息的時候你遇到了不可恢復的錯誤,可是因爲硬件問題,隻影響到當前的消費者(這就是一個很好的示例,直到消息處理完成以前,你毫不能進行確認)。只要消息還沒有確認,則你有如下兩個選擇:

 

0)把消費者從 RabbitMQ服務器斷開鏈接。這會致使 RabbitMQ自動從新把消息人隊併發送給另外一個消費者。這樣作的好處是全部的 RabbitMQ版本都支持。缺點是,這樣鏈接/斷開鏈接的方式會額外增長 RabbitMQ的負擔(若是消費者在處理每條消息時都遇到錯誤的話,會致使潛在的重大負荷)。

2)若是你正使用 RabbitMQ2.0.0或者更新的版本,那就使用 AMQP的basic.reject命令。顧名思義:basic.reject容許消費者拒絕 RabbitMQ發送的消息。若是把 reject命令的 requeue參數設置成 true的話, RabbitMQ會將消息從新發送給下一個訂閱的消費者。若是設置成 false的話, RabbitMQ當即會把消息從隊列中移除,而不會把它發送給新的消費者。你也能夠經過對消息確認的方式來簡單地忽略該消息(這種忽略消息的方式的優點在於全部版本的 RabbitMQ都支持)。若是你檢測到一條格式錯誤的消息而任何一個消費者都沒法處理的時候,這樣作就十分有用。

 

死信隊列:

利用死信隊列 實現定時發送

 

臨時隊列:斷開鏈接就會刪除

 

 

交換機(exchange)和綁定(binding):

 

就像在前幾節看到的那樣,你想讓消費者從隊列中獲取消息。如今的問題是,消息是如何到達隊列的呢?讓咱們來認識一下 AMQP的交換器和綁定。當你想要將消息投遞到隊列時,你經過把消息發送給交換器來完成。而後,根據肯定的規則, RabbitMQ將會決定消息該投遞到哪一個隊列。這些規則被稱做路由鍵 routing key)。隊列經過路由鍵綁定到交換器。當你把消息發送到代理服務器時,消息將擁有一個路由鍵一一一即使是空的—RabbitMQ也會將其和綁定使用的路由鍵進行匹配。若是相匹配的話,那麼消息將會投遞到該隊列。若是路由的消息不匹配任何綁定模式的話,消息將進人「黑洞"

 

 

消息會根據路由鍵從交換機路由到隊列,如何處理投遞到多個隊列的狀況呢?

 

消息有路由鍵,隊列有匹配規則。

 

 

不一樣類型的交換機發揮了做用:

交換機類型:

Header(頭)

Header交換器容許你匹配AMQP消息的header而非路由鍵,除此以外,header交換器和direct交換機徹底一致,但性能會差不少,所以他並不實用,並且幾乎用不到了。

 

Direct(直接)

Direct Exchange – 處理路由鍵。須要將一個隊列綁定到交換機上,要求該消息與一個特定的路由鍵徹底匹配。這是一個完整的匹配。若是一個隊列綁定到該交換機上要求路由鍵 「dog」,則只有被標記爲「dog」的消息才被轉發,不會轉發dog.puppy,也不會轉發dog.guard,只會轉發dog 

 

 

 

Fanout展開

 

Fanout Exchange – 不處理路由鍵。你只須要簡單的將隊列綁定到交換機上。一個發送到交換機的消息都會被轉發到與該交換機綁定的全部隊列上。很像子網廣播,每臺子網內的主機都得到了一份複製的消息。Fanout交換機轉發消息是最快的。 

 

 

 

Topic(主題)

Topic Exchange 將路由鍵和某模式進行匹配。此時隊列須要綁定要一個模式上。符號「#」匹配一個或多個詞,符號「*」匹配很少很多一個詞。所以「audit.#」可以匹配到「audit.irs.corporate」,可是「audit.*」 只會匹配到「audit.irs」。我在RedHat的朋友作了一張不 
 

 

 

 

 

名稱

默認的預先定義exchange名字

做用描述

Direct exchange

(Empty string) and amq.direct

根據Binding指定的Routing Key,將符合Key的消息發送到BindingQueue

Fanout exchange

amq.fanout

將同一個message發送到全部同該Exchange bingdingqueue

Topic exchange

amq.topic

根據Binding指定的Routing KeyExchangekey進行模式匹配後路由到相應的Queue,模式匹配時符號」#」匹配一個或多個詞,符號」*」匹配正好一個詞。

Headers exchange

amq.match (and amq.headers in RabbitMQ)

direct exchange相似,不一樣之處是再也不使用Routing Key路由,而是使用headersmessage attributes)進行匹配路由到指定Queue

 

 

 

簡單的說:

exchange」(交換器)接收發布應用程序發送的消息,並根據必定的規則將這些消息路由到「消息隊列」。

message queue」(消息隊列)存儲消息,直到這些消息被消費者安全處理完爲止。

binding」(綁定)定義了exchangemessage queue之間的關聯,提供路由規則。

 

 

 

 

虛擬主機(vhost):

每個 RabbitMQ服務器都能建立虛擬消息服務器,咱們稱之爲虛擬主機( vhost)。每個 vhost本質上是一個 mini版的 RabbitMQ服務器,擁有本身的隊列、交換器和綁定一一更重要的是,它擁有本身的權限機制。這使得你可以安全地使用一個 RabbitMQ服務器來服務衆多應用程序,而不用擔憂你的 Sudoku(數獨)應用可能會刪除狗狗防丟跟蹤器正在使用的隊列。 vhost之於 Rabbit就像虛擬機之於物理服務器同樣:它們經過在各個實例間提供邏輯上分離,容許你爲不一樣應用程序安全保密地運行數據。這頗有用,它既能將同一 Rabbit的衆多客戶區分開來,又能夠避免隊列和交換器的命名衝突。不然你可能不得不運行多個 Rabbit,並忍受隨之而來頭疼的管理問題。相反,你能夠只運行一個 Rabbit,而後按需啓動或關閉 vhost。

 

 

 

 

Broker::它提供一種傳輸服務,它的角色就是維護一條從生產者到消費者的路線,保證數據能按照指定的方式進行傳輸,簡單來講就是消息隊列服務器實體

 

 

 

消息持久化:

持久化隊列,非持久化隊列,

費持久化 速度快

 

 

隊列類型:

簡單隊列:

 

代碼

分析說明

閱後即焚

監聽程序 若是沒有 會阻塞阻塞。

Work模式:

 

一個生產者,多個消費者

消息是被一個消費者獲取(爭搶)

一個快,一個慢,結果拿到的結果是同樣的

應該是快的拿到的多

輪訓。

集羣的時候

 

訂閱模式:

 

 

 

 

前臺系統 例如 搜索系統 或者 消費系統  本身建立一個隊列,而後把隊列綁定到交換機,就能夠建立了

沒有耦合度了

某些系統不須要通知了,只要解除隊列與交換機的綁定便可。

 

若是隻是把數據發送到交換機,沒有隊列綁定交換價,那麼消息會丟失。

交換機咩有存儲消息的能力,只作交換,不作存儲。

發一個消息,能夠通知多個消費者

 

路由模式和 交換機模式 訂閱模式 實際上是同樣的 只是交換機的類型不同。

 

路由模式:

 

有選擇的接收消息

路由模式 ,綁定多個路由鍵,再寫一個就行

 

先啓動消費者 會報錯 由於沒有 交換機。

 

通配符模式:

 

修改路由鍵:

將路由鍵和某模式進行匹配。此時隊列須要綁定要一個模式上。符號「#」匹配一個或多個詞,符號「*」匹配很少很多一個詞。所以「audit.#」可以匹配到「audit.irs.corporate」,可是「audit.*」 只會匹配到「audit.irs」

 

 

 

後臺系統的配置文件

 

 

六、RabbitMQ集羣

七、RabbitMQ集羣處理問題

八、RabbitMQ鏡像隊列

九、RabbitMQ恢復故障

十、RabbitMQ Management插件 web

 

消息隊列的安裝:linux+windows

 

RabbitMQ的用戶類型

 

2 使用了消息隊列會有什麼缺點?
分析:一個使用了MQ的項目,若是連這個問題都沒有考慮過,就把MQ引進去了,那就給本身的項目帶來了風險。咱們引入一個技術,要對這個技術的弊端有充分的認識,才能作好預防。要記住,不要給公司挖坑!
回答:回答也很容易,從如下兩個個角度來答

系統可用性下降:你想啊,原本其餘系統只要運行好好的,那你的系統就是正常的。如今你非要加個消息隊列進去,那消息隊列掛了,你的系統不是呵呵了。所以,系統可用性下降
系統複雜性增長:要多考慮不少方面的問題,好比一致性問題、如何保證消息不被重複消費,如何保證保證消息可靠傳輸。所以,須要考慮的東西更多,系統複雜性增大。
可是,咱們該用仍是要用的。

 

十一、消息隊列比較 

三、消息隊列如何選型?
一、ActiveMQ 
Apache出品。號稱最流行的,能力強勁的開源消息總線。 
特色有兼容常見J2EE服務器,支持Spring,Ajax

二、RabbitMQ 
流行的、開源的消息隊列。用AMQP(高級消息隊列協議)標準實現。支持多種客戶端,包括.Net,Java,PHP。 
用於分佈式系統中存儲轉發消息。易用性、擴展性、高可用性等方面表現不俗。

三、ZeroMQ 
號稱史上最快的消息隊列,實際相似於Socket的一系列接口。普通Socket是端到端(1:1)的關係,而ZMQ是N:M。ZMQ屏蔽了各類鏈接的細節,讓網絡編程更簡單。 
用於node與node間的通訊。node能夠是主機或進程。

四、Kafka 
高吞吐量的分佈式發佈訂閱消息系統。 
持久化 
高吞吐 
集羣、分區 
支持Hadoop

 

 

綜合上面的材料得出如下兩點:
(1)中小型軟件公司,建議選RabbitMQ.一方面,erlang語言天生具有高併發的特性,並且他的管理界面用起來十分方便。正所謂,成也蕭何,敗也蕭何!他的弊端也在這裏,雖然RabbitMQ是開源的,然而國內有幾個能定製化開發erlang的程序員呢?所幸,RabbitMQ的社區十分活躍,能夠解決開發過程當中遇到的bug,這點對於中小型公司來講十分重要。

不考慮rocketmq和kafka的緣由是,一方面中小型軟件公司不如互聯網公司,數據量沒那麼大,選消息中間件,應首選功能比較完備的,因此kafka排除。

不考慮rocketmq的緣由是,rocketmq是阿里出品,若是阿里放棄維護rocketmq,中小型公司通常抽不出人來進行rocketmq的定製化開發,所以不推薦。

(2)大型軟件公司,根據具體使用在rocketMq和kafka之間二選一。一方面,大型軟件公司,具有足夠的資金搭建分佈式環境,也具有足夠大的數據量。

針對rocketMQ,大型軟件公司也能夠抽出人手對rocketMQ進行定製化開發,畢竟國內有能力改JAVA源碼的人,仍是至關多的。至於kafka,根據業務場景選擇,若是有日誌採集功能,確定是首選kafka了。具體該選哪一個,看使用場景。

 

4 如何保證消息隊列是高可用的?

普通集羣和鏡像集羣模式

5 如何保證消息不被重複消費?

分析:這個問題其實換一種問法就是,如何保證消息隊列的冪等性?這個問題能夠認爲是消息隊列領域的基本問題。換句話來講,是在考察你的設計能力,這個問題的回答能夠根據具體的業務場景來答,沒有固定的答案。

回答:先來講一下爲何會形成重複消費?

其實不管是那種消息隊列,形成重複消費緣由其實都是相似的。正常狀況下,消費者在消費消息時候,消費完畢後,會發送一個確認信息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除。只是不一樣的消息隊列發送的確認信息形式不一樣,例如RabbitMQ是發送一個ACK確認消息,RocketMQ是返回一個CONSUME_SUCCESS成功標誌,kafka實際上有個offset的概念,簡單說一下(若是還不懂,出門找一個kafka入門到精通教程),就是每個消息都有一個offset,kafka消費過消息後,須要提交offset,讓消息隊列知道本身已經消費過了。那形成重複消費的緣由?,就是由於網絡傳輸等等故障,確認信息沒有傳送到消息隊列,致使消息隊列不知道本身已經消費過該消息了,再次將該消息分發給其餘的消費者。

如何解決?這個問題針對業務場景來答分如下幾點

  (1)好比,你拿到這個消息作數據庫的insert操做。那就容易了,給這個消息作一個惟一主鍵,那麼就算出現重複消費的狀況,就會致使主鍵衝突,避免數據庫出現髒數據。
  (2)再好比,你拿到這個消息作redis的set的操做,那就容易了,不用解決,由於你不管set幾回結果都是同樣的,set操做原本就算冪等操做。
  (3)若是上面兩種狀況還不行,上大招。準備一個第三方介質,來作消費記錄。以redis爲例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄便可。

6 如何保證消費的可靠性傳輸?
分析:咱們在使用消息隊列的過程當中,應該作到消息不能多消費,也不能少消費。若是沒法作到可靠性傳輸,可能給公司帶來千萬級別的財產損失。一樣的,若是可靠性傳輸在使用過程當中,沒有考慮到,這不是給公司挖坑麼,你能夠拍拍屁股走了,公司損失的錢,誰承擔。仍是那句話,認真對待每個項目,不要給公司挖坑。

回答:其實這個可靠性傳輸,每種MQ都要從三個角度來分析:生產者弄丟數據、消息隊列弄丟數據、消費者弄丟數據

RabbitMQ

(1)生產者丟數據
從生產者弄丟數據這個角度來看,RabbitMQ提供transaction和confirm模式來確保生產者不丟消息。
transaction機制就是說,發送消息前,開啓事務(channel.txSelect()),而後發送消息,若是發送過程當中出現什麼異常,事物就會回滾(channel.txRollback()),若是發送成功則提交事物(channel.txCommit())。

然而缺點就是吞吐量降低了。所以,按照博主的經驗,生產上用confirm模式的居多。一旦channel進入confirm模式,全部在該信道上面發佈的消息都將會被指派一個惟一的ID(從1開始),一旦消息被投遞到全部匹配的隊列以後,rabbitMQ就會發送一個Ack給生產者(包含消息的惟一ID),這就使得生產者知道消息已經正確到達目的隊列了.若是rabiitMQ沒能處理該消息,則會發送一個Nack消息給你,你能夠進行重試操做。處理Ack和Nack的代碼以下所示(說好不上代碼的,偷偷上了):

channel.addConfirmListener(new ConfirmListener() { 
@Override 
public void handleNack(long deliveryTag, boolean multiple) throws IOException { 
System.out.println("nack: deliveryTag = "+deliveryTag+" multiple: "+multiple); 

@Override 
public void handleAck(long deliveryTag, boolean multiple) throws IOException { 
System.out.println("ack: deliveryTag = "+deliveryTag+" multiple: "+multiple); 

}); 
(2)消息隊列丟數據
處理消息隊列丟數據的狀況,通常是開啓持久化磁盤的配置。這個持久化配置能夠和confirm機制配合使用,你能夠在消息持久化磁盤後,再給生產者發送一個Ack信號。這樣,若是消息持久化磁盤以前,rabbitMQ陣亡了,那麼生產者收不到Ack信號,生產者會自動重發。

那麼如何持久化呢,這裏順便說一下吧,其實也很容易,就下面兩步

一、將queue的持久化標識durable設置爲true,則表明是一個持久的隊列
二、發送消息的時候將deliveryMode=2

這樣設置之後,rabbitMQ就算掛了,重啓後也能恢復數據

(3)消費者丟數據
消費者丟數據通常是由於採用了自動確認消息模式。這種模式下,消費者會自動確認收到信息。這時rahbitMQ會當即將消息刪除,這種狀況下若是消費者出現異常而沒能處理該消息,就會丟失該消息。
至於解決方案,採用手動確認消息便可。

7 如何保證消息的順序性?
分析:其實並不是全部的公司都有這種業務需求,可是仍是對這個問題要有所複習。

回答:針對這個問題,經過某種算法,將須要保持前後順序的消息放到同一個消息隊列中(kafka中就是partition,rabbitMq中就是queue)。而後只用一個消費者去消費該隊列。

有的人會問:那若是爲了吞吐量,有多個消費者去消費怎麼辦?

這個問題,沒有固定回答的套路。好比咱們有一個微博的操做,發微博、寫評論、刪除微博,這三個異步操做。若是是這樣一個業務場景,那隻要重試就行。好比你一個消費者先執行了寫評論的操做,可是這時候,微博都還沒發,寫評論必定是失敗的,等一段時間。等另外一個消費者,先執行寫評論的操做後,再執行,就能夠成功。

總之,針對這個問題,個人觀點是保證入隊有序就行,出隊之後的順序交給消費者本身去保證,沒有固定套路。

 

 

RabbitMQ知識詳解:

https://blog.csdn.net/dreamchasering/article/details/77653512

 

4.任務分發機制

4.1Round-robin dispathching循環分發

RabbbitMQ的分發機制很是適合擴展,並且它是專門爲併發程序設計的,若是如今load加劇,那麼只須要建立更多的Consumer來進行任務處理。

4.2Message acknowledgment消息確認

爲了保證數據不被丟失,RabbitMQ支持消息確認機制,爲了保證數據能被正確處理而不只僅是被Consumer收到,那麼咱們不能採用no-ack,而應該是在處理完數據以後發送ack. 
在處理完數據以後發送ack,就是告訴RabbitMQ數據已經被接收,處理完成,RabbitMQ能夠安全的刪除它了. 
若是Consumer退出了可是沒有發送ack,那麼RabbitMQ就會把這個Message發送到下一個Consumer,這樣就保證在Consumer異常退出狀況下數據也不會丟失. 
RabbitMQ它沒有用到超時機制.RabbitMQ僅僅經過Consumer的鏈接中斷來確認該Message並無正確處理,也就是說RabbitMQ給了Consumer足夠長的時間作數據處理。 
若是忘記ack,那麼當Consumer退出時,Mesage會從新分發,而後RabbitMQ會佔用愈來愈多的內存.

5.Message durability消息持久化

要持久化隊列queue的持久化須要在聲明時指定durable=True; 
這裏要注意,隊列的名字必定要是Broker中不存在的,否則不能改變此隊列的任何屬性. 
隊列和交換機有一個建立時候指定的標誌durable,durable的惟一含義就是具備這個標誌的隊列和交換機會在重啓以後從新創建,它不表示說在隊列中的消息會在重啓後恢復 
消息持久化包括3部分 
1. exchange持久化,在聲明時指定durable => true

hannel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);//聲明消息隊列,且爲可持久化的

  • 1

2.queue持久化,在聲明時指定durable => true

channel.QueueDeclare(QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null);//聲明消息隊列,且爲可持久化的

  • 1

3.消息持久化,在投遞時指定delivery_mode => 2(1是非持久化).

channel.basicPublish("", queueName, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());  

  • 1

若是exchange和queue都是持久化的,那麼它們之間的binding也是持久化的,若是exchange和queue二者之間有一個持久化,一個非持久化,則不容許創建綁定. 
注意:一旦建立了隊列和交換機,就不能修改其標誌了,例如,建立了一個non-durable的隊列,而後想把它改變成durable的,惟一的辦法就是刪除這個隊列而後重現建立。

6.Fair dispath 公平分發

你可能也注意到了,分發機制不是那麼優雅,默認狀態下,RabbitMQ將第n個Message分發給第n個Consumer。n是取餘後的,它無論Consumer是否還有unacked Message,只是按照這個默認的機制進行分發. 
那麼若是有個Consumer工做比較重,那麼就會致使有的Consumer基本沒事可作,有的Consumer卻毫無休息的機會,那麼,Rabbit是如何處理這種問題呢? 
 
經過basic.qos方法設置prefetch_count=1,這樣RabbitMQ就會使得每一個Consumer在同一個時間點最多處理一個Message,換句話說,在接收到該Consumer的ack前,它不會將新的Message分發給它

channel.basic_qos(prefetch_count=1)

  • 1

注意,這種方法可能會致使queue滿。固然,這種狀況下你可能須要添加更多的Consumer,或者建立更多的virtualHost來細化你的設計。

7.分發到多個Consumer

7.1Exchange

先來溫習如下交換機路由的幾種類型
Direct Exchange:直接匹配,經過Exchange名稱+RountingKey來發送與接收消息. 
Fanout Exchange:廣播訂閱,向全部的消費者發佈消息,可是隻有消費者將隊列綁定到該路由器才能收到消息,忽略Routing Key. 
Topic Exchange:主題匹配訂閱,這裏的主題指的是RoutingKey,RoutingKey能夠採用通配符,如:*或#,RoutingKey命名採用.來分隔多個詞,只有消息這將隊列綁定到該路由器且指定RoutingKey符合匹配規則時才能收到消息; 
Headers Exchange:消息頭訂閱,消息發佈前,爲消息定義一個或多個鍵值對的消息頭,而後消費者接收消息同時須要定義相似的鍵值對請求頭:(如:x-mactch=all或者x_match=any),只有請求頭與消息頭匹配,才能接收消息,忽略RoutingKey. 
默認的exchange:若是用空字符串去聲明一個exchange,那麼系統就會使用」amq.direct」這個exchange,咱們建立一個queue時,默認的都會有一個和新建queue同名的routingKey綁定到這個默認的exchange上去

channel.BasicPublish("", "TaskQueue", properties, bytes);

  • 1

由於在第一個參數選擇了默認的exchange,而咱們申明的隊列叫TaskQueue,因此默認的,它在新建一個也叫TaskQueue的routingKey,並綁定在默認的exchange上,致使了咱們能夠在第二個參數routingKey中寫TaskQueue,這樣它就會找到定義的同名的queue,並把消息放進去。 
若是有兩個接收程序都是用了同一個的queue和相同的routingKey去綁定direct exchange的話,分發的行爲是負載均衡的,也就是說第一個是程序1收到,第二個是程序2收到,以此類推。 
若是有兩個接收程序用了各自的queue,但使用相同的routingKey去綁定direct exchange的話,分發的行爲是複製的,也就是說每一個程序都會收到這個消息的副本。行爲至關於fanout類型的exchange。 
下面詳細來講:

8.消息序列化

RabbitMQ使用ProtoBuf序列化消息,它可做爲RabbitMQ的Message的數據格式進行傳輸,因爲是結構化的數據,這樣就極大的方便了Consumer的數據高效處理,固然也能夠使用XML,與XML相比,ProtoBuf有如下優點: 
1.簡單 
2.size小了3-10倍 
3.速度快了20-100倍 
4.易於編程 
6.減小了語義的歧義. 
ProtoBuf具備速度和空間的優點,使得它如今應用很是普遍

 

 

rabbitMQ教程(三)一篇文章看懂rabbitMQ

1、rabbitMQ是什麼:

  RabbitMQ,遵循AMQP協議,由內在高併發的erlanng語言開發,用在實時的對可靠性要求比較高的消息傳遞上。

  學過websocket的來理解rabbitMQ應該是很是簡單的了,websocket是基於服務器和頁面之間的通訊協議,一次握手,屢次通訊。 而rabbitMQ就像是服務器之間的socket,一個服務器連上MQ監聽,而另外一個服務器只要經過MQ發送消息就能被監聽服務器所接收。

  可是MQsocket仍是有區別的,socket至關因而頁面直接監聽服務器。而MQ就是服務器之間的中轉站,例如郵箱,一我的投遞信件給郵箱,另外一我的去郵箱取,他們中間沒有直接的關係,因此耦合度相比socket小了不少。

  

上圖是最簡單的MQ關係,生產者-MQ隊列-消費者   

 5、一些細節說明

       MQ不能進行批量的消息處理,你看到的傳輸再多也只是消息被一條一條的存入隊列,消費者從隊列中一條一條的取出。這kafKa有區別,因此在效率上比不上kafKa,可是MQ主打的是穩定。

  每次消費者取出消息時會通知隊列,我拿到了,當隊列接收到這條消息,就會把消息刪除,這是默認的ACK機制。若是在接收消息以後,消費者掛掉,或者任何狀況沒有返回ack,隊列中這條消息將不會刪除,能夠一直存着,等待其餘消費者來取。    注意,可是若是設置不返回ack,在不斷的發送消息到隊列又不刪除,會致使MQ倉庫boom~~~~

 

 

 

 

關於秒殺的系統架構優化思路 http://www.cnblogs.com/chenpingzhao/p/6195788.html

淺談庫存扣減相關問題 https://blog.csdn.net/xiongyouqiang/article/details/79388120

 

定時任務:MQ

 

RabbitMQ權限系統。

管理用戶

 

RabbitMQ 整合 spring

RabbitMQ整合 spring-boo

 

 

消費者的優先級

Ttl

交換機到交換機的綁定

 

Rabbitmq事務

消息確認

冪等性

 

定時任務 quartz

Spring-boot的定時任務

 

 

 

 

RabbitMQ-exchangeDeclare()方法:

exchange: 交換器名稱

type : 交換器類型 DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers");

durable: 是否持久化,durable設置爲true表示持久化,反之是非持久化,持久化的能夠將交換器存盤,在服務器重啓的時候不會丟失信息.

autoDelete是否自動刪除,設置爲TRUE則表是自動刪除,自刪除的前提是至少有一個隊列或者交換器與這交換器綁定,以後全部與這個交換器綁定的隊列或者交換器都與此解綁,通常都設置爲fase

internal 是否內置,若是設置 爲true,則表示是內置的交換器,客戶端程序沒法直接發送消息到這個交換器中,只能經過交換器路由到交換器的方式

arguments:其它一些結構化參數好比:alternate-exchange

若是到此交換器的消息不能以其餘方式路由,則將它們發送到這裏命名的備用交換器。

(設置「交互交換」參數。)

 

rabbitMQ-queueDeclare()方法:

queueDeclare(String queue, boolean durable,boolean exclusive, Map<String, Object> arguments);

queue: 隊列名稱

durable: 是否持久化, 隊列的聲明默認是存放到內存中的,若是rabbitmq重啓會丟失,若是想重啓以後還存在就要使隊列持久化,保存到Erlang自帶的Mnesia數據庫中,當rabbitmq重啓以後會讀取該數據庫 (true爲持久化)

exclusive:是否排外的,有兩個做用,

一:當鏈接關閉時connection.close()該隊列是否會自動刪除;

二:該隊列是不是私有的private

若是不是排外的,能夠使用兩個消費者都訪問同一個隊列,沒有任何問題,

若是是排外的,會對當前隊列加鎖,其餘通道channel是不能訪問的,若是強制訪 問會報異常:com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'queue_name' in vhost '/', class-id=50, method-id=20)

通常等於true的話用於一個隊列只能有一個消費者來消費的場景

 

autoDelete:是否自動刪除,當最後一個消費者斷開鏈接以後隊列是否自動被刪除,能夠經過RabbitMQ Management,查看某個隊列的消費者數量,當consumers = 0時隊列就會自動刪除

arguments: 隊列中的消息何時會自動被刪除?

Message TTL(x-message-ttl):設置隊列中的全部消息的生存週期(統一爲整個隊列的全部消息設置生命週期), 也能夠在發佈消息的時候單獨爲某個消息指定剩餘生存時間,單位毫秒, 相似於redis中的ttl,生存時間到了,消息會被從隊裏中刪除,注意是消息被刪除,而不是隊列被刪除, 特性Features=TTL, 單獨爲某條消息設置過時時間AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties().builder().expiration(6000); channel.basicPublish(EXCHANGE_NAME, 「」, properties.build(), message.getBytes(UTF-8));

Auto Expire(x-expires): 當隊列在指定的時間沒有被訪問(consume, basicGet, queueDeclare)就會被刪除,Features=Exp

Max Length(x-max-length): 限定隊列的消息的最大值長度,超過指定長度將會把最先的幾條刪除掉, 相似於mongodb中的固定集合,例如保存最新的100條消息, Feature=Lim Max Length

Bytes(x-max-length-bytes): 限定隊列最大佔用的空間大小, 通常受限於內存、磁盤的大小, Features=Lim B

Dead letter exchange(x-dead-letter-exchange): 當隊列消息長度大於最大長度、或者過時的等,將從隊列中刪除的消息推送到指定的交換機中去而不是丟棄掉,Features=DLX

Dead letter routing key(x-dead-letter-routing-key):將刪除的消息推送到指定交換機的指定路由鍵的隊列中去, Feature=DLK

Maximum priority(x-max-priority):優先級隊列,聲明隊列時先定義最大優先級值(定義最大值通常不要太大),在發佈消息的時候指定該消息的優先級, 優先級更高(數值更大的)的消息先被消費,

Lazy mode(x-queue-mode=lazy)Lazy Queues: 先將消息保存到磁盤上,不放在內存中,當消費者開始消費的時候才加載到內存中

Master locator(x-queue-master-locator) 設置集羣的主隊列

 

 

 

 

idea中@Data標籤getset不起做用

spring cloud中使用@Data標籤,不用手動添加get set方法,可是若是項目中其餘類中使用getset方法,若是報錯,緣由是idea中沒有添加Lombok插件,添加上插件即可以解決。截圖以下

 

 

 

@Controller@RestController的區別?

知識點:@RestController註解至關於@ResponseBody @Controller合在一塊兒的做用。

 

1) 若是隻是使用@RestController註解Controller,則Controller中的方法沒法返回jsp頁面,或者html,配置的視圖解析器 InternalResourceViewResolver不起做用,返回的內容就是Return 裏的內容。

 

2) 若是須要返回到指定頁面,則須要用 @Controller配合視圖解析器InternalResourceViewResolver才行。
    若是須要返回JSONXML或自定義mediaType內容到頁面,則須要在對應的方法上加上@ResponseBody註解。

 

例如:

1.使用@Controller 註解,在對應的方法上,視圖解析器能夠解析return jsp,html頁面,而且跳轉到相應頁面

若返回json等內容到頁面,則須要加@ResponseBody註解

 

Nginx:

Nginxtomcat對比:在web1.0時代,併發量小,用戶少。用戶直接訪問tomcat是沒有問題的。

  Web2.0時代,信息量爆炸,漸漸出現了高併發的問題,一個tomcat承載不了這些訪問量,須要同時使用多個tomcatnginx就能夠把這多個tomcat統一代理對外開放爲一個端口地址

nginx更加擅長靜態資源的處理服務,將項目的靜態資源統一放在靜態服務器,提升訪問效率。

 

爲何要使用代理服務器?

1)提升訪問速度

因爲目標主機返回的數據會存放在代理服務器的硬盤中,所以下一次客戶再訪問相同的站點數據時,會直接從代理服務器的硬盤中讀取,起到了緩存的做用,尤爲對於熱門站點能明顯提升請求速度。

2nginx的一些特性能夠保住脆弱的java服務器。

3nginx用於提供靜態頁面服務,java服務器要強。

 

Nginx特色:

1)跨平臺:Nginx 能夠在大多數 Unix like OS編譯運行,並且也有Windows的移植版本。

2)配置異常簡單,很是容易上手。配置風格跟程序開發同樣,神通常的配置

3)非阻塞、高併發鏈接:數據複製時,磁盤I/O的第一階段是非阻塞的。官方測試可以支撐5萬併發鏈接,在實際生產環境中跑到23萬併發鏈接數.(這得益於Nginx使用了最新的epoll模型)

4)事件驅動:通訊機制採用epoll模型,支持更大的併發鏈接。

5master/worker結構:一個master進程,生成一個或多個worker進程

6)內存消耗小:處理大併發的請求內存消耗很是小。在3萬併發鏈接下,開啓的10Nginx 進程才消耗150M內存(15M*10=150M 

7)成本低廉:Nginx爲開源軟件,能夠無償使用。而購買F5 BIG-IPNetScaler等硬件負載均衡交換機則須要十多萬至幾十萬人民幣

8)內置的健康檢查功能:若是 Nginx Proxy 後端的某臺 Web 服務器宕機了,不會影響前端訪問。

9)節省帶寬:支持 GZIP 壓縮,能夠添加瀏覽器本地緩存的 Header 頭。

10)穩定性高:用於反向代理,宕機的機率微乎其微

Nginx三大核心功能:

(一)反向代理:

反向代理是指以代理服務器來接受internet上的鏈接請求,而後將請求轉發給內部網絡上的服務器,並將從服務器上獲得的結果返回給internet上請求鏈接的客戶端,此時代理服務器對外就表現爲一個反向代理服務器。

 

正向代理客戶端必須設置正向代理服務器,固然前提是要知道正向代理服務器的IP地址,還有代理程序的端口。

反向代理正好與正向代理相反,對於客戶端而言代理服務器就像是原始服務器,而且客戶端不須要進行任何特別的設置。客戶端向反向代理的命名空間中的內容發送普通請求,接着反向代理將判斷向哪一個原始服務器轉交請求,並將得到的內容返回給客戶端。

反向代理服務器一般有兩種模型,它能夠做爲內容服務器的替身,也能夠做爲內容服務器集羣的負載均衡器:

做爲內部服務器替身就是代理域名直接去代理後臺服務器tomcat

內部服務器負載均衡,同時代理幾臺tomcat服務器

 

(二)負載均衡

爲何解決負載均衡:

   1)解決併發壓力,提升應用處理性能(增長吞吐量,增強網絡處理能力)                

2)提供故障轉移,實現高可用

3)經過添加或減小服務器數量,提供網站伸縮性(擴展性)

什麼是負載均衡:

負載均衡指的是多個服務器共同完成一件事情,核心是「分攤壓力」。Ngnix實現負載均衡指的是將請求轉發給服務器集羣。Ngnix默認處理負載均衡的方式是「輪詢」,咱們能夠經過weight來調整權重。

 

Nginx負載均衡的方式:

  1、輪詢(默認)

2weight(輪詢權值)

3ip_hash

4fair(第三方)

5url_hash(第三方)

(三)動靜分離

動靜分離的優勢,配置動靜分離

爲何動靜分離?

1.分擔服務器壓力,動態請求和靜態請求都是tomcat,靜態資源請求處理速度效率很低,將靜態文件放到另外一個服務器增長訪問效率,便於維護。

2.Nginx很容易構造一個靜態內容的服務,提供一個靜態站點的服務器。

動靜分離的概念和做用:

  爲了提升網站的響應速度,減輕程序服務器(TomcatJboss等)的負載對於靜態資源好比圖片,jscss等文件,咱們能夠在反向代理服務器中進行緩存,這樣瀏覽器在請求一個靜態資源時,代理服務器就能夠直接處理,而不用將請求轉發給後端服務器。用戶請求的動態文件好比servlet,jsp則轉發給TomcatJboss服務器處理,這就是動靜分離。這也是反向代理服務器的一個重要的做用。

   代理服務器和靜態服務器即爲一臺服務器上,這裏只是爲了明顯區分動靜分離所處服務器的不一樣;

   靜態服務器中,存放的資源主要是源代碼文件、圖片、屬性、樣式以及其它全部非動態的資源文件;

   動靜分離在先後端分離的項目契合度更高,更可以發揮它的優點,

 

 

高併發:

高併發簡單來講就是在同一時刻不一樣用戶訪問同一資源的問題,專業點的說法就是同一時刻有多個線程訪問同一個數據資源。

Nginx的高併發處理:

nginx的高併發就是經過worker的搶佔機制同時搭配了異步非阻塞方式來實現的。

主進程只進行監聽,請求等處理都是在工做進程完成的。當工做進程獲得客戶端的請求時,對請求並非一次性處理完,而只是處理一部分,處理到請求阻塞的時候,工做進程不會一直等着該請求阻塞完成,而是會去作其餘客戶的請求,這個切換是客戶請求主動讓出的,不須要任何代價。這樣就實現了一個工做進程能夠同時處理多個客戶端的請求。從而實現高併發。

進程模型:

nginx在啓動後,會有一個master進程和多個worker進程。master進程主要用來管理worker進程,包含:接收來自外界的信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出後(異常狀況下),會自動從新啓動新的worker進程。而基本的網絡事件,則是放在worker進程中來處理了。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。worker進程的個數是能夠設置的,通常咱們會設置與機器cpu核數一致,這裏面的緣由與nginx的進程模型以及事件處理模型是分不開的。

nginx採用這種進程模型有什麼好處呢?

       首先,對於每一個worker進程來講,獨立的進程,不須要加鎖,因此省掉了鎖帶來的開銷,同時在編程以及問題查上時,也會方便不少。其次,採用獨立的進程,可讓互相之間不會影響,一個進程退出後,其它進程還在工做,服務不會中斷,master進程則很快從新啓動新的worker進程。固然,worker進程的異常退出,確定是程序有bug了,異常退出,會致使當前worker上的全部請求失敗,不過不會影響到全部請求,因此下降了風險

 

Nginx事件模型:

異步非阻塞:

Nginx採起異步非阻塞的方式處理請求。

處理請求流程:收到請求,創建鏈接,接收數據,發送數據。

若是採用阻塞調用,會陷入內核等待,在單進程的nginx下這樣cpu就會空閒,無法充分使用。

採用非阻塞調用,會在事件沒有準備好時,返回EAGAIN來通知,此時線程還能夠作其餘事情,而後再回來查看事件是否準備完成。這種狀況下的消耗也比較大。

異步非阻塞調用是一種機制,能夠同時監控多個事件,調用他們是阻塞的,可是能夠設置超時時間,在超時時間內,若是有事件處理好了,就返回。以epoll爲例,當事件沒有準備好時,放到epoll中,事件準備好了,就去處理它,只有當全部的事件都沒準備好時,纔會在epoll裏面等待。這樣就能夠處理大量未完成的併發事件。

線程只有一個,因此同時能處理的請求只有一個,只是在請求間不斷地切換而已,切換也是由於事件未準備好而主動讓出,沒有任何代價。

異步非阻塞時間處理機制:

讓你能夠同時監控多個事件,調用他們是阻塞的,但能夠設置超時時間,在超時時間以內,若是有事件準備好了,就返回。當事件沒準備好時,放到epoll裏面,事件準備好了,咱們就去讀寫,寫返回EAGAIN時,咱們將它再次加入到epoll裏面。這樣,只要有事件準備好了,咱們就去處理它,只有當全部事件都沒準備好時,纔在epoll裏面等着。這樣,咱們就能夠併發處理大量的併發了,固然,這裏的併發請求,是指未處理完的請求,線程只有一個,因此同時能處理的請求固然只有一個了,只是在請求間進行不斷地切換而已,切換也是由於異步事件未準備好,而主動讓出的。

與多線程相比,這種事件處理方式是有很大的優點的,不須要建立線程,每一個請求佔用的內存也不多,沒有上下文切換,事件處理很是的輕量級。併發數再多也不會致使無謂的資源浪費(上下文切換)

 

 

Spring cloud:

Spring cloud簡介:

基於SpringBoot 提供一套微服務解決方案,包括服務註冊與發現,配置中心,全鏈路監控,服務網管,負載均衡,熔斷器等組件。除了NetFlix的開源組件作高度抽象封裝以外,還有一些中立的開源組件。

利用SpringBoot的開發遍歷性技巧,分佈式系統基礎設施的開發。包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策競選、分佈式會話等等,它們均可以用SpringBoot的開發風格作到一鍵啓動和部署。

  微服務:

微服務的核心就是將傳統的一站式應用根據業務拆成一個一個的服務,完全的去耦合,每個微服務提供單個業務功能的服務,一個服務作一件事情,從技術角度看就是一種小而獨立的處理過程,相似於進程的概念,可以自行單獨啓動或銷燬,擁有本身獨立的數據庫。

微服務條目 技術

服務開發 SpringbootSpringSpringMVC

服務配置與管理 Netflix公司的Archaius、阿里的Diamond

服務註冊與發現 EurekaConsulZookeeper

服務調用 RestRPCgRPC

服務熔斷器 HystrixEnvoy

負載均衡 RibbonNginx

服務接口調用(客戶端調用服務的簡化工具) Feign

消息隊列 KafkaRabbitMQActiveMQ

服務配置中心管理 SpringCloudConfigChef

服務路由(API網關) Zuul

服務監控 ZabbixNagiosMetricsSpectator

全鏈路追蹤 ZipkinBraveDapper

服務部署 DockerOpenStackKubernetes

數據流操做開發包 SpringCloud Stream(封裝與Redis,RabbitKafka等發送接收消息)

事件消息總線 Spring Cloud Bus

Spring cloudboot的關係:

Springboot專一於快讀方便的開發單個個體微服務。

Springcloud是關注全局的微服務協調整理治理框架,他將springboot開發的一個個單個微服務整合並管理起來,爲各個微服務之間提供了配置管理,服務發現,斷路器,路由,微代理,時間總線,全局鎖,決策精選,分佈會話等等集成服務。

Springboot能夠離開springcloud獨立開發,可是cloud離不開springboot,屬於依賴關係。

Springboot專一於快速、方便的開發單個微服務個體,springcloud專一於全局的服務治理框架。

Springcloud的做用:

Spring cloud是一系列框架的有序集合。利用springboot開發遍歷的技巧,簡化了分佈式系統基礎設施開發。Spring cloud就是微服務的大管家,採用微服務的框架以後,項目的數量很是多,springcloud做爲大管家就須要提供各類方案來維護整個生態。

SpringCloud的核心特性:

  1. 分佈式/版本化配置
  2. 服務註冊和發現
  3. 路由
  4. 服務和服務之間的調用
  5. 負載均衡
  6. 斷路器
  7. 分佈式消息傳遞

Eureka

簡介:Eureka主要實現了服務註冊和發現。(zookeeper

Eureka採用了C-S的設計架構。EurekaServer 做爲服務註冊功能的服務器,他是服務註冊中心。

系統中的其餘微服務,使用Eureka的客戶端鏈接到Eureka Server並維持心跳鏈接,這樣系統維護人員能夠經過Eureka來監控系統中各個微服務是否正常運行,Cloud其餘模塊能夠經過Eurake來發現系統中哦你的其餘微服務,並執行相應邏輯。

Eureka組件:Eureka Server Eureka Client

Eureka Server提供服務註冊服務

各個節點啓動後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務註冊表中將會存儲全部可用服務節點的信息,服務節點的信息能夠在界面中直觀的看到

EurekaClient是一個Java客戶端,用於簡化Eureka Server的交互,客戶端同時也具有一個內置的、使用輪詢(round-robin)負載算法的負載均衡器。在應用啓動後,將會向Eureka Server發送心跳(默認週期爲30)。若是Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務註冊表中把這個服務節點移除(默認90秒)

 

ZookeeperEureka

Zookeeper保證CP。當向註冊中心查詢服務列表時,咱們能夠容忍註冊中心返回的是幾分鐘前的註冊信息,但不能接受直接掛掉不可用。所以,服務註冊中心對可用性的要求高於一致性。可是,因網絡問題致使的zookeeper集羣式去master節點的機率較大,雖然服務器最終恢復,但漫長的選舉時間致使註冊服務長期不可用是不可容忍的。

 

Eureka保證AP。在設計上Eureka優先保證了可用性。EurekaServer各個節點都是平等的,幾個節點掛掉不會影響正常節點的工做,剩餘節點依然能夠提供註冊和發現服務。而Eureka客戶端在想某個server註冊或發現連接失敗時,會自動切換到其餘server節點,只要有一臺server正常運行,就能保證註冊服務可用,只不過查詢到的信息不必定是最新的。

Eureka還有一種自我保護機制,若是15分鐘內超過85%的節點都沒有正常心跳,那麼EurekaServer將認爲客戶端和註冊中心網絡故障,此時:1Eurekaserver再也不從註冊列表中移除由於長時間沒有收到心跳而應該過時的服務。2.EurekaServer仍可以接受新服務的註冊查詢請求,但不會被同步到其餘節點上當網絡穩定時,當前EurekaServer節點新的註冊信息會同步到其餘節點中。所以,Eureka能夠很好的應對因網絡故障致使部分節點式去聯繫的狀況,而不會像Zooper那樣整個服務癱瘓。

 

Eureka配置:

依賴:

 <dependency>

     <groupId>org.springframework.cloud</groupId>

     <artifactId>spring-cloud-starter-eureka</artifactId>

   </dependency>

   <dependency>

     <groupId>org.springframework.cloud</groupId>

     <artifactId>spring-cloud-starter-config</artifactId>

   </dependency>

配置yml

server:

   port: 7001

eureka:

   instance:

     hostname: localhost #eureka服務端的實例名稱

   client:

     register-with-eureka: false #false表示不向註冊中心註冊本身。

     fetch-registry: false #false表示本身端就是註冊中心,個人職責就是維護服務實例,並不須要去檢索服務

     service-url:

       defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/  

添加啓動類註解:

@EnableEurekaServer

 

Eureka客戶端配置:

添加依賴:

   <dependency>

     <groupId>org.springframework.cloud</groupId>

     <artifactId>spring-cloud-starter-eureka</artifactId>

   </dependency>

   <dependency>

     <groupId>org.springframework.cloud</groupId>

     <artifactId>spring-cloud-starter-config</artifactId>

   </dependency>

添加啓動類註解:

@EnableEurekaClient

 YML:

server:

  port: 8001

mybatis:

  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路徑

  type-aliases-package: com.atguigu.springcloud.entities    # 全部Entity別名類所在包

  mapper-locations:

  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件

spring:

   application:

    name: microservicecloud-dept

     client: #客戶端註冊進eureka服務列表內

    service-url:

      defaultZone: http://localhost:7001/eureka      

 

Feign

Feign簡介:Feign是一個聲明式的Web Service客戶端,它使得編寫Web Serivce客戶端變得更加簡單。咱們只須要使用Feign來建立一個接口並用註解來配置它既可完成。它具有可插拔的註解支持,包括Feign註解和JAX-RS註解。Feign也支持可插拔的編碼器和解碼器。Spring Cloud爲Feign增長了對Spring MVC註解的支持,還整合了Ribbon和Eureka來提供均衡負載的HTTP客戶端實現。

Feign經過接口的方法調用Rest服務,該請求發送到Eureka服務器,經過Feign直接找到服務接口。因爲在進行服務調用的時候融合了Ribbon技術,因此也支持了負載均衡。

Feign的實現:

依賴:

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-feign</artifactId>

        </dependency>

添加啓動類註解:

@EnableDiscoveryClient

@EnableFeignClients

服務雪崩:

多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的「扇出」。若是扇出的鏈路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會佔用愈來愈多的系統資源,進而引發系統崩潰,所謂的「雪崩效應」.

雪崩緣由:硬件故障,負載過大(雙11),代碼問題.

熔斷器:它能夠實現快速失敗,若是他在一段時間內偵測到許多相似的錯誤,會強迫其之後的多個調用快速失敗,再也不訪問遠程服務器,從而防止應用程序不斷嘗試執行可能會失敗的操做,使應用程序繼續執行而不用等待修正錯誤,或者浪費CPU時間去等到長時間的超時產生。熔斷器也能夠使硬喲娜程序可以診斷錯誤是否修正,若是已修正,應用程序會再次嘗試調用操做。

Hystrix:

Hystrix特性:

1.斷路器機制。 當Hystrix Command請求後端服務失敗數量超過必定比例(默認50%), 斷路器會切換到開路狀態(Open). 這時全部請求會直接失敗而不會發送到後端服務. 斷路器保持在開路狀態一段時間後(默認5秒), 自動切換到半開路狀態(HALF-OPEN). 這時會判斷下一次請求的返回狀況, 若是請求成功, 斷路器切回閉路狀態(CLOSED), 不然從新切換到開路狀態(OPEN). Hystrix的斷路器就像咱們家庭電路中的保險絲, 一旦後端服務不可用, 斷路器會直接切斷請求鏈, 避免發送大量無效0203. 。

你請求影響系統吞吐量, 而且斷路器有自我檢測並恢復的能力.

2.Fallback

Fallback至關於降級操做,對於查詢操做。咱們能夠實現一個fallback方法,當請求後端服務出現異常的時候,能夠使用fallback方法返回的值,fallback方法的返回值通常是設置的默認值或來自緩存。

服務降級:

yml添加節點

feign:

  hystrix:

    enabled: true

 

 

繼承並實現生產者接口

 value=指定生產者服務名字 fallbackFactory=實現類的全限定名

@FeignClient(value = "MICROSERVICDEPT",fallbackFactory=DeptClientServiceFallbackFactory.class

3.資源隔離

Hystrix中,主要經過線程池來實現資源隔離,一般使用的時候咱們會根據調用的遠程服務劃分出多個線程池,這樣作主要優勢是運行環境被隔離開,這樣就算調用服務的代碼存在bug或優於其餘緣由致使本身所在的線程池被耗盡時,不會對系統的其餘服務形成影響,可是帶來的代價就是維護多個線程池會對系統帶來額外的性能開銷,若是對性能有嚴格要求並且確信本身調用服務的客戶端代碼不會出現的話,能夠使用Hystrix的信號模式來隔離資源。

Hystrix監控:

依賴:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artfactId>

</dependency>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-hystrix</artifactId>

</dependency>

 

添加註解:

@EnableCircuitBreaker

 

啓動服務器查看監控數據:

訪問/hystrix.stream端點 好比:http://localhost:5001/hystrix.stream

先訪問服務中的任意接口,而後訪問/hystrix.stream端點纔會顯示對應的接口監控數據。

Hystrix的監控是以文字形式展示的,不方便分析。Hystrix Dashboard可視化監控。

添加依賴:

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-hystrix</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-actuator</artifactId>

        </dependency>

添加註釋:

@EnableHystrixDashboard啓用Hystrix Dashboard功能。

啓動服務器查看監控數據,訪問當前節點。

 

Ribbon

簡介:

Spring cloud Ribbon 是基於Netflix Ribbon實現的一套客戶端負載均衡工具。簡單的說,Ribbon是Netflix發佈的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務鏈接在一塊兒。Ribbon客戶端組件提供一系列完善的配置項如鏈接超時,重試等。就是在配置文件中列出Load Balancer(簡稱LB)後面全部的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機鏈接等)去鏈接這些機器。咱們也很容易使用Ribbon實現自定義的負載均衡算法。

經過配置方式更愛負載均衡策略:

consumer項目添加配置:

(yml)

dm-user-provider:

  ribbon:

    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

 

其餘負載均衡策略均定義在com.netflix.loadbalancer包中,能夠根據須要選擇合適的策略。

 

Zuul微服務網關:

簡介:Zuul做爲邊界應用服務,zuul能實現動態路由、監控、彈性與安全性。

Zuul實現:

建立項目

添加Zuul依賴

<dependency>

   <groupId>org.springframework.cloud</groupId>

   <artifactId>spring-cloud-starter-eureka</artifactId>

   <version>1.3.5.RELEASE</version>

</dependency>

<dependency>

   <groupId>org.springframework.cloud</groupId>

   <artifactId>spring-cloud-starter-zuul</artifactId>

   <version>1.3.5.RELEASE</version>

</dependency>

修改配置指定服務端口、Eureka Server地址等信息

spring:

   application:

      name: dm-gateway-zuul

server:

   port: 7600

eureka:

   client:

      service-url:

         defaultZone: http://localhost:7776/eureka/

添加註解

@EnableZuulProxy

配置zuul網關過濾器:

微服務名: 映射路徑

zuul:

   routes:

     dm-user-consumer: /user/**

   strip-prefix: false

 

每一個服務在處理請求的時候都要判斷是否驗證token

須要驗證token是否有效

 

效率低

    每一個請求都須要轉發到具體的微服務後再判斷,而後將判斷的結果迴轉給網關

    在網關轉發前就行進過濾處理

過濾器

建立過濾器

繼承ZuulFilter

重寫方法

filterType():過濾器類型

filterOrder():過濾順序

shouldFilter():是否進行攔截過濾

run():肯定須要攔截以後執行的方法

分佈式總配置:

每一個服務都有本身的配置文件,不少公共的配置信息更改配置信息都須要從新發布服務

Spring Cloud Config

公共信息都保存到遠程倉庫

鏈接Config Server,無需重啓更新配置參數

統一加密解密

建立項目

添加依賴

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-server</artifactId>
</dependency>

<dependency>

  <groupId>org.springframework.cloud</groupId>

  <artifactId>spring-cloud-starter-eureka</artifactId>

  <version>1.3.5.RELEASE</version>

</dependency>

添加註解

@EnableConfigServer

@EnableDiscoveryClient

Yml:

server:

  port: 7900

spring:

  cloud:

    config:

      server:

        git:

          uri: Git倉庫地址

          username: 帳號名稱

          password: 帳號密碼

          search-paths: config-repo

  application:

    name: dm-config-server

eureka:

  client:

    service-url:

      defaultZone: http://root:123456@localhost:7776/eureka/

 

啓動服務

訪問端點

http://localhost:7900/client/dev/sprint2.0_dev

映射規則:/{application}/{profile}/{label}

{application}Git倉庫中文件名的前綴, 一般使用微服務名稱

{profile}{application}-後面的數值

在同一個分支下能夠有多個{application}名稱相同的文件

{label}Git倉庫的分支名,默認爲maste\

建立遠程配置文件:

dm-gateway-zuul-dev.properties

添加依賴:

Zuul網關項目dm-gateway-zuul添加依賴

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

 

 編寫Config Client:

spring:

  application:

#對應映射規則中的{application}

    name: dm-gateway-zuul   

  cloud:

    config:

#對應映射規則中的{label}部分

      label: sprint2.0_dev  

#對應Config Server的地址

      uri: http://localhost:7900/

#對應映射規則中的{profile}部分

      profile: dev

eureka:

  client:

    service-url:

defaultZone:http://root:123456@localhost:7776/eureka/

           

配置refresh:

添加依賴

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

添加註解

@RefreshScope

添加配置

management:

  security:

    enabled: false

訪問刷新端點http://localhost:7900/refresh

           

使用Sleuth微服務跟蹤:

添加依賴,整合Sleuth

在前面示例的基礎上,爲 providerconsumer項目添加依賴

 

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-sleuth</artifactId>

    <version>1.2.5.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-zipkin</artifactId>

</dependency>

 

修改配置文件

修改consumer項目的application.yml文件,在其中設置日誌級別爲info

server:

   port: 8080

spring:

   application:

      name: dm-user-consumer

eureka:

   client:

      service-url:

          defaultZone: http://root:123456@localhost:7776/eureka/

logging:

    level: info

 

     配置Zipkin Server

建立項目

       指定artifactIdsleuth

添加註解

@EnableZipkinServer

 

添加依賴

<dependency>
   <groupId>io.zipkin.java</groupId>
   <artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
   <groupId>io.zipkin.java</groupId>
   <artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>

 

分別修改consumerprovider application.yml,在其中指定Zipkin Server地址和採樣率

 

spring:

  zipkin:

    base-url: http://localhost:7777

  sleuth:

    sampler:

       percentage: 1.0

在開發、測試中配置文件中的spring.sleuth.sampler.percentage屬性設置爲1.0,表明100%採樣,不然可能會忽略掉大量span,可能看不到想要查看的請求                                                                                                                                                     

相關文章
相關標籤/搜索