得不到的始終在騷動 金三銀四的季節你們有點躁動了 總結一下面試題java
其中有不少其餘博客或者論壇摘抄的內容mysql
一. 基礎nginx
1.什麼是Java虛擬機?爲何Java被稱做是「平臺無關的編程語言」?
答:Java虛擬機是一個能夠執行Java字節碼的虛擬機進程。Java源文件被編譯成能被Java虛擬機執行的字節碼文件。程序員
2.面向對象的三大特性
答:面向對象的特徵主要有如下幾個方面:
- 抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。抽象只關注對象有哪些屬性和行爲,並不關注這些行爲的細節是什麼。
- 繼承:繼承是從已有類獲得繼承信息建立新類的過程。提供繼承信息的類被稱爲父類(超類、基類);獲得繼承信息的類被稱爲子類(派生類)。繼承讓變化中的軟件系統有了必定的延續性,同時繼承也是封裝程序中可變因素的重要手段(若是不能理解請閱讀閻宏博士的《Java與模式》或《設計模式精解》中關於橋樑模式的部分)。
- 封裝:一般認爲封裝是把數據和操做數據的方法綁定起來,對數據的訪問只能經過已定義的接口。面向對象的本質就是將現實世界描繪成一系列徹底自治、封閉的對象。咱們在類中編寫的方法就是對實現細節的一種封裝;咱們編寫一個類就是對數據和數據操做的封裝。能夠說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程 接口(能夠想一想普通洗衣機和全自動洗衣機的差異,明顯全自動洗衣機封裝更好所以操做起來更簡單;咱們如今使用的智能手機也是封裝得足夠好的,由於幾個按鍵就搞定了全部的事情)。
- 多態性:多態性是指容許不一樣子類型的對象對同一消息做出不一樣的響應。簡單的說就是用一樣的對象引用調用一樣的方法可是作了不一樣的事情。多態性分爲編譯時的多態性和運行時的多態性。若是將對象的方法視爲對象向外界提供的服務,那麼運行時的多態性能夠解釋爲:當A系統訪問B系統提供的服務時,B系統有多種提供服務的方式, 但一切對A系統來講都是透明的(就像電動剃鬚刀是A系統,它的供電系統是B系統,B系統能夠使用電池供電或者用交流電,甚至還有多是太陽能,A系統只會經過B類對象調用供電的方法,但並不知道供電系統的底層實現是什麼,究竟經過何種方式得到了動力)。方法重載(overload)實現的是編譯時的多態性(也稱爲前綁 定),而方法重寫(override)實現的是運行時的多態性(也稱爲後綁定)。運行時的多態是面向對象最精髓的東西,要實現多態須要作兩件事:1). 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法);2). 對象造型(用父類型引用引用子類型對象,這樣一樣的引用調用一樣的方法就會根據子類對象的不一樣而表現出不一樣的 行爲)。
3.Java支持的數據類型有哪些?什麼是自動拆裝箱?
答:Java語言支持的8中基本數據類型是:
• byte
• short
• int
• long
• float
• double
• boolean
• char
自動裝箱是Java編譯器在基本數據類型和對應的對象包裝類型之間作的一個轉化。好比:把int轉化成Integer,double轉化成double,等等。反之就是自動拆箱。
4.Overload和Override的區別。Overloaded的方法是否能夠改變返回值的類型?
答:方法的重寫Overriding和重載Overloading是Java多態性的不一樣表現。重寫Overriding是父類與子類之間多態性的一種表現,重載O verloading是一個類中多態性的一種表現。若是在子類中定義某方法與其父類有相同的名稱和參數,咱們說該方法被重寫(Overriding)。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被」屏蔽」了。若是在一個類中定義了多個同名的方法,它們或有不一樣的參數個數或有不一樣的參數類型,則稱爲方法的重載(Overloading)。Overloaded的方法是能夠改變返回值的類型。
5.接口和抽象類的區別是什麼?
答:Java提供和支持建立抽象類和接口。它們的實現有共同點,不一樣點在於:
• 接口中全部的方法隱含的都是抽象的。而抽象類則能夠同時包含抽象和非抽象的方法。
• 類能夠實現不少個接口,可是隻能繼承一個抽象類
• 類若是要實現一個接口,它必需要實現接口聲明的全部方法。可是,類能夠不實現抽象類聲明的全部方法,固然,在這種狀況下,類也必須得聲明成是抽象的。
• 抽象類能夠在不提供接口方法實現的狀況下實現接口。
• Java接口中聲明的變量默認都是final的。抽象類能夠包含非final的變量。
• Java接口中的成員函數默認是public的。抽象類的成員函數能夠是private,protected或者是public。
• 接口是絕對抽象的,不能夠被實例化。抽象類也不能夠被實例化,可是,若是它包含main方法的話是能夠被調用的。
也能夠參考JDK8中抽象類和接口的區別
6.什麼是值傳遞和引用傳遞?
答:對象被值傳遞,意味着傳遞了對象的一個副本。所以,就算是改變了對象副本,也不會影響源對象的值。
對象被引用傳遞,意味着傳遞的並非實際的對象,而是對象的引用。所以,外部對引用對象所作的改變會反映到全部的對象上。web
7.建立線程有幾種不一樣的方式?面試
• 繼承Thread類算法
重寫run()
• 實現Runnable接口spring
重寫run()方法
• 實現Callable接口sql
該接口中的call方法能夠在線程執行結束時產生一個返回值docker
8.啓動一個線程是調用run()仍是start()方法?
答:啓動一個線程是調用start()方法,使線程所表明的虛擬處理機處於可運行狀態,這意味着它能夠由JVM 調度並執行,這並不意味着線程就會當即運行。run()方法是線程啓動後要進行回調(callback)的方法。
9.synchronized關鍵字的用法?
答:synchronized關鍵字能夠將對象或者方法標記爲同步,以實現對對象和方法的互斥訪問,能夠用synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將synchronized做爲方法的修飾符。
10.簡述synchronized和java.util.concurrent.locks.Lock的異同?
答:主要相同點:Lock能完成synchronized所實現的全部功能
主要不一樣點:Lock有比synchronized更精確的線程語義和更好的性能。
Lock是一個類,synchronized是一個關鍵字
synchronized會自動釋放鎖,而Lock必定要求程序員手工釋放,而且必須在finally從句中釋放。
11.舉例說明同步和異步。
答:若是系統中存在臨界資源(資源數量少於競爭資源的線程數量的資源),例如正在寫的數據之後可能被另外一個線程讀到,或者正在讀的數據可能已經被另外一個線程寫過了,那麼這些數據就必須進行同步存取(數據庫操做中的排他鎖就是最好的例子)。當應用程序在對象上調用了一個須要花費很長時間來執行的方法,而且不但願讓程序等待方法的返回時,就應該使用異步編程,在不少狀況下采用異步途徑每每更有效率。事實上,所謂的同步就是指阻塞式操做,而異步就是非阻塞式操做。
12.Thread類的sleep()方法和對象的wait()方法均可以讓線程暫停執行,它們有什麼區別?
答:sleep()方法(休眠)是線程類(Thread)的靜態方法,調用此方法會讓當前線程暫停執行指定的時間,將執行機會(CPU)讓給其餘線程,可是對象的鎖依然保持,所以休眠時間結束後會自動恢復(線程回到就緒狀態,請參考第66題中的線程狀態轉換圖)。wait()是Object類的方法,調用對象的wait()方法致使當前線程放棄對象的鎖(線程暫停執行),進入對象的等待池(wait pool),只有調用對象的notify()方法(或notifyAll()方法)時才能喚醒等待池中的線程進入等鎖池(lock pool),若是線程從新得到對象的鎖就能夠進入就緒狀態。
13.同步方法和同步代碼塊的區別是什麼?
答:在Java語言中,每個對象有一把鎖。線程能夠使用synchronized關鍵字來獲取對象上的鎖。synchronized關鍵字可應用在方法級別(粗粒度鎖:這裏的鎖對象能夠是This)或者是代碼塊級別(細粒度鎖:這裏的鎖對象就是任意對象)。
14.什麼是線程池(thread pool)?
答:在面向對象編程中,建立和銷燬對象是很費時間的,由於建立一個對象要獲取內存資源或者其它更多資源。在Java中更是如此,虛擬機將試圖跟蹤每個對象,以便可以在對象銷燬後進行垃圾回收。因此提升服務程序效率的一個手段就是儘量減小建立和銷燬對象的次數,特別是一些很耗資源的對象建立和銷燬,這就是」池化資源」技術產生的緣由。線程池顧名思義就是事先建立若干個可執行的線程放入一個池(容器)中,須要的時候從池中獲取線程不用自行建立,使用完畢不須要銷燬線程而是放回池中,從而減小建立和銷燬線程對象的開銷。
Java 5+中的Executor接口定義一個執行線程的工具。它的子類型即線程池接口是ExecutorService。要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,所以在工具類Executors面提供了一些靜態工廠方法,生成一些經常使用的線程池,以下所示:
- newSingleThreadExecutor:建立一個單線程的線程池。這個線程池只有一個線程在工做,也就是至關於單線程串行執行全部任務。若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它。此線程池保證全部任務的執行順序按照任務的提交順序執行。
- newFixedThreadPool:建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程。
- newCachedThreadPool:建立一個可緩存的線程池。若是線程池的大小超過了處理任務所須要的線程,那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增長時,此線程池又能夠智能的添加新線程來處理任務。此線程池不會對線程池大小作限制,線程池大小徹底依賴於操做系統(或者說JVM)可以建立的最大線程大小。
- newScheduledThreadPool:建立一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。
- newSingleThreadExecutor:建立一個單線程的線程池。此線程池支持定時以及週期性執行任務的需求。
15.線程的基本概念、線程的基本狀態以及狀態之間的關係
答:線程指在程序執行過程當中,可以執行程序代碼的一個執行單位,每一個程序至少都有一個線程,也就是程序自己。
Java中的線程有五種狀態分別是:新建、就緒、運行、阻塞、結束。
16.解釋內存中的棧(stack)、堆(heap)和方法區(method area)的用法。
答:一般咱們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用JVM中的棧空間;而經過new關鍵字和構造器建立的對象則放在堆空間,堆是垃圾收集器管理的主要區域,因爲如今的垃圾收集器都採用分代收集算法,因此堆空間還能夠細分爲新生代和老生代,再具體一點能夠分爲Eden、Survivor(又可分爲From Survivor和To Survivor)、Tenured;方法區和堆都是各個線程共享的內存區域,用於存儲已經被JVM加載的類信息、常量、靜態變量、JIT編譯器編譯後的代碼等數據;程序中的字面量(literal)如直接書寫的100、"hello"和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操做起來最快可是棧很小,一般大量的對象都是放在堆空間,棧和堆的大小均可以經過JVM的啓動參數來進行調整,棧空間用光了會引起StackOverflowError,而堆和常量池空間不足則會引起OutOfMemoryError。
String str = new String("hello");
上面的語句中變量str放在棧上,用new建立出來的字符串對象放在堆上,而"hello"這個字面量是放在方法區的。
17.當一個對象被看成參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏究竟是值傳遞仍是引用傳遞?
答:是值傳遞。Java語言的方法調用只支持參數的值傳遞。當一個對象實例做爲一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的屬性能夠在被調用過程當中被改變,但對對象引用的改變是不會影響到調用者的。C++和C#中能夠經過傳引用或傳輸出參數來改變傳入的參數的值。在C#中能夠編寫以下所示的代碼,可是在Java中卻作不到。
18.String和StringBuilder、StringBuffer的區別?
答:Java平臺提供了兩種類型的字符串:String和StringBuffer/StringBuilder,它們能夠儲存和操做字符串。其中String是隻讀字符串,也就意味着String引用的字符串內容是不能被改變的。而StringBuffer/StringBuilder類表示的字符串對象能夠直接進行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法徹底相同,區別在於它是在單線程環境下使用的,由於它的全部方面都沒有被synchronized修飾,所以它的效率也比StringBuffer要高。
19.描述一下JVM加載class文件的原理機制?
答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。
因爲Java的跨平臺性,通過編譯的Java源程序並非一個可執行程序,而是一個或多個類文件。當Java程序須要使用某個類時,JVM會確保這個類已經被加載、鏈接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數據讀入到內存中,一般是建立一個字節數組讀入.class文件,而後產生與所加載類對應的Class對象。加載完成後,Class對象還不完整,因此此時的類還不可用。當類被加載後就進入鏈接階段,這一階段包括驗證、準備(爲靜態變量分配內存並設置默認的初始值)和解析(將符號引用替換爲直接引用)三個步驟。最後JVM對類進行初始化,包括:1)若是類存在直接的父類而且這個類尚未被初始化,那麼就先初始化父類;2)若是類中存在初始化語句,就依次執行這些初始化語句。
類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程採起了父親委託機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根加載器,其餘的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能爲力時才由其子類加載器自行加載。JVM不會向Java程序提供對Bootstrap的引用。下面是關於幾個類加載器的說明:
20,簡述深克隆與淺克隆
淺拷貝是指在拷貝對象時,對於基本數據類型的變量會從新複製一份,而對於引用類型的變量只是對引用進行拷貝,
沒有對引用指向的對象進行拷貝。
而深拷貝是指在拷貝對象時,同時會對引用指向的對象進行拷貝。
區別就在因而否對 對象中的引用變量所指向的對象進行拷貝。
21.GC是什麼?爲何要有GC?
答:GC是垃圾收集的意思,內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。Java程序員不用擔憂內存管理,由於垃圾收集器會自動進行管理。要請求垃圾收集,能夠調用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM能夠屏蔽掉顯示的垃圾回收調用。
垃圾回收能夠有效的防止內存泄露,有效的使用能夠使用的內存。垃圾回收器一般是做爲一個單獨的低優先級的線程運行,不可預知的狀況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或全部對象進行垃圾回收。在Java誕生初期,垃圾回收是Java最大的亮點之一,由於服務器端的編程須要有效的防止內存泄露問題,然而時過境遷,現在Java的垃圾回收機制已經成爲被詬病的東西。移動智能終端用戶一般以爲iOS的系統比Android系統有更好的用戶體驗,其中一個深層次的緣由就在於Android系統中垃圾回收的不可預知性。
22.列出一些你常見的運行時異常?
答:
- ArithmeticException(算術異常)
- ClassCastException (類轉換異常)
- IllegalArgumentException (非法參數異常)
- IndexOutOfBoundsException (下標越界異常)
- NullPointerException (空指針異常)
- SecurityException (安全異常)
23.線程如何同步和通信。
線程同步
什麼是線程同步?
當使用多個線程來訪問同一個數據時,很是容易出現線程安全問題(好比多個線程都在操做同一數據致使數據不一致),因此咱們用同步機制來解決這些問題。
實現同步機制有兩個方法:
1。同步代碼塊:
synchronized(同一個數據){} 同一個數據:就是N條線程同時訪問一個數據。
2。同步方法:
public synchronized 數據返回類型 方法名(){}
就是使用 synchronized 來修飾某個方法,則該方法稱爲同步方法。對於同步方法而言,無需顯示指定同步監視器,同步方法的同步監視器是 this 也就是該對象的自己(這裏指的對象自己有點含糊,其實就是調用該同步方法的對象)經過使用同步方法,可很是方便的將某類變成線程安全的類
24.爲何要使用線程通信?
當使用synchronized 來修飾某個共享資源時(分同步代碼塊和同步方法兩種狀況),當某個線程得到共享資源的鎖後就能夠執行相應的代碼段,直到該線程運行完該代碼段後才釋放對該 共享資源的鎖,讓其餘線程有機會執行對該共享資源的修改。當某個線程佔有某個共享資源的鎖時,若是另一個線程也想得到這把鎖運行就須要使用wait() 和notify()/notifyAll()方法來進行線程通信了。
25.用Java寫一個單例類。
//餓漢式
public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance() {
return instance; } }
//懶漢式 public class Singleton { private static Singleton instance = null; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; } }
26.Java中的四種引用及其應用場景是什麼?
new
操做符建立一個對象時所返回的引用即爲強引用Bitmap
Bitmap
再也不使用就會被回收-----------------------------------------------------------------------------集合-------------------------------------------------------------------------------------
23.List、Set、Map是否繼承自Collection接口?
答:List、Set 是,Map 不是。Map是鍵值對映射容器,與List和Set有明顯的區別,而Set存儲的零散的元素且不容許有重複元素(數學中的集合也是如此),List是線性結構的容器,適用於按數值索引訪問元素的情形。
24.闡述ArrayList、Vector、LinkedList的存儲性能和特性。
答:ArrayList 和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增長和插入元素,它們都容許直接按序號索引元素,可是插入元素要涉及數組元素移動等內存操做,因此索引數據快而插入數據慢,Vector中的方法因爲添加了synchronized修飾,所以Vector是線程安全的容器,但性能上較ArrayList差,所以已是Java中的遺留容器。LinkedList使用雙向鏈表實現存儲(將內存中零散的內存單元經過附加的引用關聯起來,造成一個能夠按序號索引的線性結構,這種鏈式存儲方式與數組的連續存儲方式相比,內存的利用率更高),按序號索引數據須要進行前向或後向遍歷,可是插入數據時只須要記錄本項的先後項便可,因此插入速度較快。Vector屬於遺留容器(Java早期的版本中提供的容器,除此以外,Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),已經不推薦使用,可是因爲ArrayList和LinkedListed都是非線程安全的,若是遇到多個線程操做同一個容器的場景,則能夠經過工具類Collections中的synchronizedList方法將其轉換成線程安全的容器後再使用(這是對裝潢模式的應用,將已有對象傳入另外一個類的構造器中建立新的對象來加強實現)。
25.List、Map、Set三個接口存取元素時,各有什麼特色?
答:List以特定索引來存取元素,能夠有重複元素。Set不能存放重複元素(用對象的equals()方法來區分元素是否重複)。Map保存鍵值對(key-value pair)映射,映射關係能夠是一對一或多對一。Set和Map容器都有基於哈希存儲和排序樹的兩種實現版本,基於哈希存儲的版本理論存取時間複雜度爲O(1),而基於排序樹版本的實如今插入或刪除元素時會按照元素或元素的鍵(key)構成排序樹從而達到排序和去重的效果。
26.Java中的HashMap的工做原理是什麼?
Java中的HashMap是以鍵值對(key-value)的形式存儲元素的。HashMap須要一個hash函數,它使用hashCode()和equals()方法來向集合/從集合添加和檢索元素。當調用put()方法的時候,HashMap會計算key的hash值,而後把鍵值對存儲在集合中合適的索引上。若是key已經存在了,value會被更新成新值。HashMap的一些重要的特性是它的容量(capacity),負載因子(load factor)和擴容極限(threshold resizing)。
27.HashMap和Hashtable有什麼區別?
• HashMap和Hashtable都實現了Map接口,所以不少特性很是類似。可是,他們有如下不一樣點:
• HashMap容許鍵和值是null,而Hashtable不容許鍵或者值是null。
• Hashtable是同步的,而HashMap不是。所以,HashMap更適合於單線程環境,而Hashtable適合於多線程環境。
• HashMap提供了可供應用迭代的鍵的集合,所以,HashMap是快速失敗的。另外一方面,Hashtable提供了對鍵的列舉(Enumeration)。
通常認爲Hashtable是一個遺留的類。
28.數組(Array)和列表(ArrayList)有什麼區別?何時應該使用Array而不是ArrayList?
下面列出了Array和ArrayList的不一樣點:
• Array能夠包含基本類型和對象類型,ArrayList只能包含對象類型。
• Array大小是固定的,ArrayList的大小是動態變化的。
• ArrayList提供了更多的方法和特性,好比:addAll(),removeAll(),iterator()等等。
• 對於基本類型數據,集合使用自動裝箱來減小編碼工做量。可是,當處理固定大小的基本數據類型的時候,這種方式相對比較慢。
29.ArrayList和LinkedList有什麼區別?
ArrayList和LinkedList都實現了List接口,他們有如下的不一樣點:
• ArrayList是基於索引的數據接口**,它的底層是數組**。它能夠以O(1)時間複雜度對元素進行隨機訪問。與此對應,LinkedList是以元素鏈表的形式存儲它的數據,每個元素都和它的前一個和後一個元素連接在一塊兒,在這種狀況下,查找某個元素的時間複雜度是O(n)。
• 相對於ArrayList,LinkedList的插入,添加,刪除操做速度更快,由於當元素被添加到集合任意位置的時候,不須要像數組那樣從新計算大小或者是更新索引。
• LinkedList比ArrayList更佔內存,由於LinkedList爲每個節點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。
也能夠參考ArrayList vs. LinkedList。
30.HashSet和TreeSet有什麼區別?
HashSet是由一個hash表來實現的,所以,它的元素是無序的。add(),remove(),contains()方法的時間複雜度是O(1)。
另外一方面,**TreeSet是由一個樹形的結構來實現的,它裏面的元素是有序的。**所以,add(),remove(),contains()方法的時間複雜度是O(logn)。
31.說出ArrayList,Vector, LinkedList的存儲性能和特性
list的子類特色 ArrayList: 底層數據結構是數組,查詢快,增刪慢 線程不安全,效率高
Vector: 底層數據結構是數組,查詢快,增刪慢 線程安全,效率低
LinkedList: 底層數據結構是鏈表,查詢慢,增刪快 線程不安全,效率高
32.Collection 和 Collections的區別
Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.
Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做。
-----------------------------------------------------------------------------IO-------------------------------------------------------------------------------------
1.java中有幾種類型的流?JDK爲每種類型的流提供了一些抽象類以供繼承,請說出他們分別是哪些類?
字節流和字符流。字節流繼承於InputStream、OutputStream,字符流繼承於Reader、Writer。在java.io 包中還有許多其餘的流,主要是爲了提升性能和使用方便。關於Java的I/O須要注意的有兩點:一是兩種對稱性(輸入和輸出的對稱性,字節和字符的對稱性);二是兩種設計模式(適配器模式和裝潢模式)
2.什麼是java序列化,如何實現java序列化?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。能夠對流化後的對象進行讀寫操做,也可將流化後的對象傳輸於網絡之間。序列化是爲了解決在對對象流進行讀寫操做時所引起的問題。
序列化的實現:將須要被序列化的類實現Serializable接口,該接口沒有須要實現的方法,implements Serializable只是爲了標註該對象是可被序列化的,而後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接着,使用ObjectOutputStream對象的writeObject(Object obj)方法就能夠將參數爲obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。
3.什麼是同步?什麼是異步?
同步和異步的概念出來已經好久了,網上有關同步和異步的說法也有不少。如下是我我的的理解:
同步就是:若是有多個任務或者事件要發生,這些任務或者事件必須逐個地進行,一個事件或者任務的執行會致使整個流程的暫時等待,這些事件沒有辦法併發地執行;異步就是:若是有多個任務或者事件發生,這些事件能夠併發地執行,一個事件或者任務的執行不會致使整個流程的暫時等待。這就是同步和異步。舉個簡單的例子,假若有一個任務包括兩個子任務A和B,對於同步來講,當A在執行的過程當中,B只有等待,直至A執行完畢,B才能執行;而對於異步就是A和B能夠併發地執行,B沒必要等待A執行完畢以後再執行,這樣就不會因爲A的執行致使整個任務的暫時等待。
4.什麼是阻塞?什麼是非阻塞?
在前面介紹了同步和異步的區別,這一節來看一下阻塞和非阻塞的區別。
阻塞就是:當某個事件或者任務在執行過程當中,它發出一個請求操做,可是因爲該請求操做須要的條件不知足,那麼就會一直在那等待,直至條件知足;
非阻塞就是:當某個事件或者任務在執行過程當中,它發出一個請求操做,若是該請求操做須要的條件不知足,會當即返回一個標誌信息告知條件不知足,不會一直在那等待。
這就是阻塞和非阻塞的區別。也就是說阻塞和非阻塞的區別關鍵在於當發出請求一個操做時,若是條件不知足,是會一直等待仍是返回一個標誌信息。
5.什麼是阻塞IO?什麼是非阻塞IO?
在瞭解阻塞IO和非阻塞IO以前,先看下一個具體的IO操做過程是怎麼進行的。
一般來講,IO操做包括:對硬盤的讀寫、對socket的讀寫以及外設的讀寫。
當用戶線程發起一個IO請求操做(本文以讀請求操做爲例),內核會去查看要讀取的數據是否就緒,對於阻塞IO來講,若是數據沒有就緒,則會一直在那等待,直到數據就緒;對於非阻塞IO來講,若是數據沒有就緒,則會返回一個標誌信息告知用戶線程當前要讀的數據沒有就緒。當數據就緒以後,便將數據拷貝到用戶線程,這樣才完成了一個完整的IO讀請求操做,也就是說一個完整的IO讀請求操做包括兩個階段:
1)查看數據是否就緒;
2)進行數據拷貝(內核將數據拷貝到用戶線程)。
那麼阻塞(blocking IO)和非阻塞(non-blocking IO)的區別就在於第一個階段,若是數據沒有就緒,在查看數據是否就緒的過程當中是一直等待,仍是直接返回一個標誌信息。
Java中傳統的IO都是阻塞IO,好比經過socket來讀數據,調用read()方法以後,若是數據沒有就緒,當前線程就會一直阻塞在read方法調用那裏,直到有數據才返回;而若是是非阻塞IO的話,當數據沒有就緒,read()方法應該返回一個標誌信息,告知當前線程數據沒有就緒,而不是一直在那裏等待。
6.什麼是同步IO?什麼是異步IO?
咱們先來看一下同步IO和異步IO的定義,在《Unix網絡編程》一書中對同步IO和異步IO的定義是這樣的:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.
從字面的意思能夠看出:同步IO即 若是一個線程請求進行IO操做,在IO操做完成以前,該線程會被阻塞;而異步IO爲 若是一個線程請求進行IO操做,IO操做不會致使請求線程被阻塞。
事實上,同步IO和異步IO模型是針對用戶線程和內核的交互來講的:
對於同步IO:當用戶發出IO請求操做以後,若是數據沒有就緒,須要經過用戶線程或者內核不斷地去輪詢數據是否就緒,當數據就緒時,再將數據從內核拷貝到用戶線程;
而異步IO:只有IO請求操做的發出是由用戶線程來進行的,IO操做的兩個階段都是由內核自動完成,而後發送通知告知用戶線程IO操做已經完成。也就是說在異步IO中,不會對用戶線程產生任何阻塞。
這是同步IO和異步IO關鍵區別所在,同步IO和異步IO的關鍵區別反映在數據拷貝階段是由用戶線程完成仍是內核完成。因此說異步IO必需要有操做系統的底層支持。
注意同步IO和異步IO與阻塞IO和非阻塞IO是不一樣的兩組概念。
阻塞IO和非阻塞IO是反映在當用戶請求IO操做時,若是數據沒有就緒,是用戶線程一直等待數據就緒,仍是會收到一個標誌信息這一點上面的。也就是說,阻塞IO和非阻塞IO是反映在IO操做的第一個階段,在查看數據是否就緒時是如何處理的。
7.NIO與IO的區別
NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的做用和目的,但實現方式不一樣,NIO主要用到的是塊,因此NIO的效率要比IO高不少。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另外一套就是網絡編程NIO。
1.面向流與面向緩衝
Java IO和NIO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 Java IO面向流意味着每次從流中讀一個或多個字節,直至讀取全部字節,它們沒有被緩存在任何地方。此外,它不能先後移動流中的數據。若是須要先後移動從流中讀取的數據,須要先將它緩存到一個緩衝區。 Java NIO的緩衝導向方法略有不一樣。數據讀取到一個它稍後處理的緩衝區,須要時可在緩衝區中先後移動。這就增長了處理過程當中的靈活性。可是,還須要檢查是否該緩衝區中包含全部您須要處理的數據。並且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏還沒有處理的數據。
2.阻塞與非阻塞IO
Java IO的各類流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據徹底寫入。該線程在此期間不能再幹任何事情了。Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,可是它僅能獲得目前可用的數據,若是目前沒有數據可用時,就什麼都不會獲取,而不是保持線程阻塞,因此直至數據變的能夠讀取以前,該線程能夠繼續作其餘的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不須要等待它徹底寫入,這個線程同時能夠去作別的事情。 線程一般將非阻塞IO的空閒時間用於在其它通道上執行IO操做,因此一個單獨的線程如今能夠管理多個輸入和輸出通道(channel)。
3.選擇器(Selectors)
Java NIO的選擇器容許一個單獨的線程來監視多個輸入通道,你能夠註冊多個通道使用一個選擇器,而後使用一個單獨的線程來「選擇」通道:這些通道里已經有能夠處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。
4.總結
NIO可以讓您只使用一個(或幾個)單線程管理多個通道(網絡鏈接或文件),但付出的代價是解析數據可能會比從一個阻塞流中讀取數據更復雜。
若是須要管理同時打開的成千上萬個鏈接,這些鏈接每次只是發送少許的數據,例如聊天服務器,實現NIO的服務器多是一個優點。一樣,若是你須要維持許多打開的鏈接到其餘計算機上,如P2P網絡中,使用一個單獨的線程來管理你全部出站鏈接,多是一個優點。
若是你有少許的鏈接使用很是高的帶寬,一次發送大量的數據,也許典型的IO服務器實現可能很是契合。
-----------------------------------------------------------------------------數據庫-------------------------------------------------------------------------------------
數據庫優化方面
1).儘量使用更小的整數類型.(mediumint就比int更合適).
2).儘量的定義字段爲not null,除非這個字段須要null.
3).若是沒有用到變長字段的話好比varchar,那就採用固定大小的紀錄格式好比char.
4).表的主索引應該儘量的短.這樣的話每條紀錄都有名字標誌且更高效.
5).只建立確實須要的索引。索引有利於檢索記錄,可是不利於快速保存記錄。若是老是要在表的組合字段上作搜索,那麼就在這些字段上建立索引。索引的第一部分必須是最常使用的字段.若是老是須要用到不少字段,首先就應該多複製這些字段,使索引更好的壓縮。
6).全部數據都得在保存到數據庫前進行處理。
7).全部字段都得有默認值。
8).在某些狀況下,把一個頻繁掃描的表分紅兩個速度會快好多。在對動態格式表掃描以取得相關記錄時,它可能使用更小的靜態格式表的狀況下更是如此。
2.系統的用途
1).儘可能使用長鏈接.
2).explain 複雜的SQL語句。
3).若是兩個關聯表要作比較話,作比較的字段必須類型和長度都一致.
4).LIMIT語句儘可能要跟order by或者 distinct.這樣能夠避免作一次full table scan.
5).若是想要清空表的全部紀錄,建議用truncate table tablename而不是delete from tablename.
6).能使用STORE PROCEDURE 或者 USER FUNCTION的時候.
7).在一條insert語句中採用多重紀錄插入格式.並且使用load data infile來導入大量數據,這比單純的indert快好多.
8).常常OPTIMIZE TABLE 來整理碎片.
9).還有就是date 類型的數據若是頻繁要作比較的話儘可能保存在unsigned int 類型比較快。
3.系統的瓶頸
1).磁盤搜索.
並行搜索,把數據分開存放到多個磁盤中,這樣能加快搜索時間.
2).磁盤讀寫(IO)
能夠從多個媒介中並行的讀取數據。
3).CPU週期
數據存放在主內存中.這樣就得增長CPU的個數來處理這些數據。
4).內存帶寬
當CPU要將更多的數據存放到CPU的緩存中來的話,內存的帶寬就成了瓶頸.
-----------------------------------------------------------------------------分佈式-------------------------------------------------------------------------------------
CAP原理:分佈式計算系統不可能同時確保如下三個特性:一致性(Consistency)、可用性(Availability)和分區容忍性(Partition),設計中每每須要弱化對某個特性的保證。
這裏,一致性、可用性和分區容忍性的含義以下:
一致性:任何操做應該都是原子的,發生在後面的事件能看到前面事件發生致使的結果,注意這裏指的是強一致性;
可用性:在有限時間內,任何非失敗節點都能應答請求;
分區容忍性:網絡可能發生分區,即節點之間的通訊不可保障。
比較直觀地理解以下,當網絡可能出現分區的時候,系統是沒法同時保證一致性和可用性的。要麼,節點收到請求後由於沒有獲得其餘節點的確認而不該答(犧牲可用性),要麼節點只能應答非一致的結果(犧牲一致性)。
因爲大多數時候網絡被認爲是可靠的,所以系統能夠提供一致可靠的服務;當網絡不可靠時,系統要麼犧牲掉一致性(多數場景下),要麼犧牲掉可用性。
注意:網絡分區是可能存在的,出現分區狀況後極可能會致使發生「腦裂」,多個新出現的主節點可能會嘗試關閉其餘主節點。
zookeeper:
ZooKeeper是一個開放源碼的分佈式協調服務,它是集羣的管理者,監視着集羣中各個節點的狀態根據節點提交的反饋進行下一步合理操做。最終,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
分佈式應用程序能夠基於Zookeeper實現諸如數據發佈/訂閱、負載均衡、命名服務、分佈式協調/通知、集羣管理、Master選舉、分佈式鎖和分佈式隊列等功能。
Zookeeper保證了以下分佈式一致性特性:
客戶端的讀請求能夠被集羣中的任意一臺機器處理,若是讀請求在節點上註冊了監聽器,這個監聽器也是由所鏈接的zookeeper機器來處理。對於寫請求,這些請求會同時發給其餘zookeeper機器而且達成一致後,請求才會返回成功。所以,隨着zookeeper的集羣機器增多,讀請求的吞吐會提升可是寫請求的吞吐會降低。
有序性是zookeeper中很是重要的一個特性,全部的更新都是全局有序的,每一個更新都有一個惟一的時間戳,這個時間戳稱爲zxid(Zookeeper Transaction Id)。而讀請求只會相對於更新有序,也就是讀請求的返回結果中會帶有這個zookeeper最新的zxid。
zookeeper負載均衡和nginx負載均衡區別
zk的負載均衡是能夠調控,nginx只是能調權重,其餘須要可控的都須要本身寫插件;可是nginx的吞吐量比zk大不少,應該說按業務選擇用哪一種方式。
Nginx
請解釋一下什麼是Nginx?
Nginx是一個web服務器和反向代理服務器,用於HTTP、HTTPS、SMTP、POP3和IMAP協議。
(1)RR輪詢,默認的反向代理模式,用以平衡各服務器的負載,若某個服務器宕機,會自動從輪詢中剃掉。同時,咱們能夠手動指定某臺服務器脫離輪詢,用於離線檢查或升級
(2)weight權重,針對服務器性能不通,用來控制服務器被訪問的比例。調節各服務器負載
(3)ip hash,ip_hash主要記錄了客戶端IP訪問的目標主機,以實現老用戶訪問時的快速調度。
四、Nginx是如何處理一個請求的呢?
首先,nginx在啓動時,會解析配置文件,獲得須要監聽的端口與ip地址,而後在nginx的master進程裏面
先初始化好這個監控的socket,再進行listen
而後再fork出多個子進程出來, 子進程會競爭accept新的鏈接。
此時,客戶端就能夠向nginx發起鏈接了。當客戶端與nginx進行三次握手,與nginx創建好一個鏈接後,此時,某一個子進程會accept成功,而後建立nginx對鏈接的封裝,即ngx_connection_t結構體接着,根據事件調用相應的事件處理模塊,如http模塊與客戶端進行數據的交換,最後,nginx或客戶端來主動關掉鏈接,到此,一個鏈接就壽終正寢了
docker
Docker 是一個開源的應用容器引擎,讓開發者能夠打包他們的應用以及依賴包到一個可移植的容器中,而後發佈到任何流行的Linux機器上,也能夠實現虛擬化,容器是徹底使用沙箱機制,相互之間不會有任何接口。
dubbo
-----------------------------------------------------------------------------spring boot +mybatis-------------------------------------------------------------------------------------
Spring Boot
Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各類啓動器,開發者能快速上手。
springboot自動配置的原理
在spring程序main方法中 添加@SpringBootApplication或者@EnableAutoConfiguration
會自動去maven中讀取每一個starter中的spring.factories文件 該文件裏配置了全部須要被建立spring容器中的bean
springboot讀取配置文件的方式
springboot默認讀取配置文件爲application.properties或者是application.yml
什麼是微服務
之前的模式是 全部的代碼在同一個工程中 部署在同一個服務器中 同一個項目的不一樣模塊不一樣功能互相搶佔資源
微服務 將工程根據不一樣的業務規則拆分紅微服務 微服務部署在不一樣的機器上 服務之間進行相互調用
Java微服務的框架有 dubbo(只能用來作微服務),spring cloud(提供了服務的發現,斷路器等)
springcloud如何實現服務的註冊和發現
服務在發佈時 指定對應的服務名(服務名包括了IP地址和端口) 將服務註冊到註冊中心(eureka或者zookeeper)
這一過程是springcloud自動實現 只須要在main方法添加@EnableDisscoveryClient 同一個服務修改端口就能夠啓動多個實例
調用方法:傳遞服務名稱經過註冊中心獲取全部的可用實例 經過負載均衡策略調用(ribbon和feign)對應的服務
ribbon和feign區別
Ribbon添加maven依賴 spring-starter-ribbon 使用@RibbonClient(value="服務名稱") 使用RestTemplate調用遠程服務對應的方法
feign添加maven依賴 spring-starter-feign 服務提供方提供對外接口 調用方使用 在接口上使用@FeignClient("指定服務名")
Ribbon和Feign的區別:
Ribbon和Feign都是用於調用其餘服務的,不過方式不一樣。
1.啓動類使用的註解不一樣,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
2.服務的指定位置不一樣,Ribbon是在@RibbonClient註解上聲明,Feign則是在定義抽象方法的接口中使用@FeignClient聲明。
3.調用方式不一樣,Ribbon須要本身構建http請求,模擬http請求而後使用RestTemplate發送給其餘服務,步驟至關繁瑣。
Feign則是在Ribbon的基礎上進行了一次改進,採用接口的方式,將須要調用的其餘服務的方法定義成抽象方法便可,
不須要本身構建http請求。不過要注意的是抽象方法的註解、方法簽名要和提供服務的方法徹底一致。
springcloud斷路器的做用
當一個服務調用另外一個服務因爲網絡緣由或者自身緣由出現問題時 調用者就會等待被調用者的響應 當更多的服務請求到這些資源時
致使更多的請求等待 這樣就會發生連鎖效應(雪崩效應) 斷路器就是解決這一問題
斷路器有徹底打開狀態
必定時間內 達到必定的次數沒法調用 而且屢次檢測沒有恢復的跡象 斷路器徹底打開,那麼下次請求就不會請求到該服務
半開
短期內 有恢復跡象 斷路器會將部分請求發給該服務 當能正常調用時 斷路器關閉
關閉
當服務一直處於正常狀態 能正常調用 斷路器關閉
----------------------------------------------------------------------------通訊--------------------------------------------------------------------------------------------------------
1.概念解釋:SOAP、WSDL、UDDI。
答:
- SOAP:簡單對象訪問協議(Simple Object Access Protocol),是Web Service中交換數據的一種協議規範。
- WSDL:Web服務描述語言(Web Service Description Language),它描述了Web服務的公共接口。這是一個基於XML的關於如何與Web服務通信和使用的服務描述;也就是描述與目錄中列出的Web服務進行交互時須要綁定的協議和信息格式。一般採用抽象語言描述該服務支持的操做和信息,使用的時候再將實際的網絡協議和信息格式綁定給該服務。
- UDDI:統一描述、發現和集成(Universal Description, Discovery and Integration),它是一個基於XML的跨平臺的描述規範,能夠使世界範圍內的企業在互聯網上發佈本身所提供的服務。簡單的說,UDDI是訪問各類WSDL的一個門面(能夠參考設計模式中的門面模式)。
WebService是一種跨編程語言和跨操做系統平臺的遠程調用技術。
2.WSDL是什麼,有什麼做用?
WSDL是web service definition language的縮寫,即web service的定義(描述)語言。
怎樣向別人介紹你的 web service 有什麼功能,以及每一個函數調用時的參數呢?你可能會本身寫一套文檔,你甚至可能會口頭上告訴須要使用你的web service的人。這些非正式的方法至少都有一個嚴重的問題:當程序員坐到電腦前,想要使用你的web service的時候,他們的工具(如Visual Studio)沒法給他們提供任何幫助,由於這些工具根本就不瞭解你的web service。解決方法是:用機器能閱讀的方式提供一個正式的描述文檔。web service描述語言(WSDL)就是這樣一個基於XML的語言,用於描述web service及其函數、參數和返回值。由於是基於XML的,因此WSDL既是機器可閱讀的,又是人可閱讀的,這將是一個很大的好處。一些最新的開發工具既能根據你的web service生成WSDL文檔,又能導入WSDL文檔,生成調用相應web service的代碼。
Webservice服務發佈以後,經過瀏覽器訪問發佈的+?wsdl便可得到wsdl文檔。
三.WSDL文檔主要有那幾部分組成,分別有什麼做用?
一個WSDL文檔的根元素是definitions元素,WSDL文檔包含7個重要的元素:types, import, message, portType, operations, binding和service元素。
一、 definitions元素中通常包括若干個XML命名空間;
二、 Types元素用做一個容器,定義了自定義的特殊數據類型,在聲明消息部分(有效負載)的時候,messages定義使用了types元素中定義的數據類型與元素;
三、 Import元素可讓當前的文檔使用其餘WSDL文檔中指定命名空間中的定義;
四、 Message元素描述了Web服務的有效負載。至關於函數調用中的參數和返回值;
五、 PortType元素定義了Web服務的抽象接口,它能夠由一個或者多個operation元素,每一個operation元素定義了一個RPC樣式或者文檔樣式的Web服務方法;
六、 Operation元素要用一個或者多個messages消息來定義它的輸入、輸出以及錯誤;
七、 Binding元素將一個抽象的portType映射到一組具體的協議(SOAP或者HTTP)、消息傳遞樣式(RPC或者document)以及編碼樣式(literal或者SOAP encoding);
八、 Service元素包含一個或者多個Port元素
每個Port元素對應一個不一樣的Web服務,port將一個URL賦予一個特定的binding,經過location實現。
能夠使兩個或者多個port元素將不一樣的URL賦給相同的binding。
四.SOAP是什麼?
SOAP是simple object access protocal的縮寫,即簡單對象訪問協議。 是基於XML和HTTP的一種通訊協議。是webservice所使用的一種傳輸協議,webservice之因此可以作到跨語言和跨平臺,主要是由於XML和HTTP都是獨立於語言和平臺的。Soap的消息分爲請求消息和響應消息,一條SOAP消息就是一個普通的XML文檔,包含下列元素:
一、 必需的 Envelope 元素,可把此XML文檔標識爲一條SOAP消息
二、 可選的 Header 元素,包含頭部信息
三、 必需的 Body 元素,包含全部的調用和響應信息
四、 可選的 Fault 元素,提供有關在處理此消息所發生錯誤的信息
Soap請求消息
Soap響應消息
五.怎麼理解UDDI?
UDDI是Universal Description Discovery and Integration的縮寫,即統一描述、發現和整合規範。用來註冊和查找服務,把web services收集和存儲起來,這樣當別人訪問這些信息的時候就從UDDI中查找,看有沒有這個信息存在。
五.Webservice的SEI指什麼?
WebService EndPoint Interface(webservice終端[Server端]接口)
六.說說你知道的webservice框架,他們都有什麼特色?
Webservice經常使用框架有JWS、Axis2、XFire以及CXF。
下面分別介紹一個這幾種Web Service框架的基本概念
1、JWS是Java語言對WebService服務的一種實現,用來開發和發佈服務。而從服務自己的角度來看JWS服務是沒有語言界限的。可是Java語言爲Java開發者提供便捷發佈和調用WebService服務的一種途徑。
2、Axis2是Apache下的一個重量級WebService框架,準確說它是一個Web Services / SOAP / WSDL 的引擎,是WebService框架的集大成者,它能不但能製做和發佈WebService,並且能夠生成Java和其餘語言版WebService客戶端和服務端代碼。這是它的優點所在。可是,這也不可避免的致使了Axis2的複雜性,使用過的開發者都知道,它所依賴的包數量和大小都是很驚人的,打包部署發佈都比較麻煩,不能很好的與現有應用整合爲一體。可是若是你要開發Java以外別的語言客戶端,Axis2提供的豐富工具將是你不二的選擇。
3、XFire是一個高性能的WebService框架,在Java6以前,它的知名度甚至超過了Apache的Axis2,XFire的優勢是開發方便,與現有的Web整合很好,能夠融爲一體,而且開發也很方便。可是對Java以外的語言,沒有提供相關的代碼工具。XFire後來被Apache收購了,緣由是它太優秀了,收購後,隨着Java6 JWS的興起,開源的WebService引擎已經再也不被看好,漸漸的都敗落了。
4、CXF是Apache旗下一個重磅的SOA簡易框架,它實現了ESB(企業服務總線)。CXF來自於XFire項目,通過改造後造成的,就像目前的Struts2來自WebWork同樣。能夠看出XFire的命運會和WebWork的命運同樣,最終會淡出人們的視線。CXF不可是一個優秀的Web Services / SOAP / WSDL 引擎,也是一個不錯的ESB總線,爲SOA的實施提供了一種選擇方案,固然他不是最好的,它僅僅實現了SOA架構的一部分。
注:對於Axis2與CXF之間的關係,一個是Axis2出現的時間較早,而CXF的追趕速度快。
如何抉擇:
1、若是應用程序須要多語言的支持,Axis2應當是首選了;
2、若是應用程序是遵循 spring哲學路線的話,Apache CXF是一種更好的選擇,特別對嵌入式的Web Services來講;
3、若是應用程序沒有新的特性須要的話,就還是用原來項目所用的框架,好比 Axis1,XFire,Celtrix或BEA等等廠家本身的Web Services實現,就別勞民傷財了。
MQ
爲何使用消息隊列?消息隊列的優勢和缺點?kafka、activemq、rabbitmq、rocketmq都有什麼優缺點?
消息隊列的常見使用場景有不少可是核心的有三個:解耦、異步、削峯
消息隊列的有點和缺點?
優勢:特殊場景下解耦、異步、削峯。
系統可用性下降:系統引入的外部依賴越多,越容易掛掉,原本你就是A系統調用BCD三個系統的接口就行了,人ABCD四個系統好好的沒什麼問題,你偏加個MQ進來,萬一MQ掛了怎麼辦,整套系統崩潰了,就完蛋了
系統複雜性提升:硬生生加個MQ進來,你怎麼保證消息沒有重複消費?怎麼處理消息丟失的狀況?怎麼保證消息傳遞的順序性?
一致性問題:系統A處理完了直接返回成功了,人家都認爲你這個請求成功了;但問題是,要是BCD三個系統哪裏BD系統成功了,結果C系統寫庫失敗了,咋整?數據就不一致了,
kafka、activemq、rabbitmq、rocketmq都有什麼優缺點?
特性
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
單機吞吐量 |
萬級,吞吐量比RocketMQ和Kafka要低了一個數量級 | 萬級,吞吐量比RocketMQ和Kafka要低了一個數量級 | 10萬級,RocketMQ也是能夠支撐高吞吐的一種MQ | 10萬級別,這是kafka最大的優勢,就是吞吐量高。
通常配合大數據類的系統來進行實時數據計算、日誌採集等場景 |
topic數量對吞吐量的影響 | topic能夠達到幾百,幾千個的級別,吞吐量會有較小幅度的降低
這是RocketMQ的一大優點,在同等機器下,能夠支撐大量的topic |
topic從幾十個到幾百個的時候,吞吐量會大幅度降低
因此在同等機器下,kafka儘可能保證topic數量不要過多。若是要支撐大規模topic,須要增長更多的機器資源 |
||
時效性 | ms級 | 微秒級,這是rabbitmq的一大特色,延遲是最低的 | ms級 | 延遲在ms級之內 |
可用性 | 高,基於主從架構實現高可用性 | 高,基於主從架構實現高可用性 | 很是高,分佈式架構 | 很是高,kafka是分佈式的,一個數據多個副本,少數機器宕機,不會丟失數據,不會致使不可用 |
消息可靠性 | 有較低的機率丟失數據 | 通過參數優化配置,能夠作到0丟失 | 通過參數優化配置,消息能夠作到0丟失 | |
功能支持 | MQ領域的功能極其完備 | 基於erlang開發,因此併發能力很強,性能極其好,延時很低 | MQ功能較爲完善,仍是分佈式的,擴展性好 |
功能較爲簡單,主要支持簡單的MQ功能,在大數據領域的實時計算以及日誌 採集被大規模使用,是事實上的標準 |
優劣勢總結 | 很是成熟,功能強大,在業內大量的公司以及項目中都有應用 偶爾會有較低機率丟失消息 並且如今社區以及國內應用都愈來愈少,官方社區如今對ActiveMQ 5.x維護愈來愈少,幾個月才發佈一個版本 並且確實主要是基於解耦和異步來用的,較少在大規模吞吐的場景中使用 |
erlang語言開發,性能極其好,延時很低; ,你很難去看懂源碼,你公司對這個東西的掌控很弱,基本職能依賴於開源社區的快速維護和修復bug。 |
接口簡單易用,並且畢竟在阿里大規模應用過,有阿里品牌保障 可靠性和可用性都是ok的,還能夠支撐大規模的topic數量,支持複雜MQ業務場景 塊不是按照標準JMS規範走的有些系統要遷移須要修改大量代碼 用RocketMQ挺好的 |
kafka的特色其實很明顯,就是僅僅提供較少的核心功能,可是提供超高 的吞吐量,ms級的延遲,極高的可用性以及可靠性,並且分佈式能夠任意擴展 影響,在大數據領域中以及日誌採集中,這點輕微影響能夠忽略 這個特性自然適合大數據實時計算以及日誌收集 |
1. 引入消息隊列以後如何保證其高可用性?
(1)RabbitMQ的高可用性
RabbitMQ是比較有表明性的,由於是基於主從作高可用性的,咱們就以他爲例子講解第一種MQ的高可用性怎麼實現。
rabbitmq有三種模式:單機模式,普通集羣模式,鏡像集羣模式
(1.1) 單機模式
就是demo級別的,通常就是你本地啓動了玩玩兒的,沒人生產用單機模式
(1.2)普通集羣模式
意思就是在多臺機器上啓動多個rabbitmq實例,每一個機器啓動一個。可是你建立的queue,只會放在一個rabbtimq實例上,可是每一個實例都同步queue的元數據。完了你消費的時候,實際上若是鏈接到了另一個實例,那麼那個實例會從queue所在實例上拉取數據過來。
這種方式確實很麻煩,也不怎麼好,沒作到所謂的分佈式,就是個普通集羣。由於這致使你要麼消費者每次隨機鏈接一個實例而後拉取數據,要麼固定鏈接那個queue所在實例消費數據,前者有數據拉取的開銷,後者致使單實例性能瓶頸。
並且若是那個放queue的實例宕機了,會致使接下來其餘實例就沒法從那個實例拉取,若是你開啓了消息持久化,讓rabbitmq落地存儲消息的話,消息不必定會丟,得等這個實例恢復了,而後才能夠繼續從這個queue拉取數據。
因此這個事兒就比較尷尬了,這就沒有什麼所謂的高可用性可言了,這方案主要是提升吞吐量的,就是說讓集羣中多個節點來服務某個queue的讀寫操做。
1.3)鏡像集羣模式
這種模式,纔是所謂的rabbitmq的高可用模式,跟普通集羣模式不同的是,你建立的queue,不管元數據仍是queue裏的消息都會存在於多個實例上,而後每次你寫消息到queue的時候,都會自動把消息到多個實例的queue裏進行消息同步。
這樣的話,好處在於,你任何一個機器宕機了,沒事兒,別的機器均可以用。壞處在於,第一,這個性能開銷也太大了吧,消息同步全部機器,致使網絡帶寬壓力和消耗很重!第二,這麼玩兒,就沒有擴展性可言了,若是某個queue負載很重,你加機器,新增的機器也包含了這個queue的全部數據,並無辦法線性擴展你的queue
那麼怎麼開啓這個鏡像集羣模式呢?我這裏簡單說一下,避免面試人家問你你不知道,其實很簡單rabbitmq有很好的管理控制檯,就是在後臺新增一個策略,這個策略是鏡像集羣模式的策略,指定的時候能夠要求數據同步到全部節點的,也能夠要求就同步到指定數量的節點,而後你再次建立queue的時候,應用這個策略,就會自動將數據同步到其餘的節點上去了。
(2)kafka
1)消費端弄丟了數據
惟一可能致使消費者弄丟數據的狀況,就是說,你那個消費到了這個消息,而後消費者那邊自動提交了offset,讓kafka覺得你已經消費好了這個消息,其實你剛準備處理這個消息,你還沒處理,你本身就掛了,此時這條消息就丟咯。
這不是同樣麼,你們都知道kafka會自動提交offset,那麼只要關閉自動提交offset,在處理完以後本身手動提交offset,就能夠保證數據不會丟。可是此時確實仍是會重複消費,好比你剛處理完,還沒提交offset,結果本身掛了,此時確定會重複消費一次,本身保證冪等性就行了。
生產環境碰到的一個問題,就是說咱們的kafka消費者消費到了數據以後是寫到一個內存的queue裏先緩衝一下,結果有的時候,你剛把消息寫入內存queue,而後消費者會自動提交offset。
而後此時咱們重啓了系統,就會致使內存queue裏還沒來得及處理的數據就丟失了
2)kafka弄丟了數據
這塊比較常見的一個場景,就是kafka某個broker宕機,而後從新選舉partiton的leader時。你們想一想,要是此時其餘的follower恰好還有些數據沒有同步,結果此時leader掛了,而後選舉某個follower成leader以後,他不就少了一些數據?這就丟了一些數據啊。
生產環境也遇到過,咱們也是,以前kafka的leader機器宕機了,將follower切換爲leader以後,就會發現說這個數據就丟了
因此此時通常是要求起碼設置以下4個參數:
給這個topic設置replication.factor參數:這個值必須大於1,要求每一個partition必須有至少2個副本
在kafka服務端設置min.insync.replicas參數:這個值必須大於1,這個是要求一個leader至少感知到有至少一個follower還跟本身保持聯繫,沒掉隊,這樣才能確保leader掛了還有一個follower吧
在producer端設置acks=all:這個是要求每條數據,必須是寫入全部replica以後,才能認爲是寫成功了
在producer端設置retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試,卡在這裏了
咱們生產環境就是按照上述要求配置的,這樣配置以後,至少在kafka broker端就能夠保證在leader所在broker發生故障,進行leader切換時,數據不會丟失
3)生產者會不會弄丟數據
若是按照上述的思路設置了ack=all,必定不會丟,要求是,你的leader接收到消息,全部的follower都同步到了消息以後,才認爲本次寫成功了。若是沒知足這個條件,生產者會自動不斷的重試,重試無限次。
1. 如何保證消息的順序性?
其實這個也是用MQ的時候必問的話題,第一看看你瞭解不瞭解順序這個事兒?第二看看你有沒有辦法保證消息是有順序的?這個生產系統中常見的問題。
我舉個例子,咱們之前作過一個mysql binlog同步的系統,壓力仍是很是大的,日同步數據要達到上億。mysql -> mysql,常見的一點在於說大數據team,就須要同步一個mysql庫過來,對公司的業務系統的數據作各類複雜的操做。
你在mysql裏增刪改一條數據,對應出來了增刪改3條binlog,接着這三條binlog發送到MQ裏面,到消費出來依次執行,起碼得保證人家是按照順序來的吧?否則原本是:增長、修改、刪除;你楞是換了順序給執行成刪除、修改、增長,不全錯了麼。
原本這個數據同步過來,應該最後這個數據被刪除了;結果你搞錯了這個順序,最後這個數據保留下來了,數據同步就出錯了。
先看看順序會錯亂的倆場景
(1)rabbitmq:一個queue,多個consumer,這不明顯亂了
(2)kafka:一個topic,一個partition,一個consumer,內部多線程,這不也明顯亂了
那如何保證消息的順序性呢?簡單簡單
(1)rabbitmq:拆分多個queue,每一個queue一個consumer,就是多一些queue而已,確實是麻煩點;或者就一個queue可是對應一個consumer,而後這個consumer內部用內存隊列作排隊,而後分發給底層不一樣的worker來處理
(2)kafka:一個topic,一個partition,一個consumer,內部單線程消費,寫N個內存queue,而後N個線程分別消費一個內存queue便可
1. 如何解決消息隊列的延時以及過時失效問題?消息隊列滿了之後該怎麼處理?有幾百萬消息持續積壓幾小時,說說怎麼解決?
你看這問法,其實本質針對的場景,都是說,可能你的消費端出了問題,不消費了,或者消費的極其極其慢。接着就坑爹了,可能你的消息隊列集羣的磁盤都快寫滿了,都沒人消費,這個時候怎麼辦?或者是整個這就積壓了幾個小時,你這個時候怎麼辦?或者是你積壓的時間太長了,致使好比rabbitmq設置了消息過時時間後就沒了怎麼辦?
因此就這事兒,其實線上挺常見的,通常不出,一出就是大case,通常常見於,舉個例子,消費端每次消費以後要寫mysql,結果mysql掛了,消費端hang那兒了,不動了。或者是消費端出了個什麼叉子,致使消費速度極其慢。
關於這個事兒,咱們一個一個來梳理吧,先假設一個場景,咱們如今消費端出故障了,而後大量消息在mq裏積壓,如今事故了,慌了
(1)大量消息在mq裏積壓了幾個小時了還沒解決
幾千萬條數據在MQ裏積壓了七八個小時,從下午4點多,積壓到了晚上很晚,10點多,11點多
這個是咱們真實遇到過的一個場景,確實是線上故障了,這個時候要否則就是修復consumer的問題,讓他恢復消費速度,而後傻傻的等待幾個小時消費完畢。這個確定不能在面試的時候說吧。
一個消費者一秒是1000條,一秒3個消費者是3000條,一分鐘是18萬條,1000多萬條
因此若是你積壓了幾百萬到上千萬的數據,即便消費者恢復了,也須要大概1小時的時間才能恢復過來
通常這個時候,只能操做臨時緊急擴容了,具體操做步驟和思路以下:
1)先修復consumer的問題,確保其恢復消費速度,而後將現有cnosumer都停掉
2)新建一個topic,partition是原來的10倍,臨時創建好原先10倍或者20倍的queue數量
3)而後寫一個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據,消費以後不作耗時的處理,直接均勻輪詢寫入臨時創建好的10倍數量的queue
4)接着臨時徵用10倍的機器來部署consumer,每一批consumer消費一個臨時queue的數據
5)這種作法至關因而臨時將queue資源和consumer資源擴大10倍,以正常的10倍速度來消費數據
6)等快速消費完積壓數據以後,得恢復原先部署架構,從新用原先的consumer機器來消費消息
(2)這裏咱們假設再來第二個坑
假設你用的是rabbitmq,rabbitmq是能夠設置過時時間的,就是TTL,若是消息在queue中積壓超過必定的時間就會被rabbitmq給清理掉,這個數據就沒了。那這就是第二個坑了。這就不是說數據會大量積壓在mq裏,而是大量的數據會直接搞丟。
這個狀況下,就不是說要增長consumer消費積壓的消息,由於實際上沒啥積壓,而是丟了大量的消息。咱們能夠採起一個方案,就是批量重導,這個咱們以前線上也有相似的場景幹過。就是大量積壓的時候,咱們當時就直接丟棄數據了,而後等過了高峯期之後,好比你們一塊兒喝咖啡熬夜到晚上12點之後,用戶都睡覺了。
這個時候咱們就開始寫程序,將丟失的那批數據,寫個臨時程序,一點一點的查出來,而後從新灌入mq裏面去,把白天丟的數據給他補回來。也只能是這樣了。
假設1萬個訂單積壓在mq裏面,沒有處理,其中1000個訂單都丟了,你只能手動寫程序把那1000個訂單給查出來,手動發到mq裏去再補一次
(3)而後咱們再來假設第三個坑
若是走的方式是消息積壓在mq裏,那麼若是你很長時間都沒處理掉,此時致使mq都快寫滿了,咋辦?這個還有別的辦法嗎?沒有,誰讓你第一個方案執行的太慢了,你臨時寫程序,接入數據來消費,消費一個丟棄一個,都不要了,快速消費掉全部的消息。而後走第二個方案,到了晚上再補數據吧。
1. 若是讓你寫一個消息隊列,該如何進行架構設計啊?說一下你的思路
其實聊到這個問題,通常面試官要考察兩塊:
(1)你有沒有對某一個消息隊列作過較爲深刻的原理的瞭解,或者從總體瞭解把握住一個mq的架構原理
(2)看看你的設計能力,給你一個常見的系統,就是消息隊列系統,看看你能不能從全局把握一下總體架構設計,給出一些關鍵點出來
其實回答這類問題,說白了,起碼不求你看過那技術的源碼,起碼你大概知道那個技術的基本原理,核心組成部分,基本架構構成,而後參照一些開源的技術把一個系統設計出來的思路說一下就好
好比說這個消息隊列系統,咱們來從如下幾個角度來考慮一下
說實話,我通常面相似問題的時候,大部分人基本都會蒙,由於平時歷來沒有思考過相似的問題,大多數人就是平時埋頭用,歷來不去思考背後的一些東西。相似的問題,我常常問的還有,若是讓你來設計一個spring框架你會怎麼作?若是讓你來設計一個dubbo框架你會怎麼作?若是讓你來設計一個mybatis框架你會怎麼作?
其實回答這類問題,說白了,起碼不求你看過那技術的源碼,起碼你大概知道那個技術的基本原理,核心組成部分,基本架構構成,而後參照一些開源的技術把一個系統設計出來的思路說一下就好
好比說這個消息隊列系統,咱們來從如下幾個角度來考慮一下
(1)首先這個mq得支持可伸縮性吧,就是須要的時候快速擴容,就能夠增長吞吐量和容量,那怎麼搞?設計個分佈式的系統唄,參照一下kafka的設計理念,broker -> topic -> partition,每一個partition放一個機器,就存一部分數據。若是如今資源不夠了,簡單啊,給topic增長partition,而後作數據遷移,增長機器,不就能夠存放更多數據,提供更高的吞吐量了?
(2)其次你得考慮一下這個mq的數據要不要落地磁盤吧?那確定要了,落磁盤,才能保證別進程掛了數據就丟了。那落磁盤的時候怎麼落啊?順序寫,這樣就沒有磁盤隨機讀寫的尋址開銷,磁盤順序讀寫的性能是很高的,這就是kafka的思路。
其次你考慮一下你的mq的可用性啊?這個事兒,具體參考咱們以前可用性那個環節講解的kafka的高可用保障機制。多副本 -> leader & follower -> broker掛了從新選舉leader便可對外服務。
(4)能不能支持數據0丟失啊?能夠的,參考咱們以前說的那個kafka數據零丟失方案
restful
談談你對restful 規範的理解? - restful其實就是一套編寫接口的協議,協議規定如何編寫以及如何設置返回值、狀態碼等信息。 - 最顯著的特色: restful: 給用戶一個url,根據method不一樣在後端作不一樣的處理,好比:post 建立數據、get獲取數據、put和patch修改數據、delete刪除數據。
restful與webservice的區別
首先須要瞭解:REST是一種架構風格,其核心是面向資源;而webService底層SOAP協議,主要核心是面向活動;
SOAP
什麼是SOAP,我想不用多說,google一把滿眼都是。其實SOAP最先是針對RPC的一種解決方案,簡單對象訪問協議,很輕量,同時做爲應用協議能夠基於多種傳輸協議來傳遞消息(Http,SMTP等)。可是隨着SOAP做爲WebService的普遍應用,不斷地增長附加的內容,使得如今開發人員以爲SOAP很重,使用門檻很高。在SOAP後續的發展過程當中,WS-*一系列協議的制定,增長了SOAP的成熟度,也給SOAP增長了負擔。
REST
REST其實並非什麼協議也不是什麼標準,而是將Http協議的設計初衷做了詮釋,在Http協議被普遍利用的今天,愈來愈多的是將其做爲傳輸協議,而非原先設計者所考慮的應用協議。SOAP類型的WebService就是最好的例子,SOAP消息徹底就是將Http協議做爲消息承載,以致於對於Http協議中的各類參數(例如編碼,錯誤碼等)都置之不顧。其實,最輕量級的應用協議就是Http協議。Http協議所抽象的get,post,put,delete就比如數據庫中最基本的增刪改查,而互聯網上的各類資源就比如數據庫中的記錄,對於各類資源的操做最後老是能抽象成爲這四種基本操做,在定義了定位資源的規則之後,對於資源的操做經過標準的Http協議就能夠實現,開發者也會受益於這種輕量級的協議。
REST專門針對網絡應用設計和開發方式,以下降開發的複雜性,提升系統的可伸縮性。REST提出設計概念和準則爲:
1. 網絡上的全部事物均可以被抽象爲資源(resource)
2. 每個資源都有惟一的資源標識(resource identifier),對資源的操做不會改變這些標識
3. 全部的操做都是無狀態的
REST簡化開發,其架構遵循CRUD原則,該原則告訴咱們對於資源(包括網絡資源)只須要四種行爲:建立,獲取,更新和刪除就能夠完成相關的操做和處理。咱們能夠經過統一資源標識符(Universal Resource Identifier,URI)來識別和定位資源,而且針對這些資源而執行的操做是經過 HTTP 規範定義的。其核心操做只有GET,PUT,POST,DELETE。因爲REST強制全部的操做都必須是stateless的,這就沒有上下文的約束,若是作分佈式,集羣都不須要考慮上下文和會話保持的問題。極大的提升系統的可伸縮性。
SOAP webService有嚴格的規範和標準,包括安全,事務等各個方面的內容,同時SOAP強調操做方法和操做對象的分離,有WSDL文件規範和XSD文件分別對其定義。
若是從這個意義上講,是否使用REST就須要考慮資源自己的抽象和識別是否困難,若是自己就是簡單的相似增刪改查的業務操做,那麼抽象資源就比較容易,而對於複雜的業務活動抽象資源並非一個簡單的事情。好比校驗用戶等級,轉帳,事務處理等,這些每每並不容易簡單的抽象爲資源。
其次若是有嚴格的規範和標準定義要求,並且前期規範標準須要指導多個業務系統集成和開發的時候,SOAP風格因爲有清晰的規範標準定義是明顯有優點的。咱們能夠在開始和實現以前就嚴格定義相關的接口方法和接口傳輸數據。(不少狀況下是爲了兼容之前項目且前臺調用邏輯代碼都不能動的前提下,更改底層應用,通常就須要使用webService模式開發,由於老代碼中已經有了明確的方法定義以及參數類型、個數等申明)
簡單數據操做,無事務處理,開發和調用簡單這些是使用REST架構風格的優點。而對於較爲複雜的面向活動的服務,若是咱們仍是使用REST,不少時候都是仍然是傳統的面向活動的思想經過轉換工具再轉換獲得REST服務,這種使用方式是沒有意義的。