java基本類型哪些,所佔字節css
byte :1個字節html
short :2個字節前端
char :2個字節vue
int :4個字節java
long :8個字節node
float :4個字節mysql
double :8個字節react
java集合以及底層原理linux
Java集合框架的根接口有Collection和Map。Collection根接口包含List和Set二個子接口。nginx
List接口
它的特色是:元素有序、且可重複,主要包含三個實現類:ArrayList,vector,LinkedList
ArrayList的特色:底層是數組,線程不安全,查找快,增刪慢(數組的特色)。
ArrayList的底層實現原理:經過ArrrayList空參構造器建立對象。
底層建立一個長度爲10的數組,當咱們向數組中添加11個元素時,底層會進行擴容,擴容爲原來的1.5倍
(建立一個新的數組,長度爲原數組長度的1.5倍,將原數組複製到新數組中)。
vector的特色:古老的實現類,底層是數組,線程安全的,JDK1.0就有了,Vector老是比ArrayList慢,因此儘可能避免使用。
LinkedList的特色:底層是使用雙向鏈表。增刪快,查找慢。
Set接口
它的特色:
無序性:經過HashCode方法算出的值來決定在數組中存放的位置;
不可重複性:進行equals方法比較,結果爲true則兩個數據相同,若爲false則不一樣。
主要包含三個實現類:HashSet,LinkedHashSet,TreeSet
HashSet特色:線程不安全,集合元素能夠爲null,不能保證元素的排列順序
HashSet的底層實現原理:
當向HashSet添加數據時,首先調用HashCode方法決定數據存放在數組中的位置,該位置上沒有其餘元素,
則將數據直接存放,若該位置上有其餘元素,調用equals方法進行比較。若返回true則認爲兩個數據相同,
若返回false,則以鏈表的形式將該數據存在該位置上,(jdk1.8)若是數量達到8則將鏈表換成紅黑樹。
HashSet的底層就是一個HashMap,向HashSet中添加的數據實際上添加到了HashMap中的key裏。
因此HashMap的key能夠當作是Set的集合。
LinkedHashSet特色:繼承了HashSet,底層實現原理和HashSet同樣,能夠安照元素添加的順序進行遍歷
根據元素的hashCode值來決定元素的存儲位置,它維護了一張鏈表該鏈表記錄了元素添加的順序。
底層就是一個LinkedHashMap。
TreeSet特色:底層爲紅黑樹;能夠安照指定的元素進行排序;TreeSet中的元素類型必須保持一致,
底層就是TreeMap。TreeSet必須(天然排序)實現Comparable接口,重寫compareTo()方法,
按照某個屬性進行排序,相結合添加元素或(定製排序)建立一個Comparator實現類的對象,
並傳入到TreeSet的構造器中,按照某個屬性進行排序,向集合添加元素。定製排序比天然排序靈活。
若是即有天然排序又有定製排序誰起做用? 定製排序
Map接口
Map的特色:
Map存儲的是鍵值對(key,value),Map中的key是無序的且不可重複的,全部的key能夠當作是一個set集合。
Map中的key若是是自定義類的對象必須重寫hashCode和equals方法,Map中的value是無序的可重複的,
全部的value能夠當作是Collection集合,Map中的value若是是自定義類的對象必須重寫equals方法,
Map中的鍵值對能夠當作是一個一個的Entry.Entry所存放的位置是由key來決定的。
Entry是無序的不可重複的。主要的實現類:HashMap,LinkedHashMap,TreeMap,HashTable.
HashMap特色
1.底層是一個數組 + 鏈表 + 紅黑樹(jdk1.8)
2.數組的類型是一個Node類型
3.Node中有key和value的屬性
4.根據key的hashCode方法來決定Node存放的位置
5.線程不安全的 ,能夠存放null
HashMap的底層實現原理:
當咱們向HashMap中存放一個元素(k1,v1),先根據k1的hashCode方法來決定在數組中存放的位置。
若是該位置沒有其它元素則將(k1,v1)直接放入數組中,若是該位置已經有其它元素(k2,v2),調用k1的equals方法和k2進行比較。
若是結果爲true則用v1替換v2,若是返回值爲false則以鏈表的形式將(k1,v1)存放,
當元素達到8時則會將鏈表替換成紅黑樹以提升查找效率。
HashMap的構造器:new HashMap() :建立一個容量爲16的數組,加載因子爲0.75。
當咱們添加的數據超過12時底層會進行擴容,擴容爲原來的2倍。
LinkedHashMap:繼承了HashMap底層實現和HashMap同樣.
能夠安照元素添加的順序進行遍歷底層維護了一張鏈表用來記錄元素添加的順序。
TreeMap特色:能夠對Key中的元素安照指定的順序進行排序 ( 不能對value進行排序)
HashTable特色:線程安全的 ,不能夠存放null,map中的key不能重複,若是有重複的,後者的value覆蓋前者的value
四大做用域和九大內置對象
四大做用域:
page :當前頁面有效時間最短(頁面執行期)
request :HTTP請求開始到結束這段時間
session :HTTP會話開始到結束這段時間
application :服務器啓動到中止這段時間
九大內置對象:
request :請求對象 做用域 Request
response :響應對象 做用域 Page
pageContext :頁面上下文對象 做用域 Page
session :會話對象 做用域 Session
application :應用程序對象 做用域 Application
out :輸出對象 做用域 Page
config :配置對象 做用域 Page
page :頁面對象 做用域 Page
exception :例外對象 做用域 page
jsp和servlet的區別
1.jsp經編譯後就變成了Servlet.(JSP的本質就是Servlet,JVM只能識別java的類,
不能識別JSP的代碼,Web容器將JSP的代碼編譯成JVM可以識別的java類)
2.jsp更擅長表現於頁面顯示,servlet更擅長於邏輯控制.
3.Servlet中沒有內置對象,Jsp中的內置對象都是必須經過HttpServletRequest象,
HttpServletResponse對象以及HttpServlet對象獲得.
Jsp是Servlet的一種簡化,使用Jsp只須要完成程序員須要輸出到客戶端的內容,Jsp中的Java腳本如何鑲嵌到一個類中,由Jsp容器完成。
而Servlet則是個完整的Java類,這個類的Service方法用於生成對客戶端的響應。
servlet生命週期
1.加載和實例化
2.初始化
3.請求處理
4.服務終止
加載(服務器啓動時,會到web.xml文件中去找到Servlet文件的配置並建立servlet的實例)
→初始化(init()此方法只執行一次) →執行(service(),doGet(),doPost()) →銷燬(銷燬destory())
service():
方法自己包含了doGet()和doPost().若是服務器發現了service()方法,則再也不執行doGet(),doPost().
通常不建議去重寫父類的service方法.由於重寫了此方法doGet方法和doPost方法將得不到利用.
沒有service()方法默認執行doGet()方法.
cookie和session區別
一、cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
二、cookie不是很安全,別人能夠分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session。
三、session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能,考慮到減輕服務器性能方面,應當使用cookie。
四、單個cookie保存的數據不能超過4K,不少瀏覽器都限制一個站點最多保存20個cookie。
五、能夠考慮將登錄信息等重要信息存放爲session,其餘信息若是須要保留,能夠放在cookie中。
轉發和重定向的區別
餓漢於懶漢單例模式
單例模式設計:
第一步:私有化構造器
第二步:提供一個公共靜態返回該類實例對象的方法
餓漢式:先初始化對象,Single類一進內存,就已經建立好了對象。
class Single{
private Single(){}
private static Single s=new Single();
public static Single getInstance()
{
return s;
}
}
懶漢式:對象是方法被調用時,才初始化,也叫作對象的延時加載。
class Single{ //Single類進內存,對象還沒存在,只有調用了getInstance方法時,才創建對象
private Single(){}
private static Single s=null;
public static synchronize Single getInstance()
{
if(s==null){
s=new single();
}
return s;
}
}
操做共享的數據有多條,會出現線程安全問題,在方法加一個同步
過濾器和攔截器的區別
①攔截器是基於java的反射機制的,而過濾器是基於函數回調。
②攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
③攔截器只能對action請求起做用,而過濾器則能夠對幾乎全部的請求起做用。
④攔截器能夠訪問action上下文、值棧裏的對象,而過濾器不能訪問。
⑤在action的生命週期中,攔截器能夠屢次被調用,而過濾器只能在容器初始化時被調用一次。
⑥攔截器能夠獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裏注入一個service,能夠調用業務邏輯。
#和$的區別
#{}和${}的區別
#{} 在mapper的配置文件的sql語句中,它是佔位符, 至關於 ? 號。
${} 在 mapper 的配置文件的 sql 語句中,它是原樣輸出變量的值,而後以字符串拼接的功能進行操做。
${} 中只能寫value,或者是@Param命名參數後的參數名稱
在輸出參數的時候,咱們並不推薦使用 ${} 來輸出。由於可能會導至 sql 注入問題的存在。
什麼是SQL注入?
若是SQL是根據用戶輸入拼出來,若是用戶故意輸入可讓後臺解析失敗的字符串,這就是SQL注入
例如,用戶在輸入密碼的時候,輸入' or 1=1', 這樣,後臺的程序在解析的時候,拼成的SQL語句,多是這樣的:
select count(1) from tab where user=userinput and pass='' or 1=1;
看這條語句,能夠知道,在解析以後,用戶沒有輸入密碼,加了一個恆等的條件 1=1,這樣,這段SQL執行的時候,
返回的 count值確定大於1的,若是程序的邏輯沒加過多的判斷,這樣就可以使用用戶名 userinput登錄,而不須要密碼。
防止SQL注入,首先要對密碼輸入中的單引號進行過濾,再在後面加其它的邏輯判斷,或者不用這樣的動態SQL拼。
&&和&與|和||的區別?
&和&&的區別?
&和&&左邊的式子爲true的時候,右邊的式子都會執行。
左邊的式子爲false的時候。&右邊的式子仍然會執行。&&右邊的式子將再也不執行。
|和||的區別?
|和||左邊的式子爲false的時候,右邊的式子都會執行。
左邊的式子爲true的時候。|右邊的式子仍然會執行。||右邊的式子將再也不執行。
final finally finalize區別?
final修飾符,用來修飾變量,方法和類,分別表示屬性不可變,方法不可被重寫,類不可被繼承,finally是異常語句中處理語句,
表示老是執行;finalize表示在垃圾回收機制時使該對象狀態恢復的方法
int和Integer的區別?
一、Integer是int的包裝類,int則是java的一種基本數據類型
二、Integer變量必須實例化後才能使用,而int變量不須要
三、Integer實際是對象的引用,當new一個Integer時,其實是生成一個指針指向此對象;而int則是直接存儲數據值
四、Integer的默認值是null,int的默認值是0
equals與==的區別?
==:若是==兩邊是基本數據類型,那麼比較的是具體的值。若是==兩邊是引用數據類型,那麼比較的是地址值。
(兩個對象是否指向同一塊內存)
equals:若是沒有重寫equals方法那麼調用的是Object中的equals方法,比較的是地址值。
若是重寫了euqlas方法(比屬性內容)那麼就比較的是對象中屬性的內容。
StringBuff 和StringBuilder及String區別?
String類是不可變類,任何對String的改變都會引起新的String對象的生成;
StringBuffer是可變類,任何對它所指代的字符串的改變都不會產生新的對象,線程安全的。
StringBuilder是可變類,線性不安全的,不支持併發操做,不適合多線程中使用,但其在單線程中的性能比StringBuffer高。
Override和Overload的含義去區別?
1. Override 特色
一、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果;
二、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
三、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
四、方法被定義爲final不能被重寫。
五、對於繼承來講,若是某一方法在父類中是訪問權限是private,那麼就不能在子類對其進行重寫覆蓋,若是定義的話,
也只是定義了一個新方法,而不會達到重寫覆蓋的效果。(一般存在於父類和子類之間。)
2.Overload 特色
一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序
固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int, float), 可是不能爲fun(int, int)
二、不能經過訪問權限、返回類型、拋出的異常進行重載;
三、方法的異常類型和數目不會對重載形成影響;
四、重載事件一般發生在同一個類中,不一樣方法之間的現象。
五、存在於同一類中,可是隻有虛方法和抽象方法才能被覆寫。
抽象類和接口及普通類的區別?
一、抽象類和接口都不能直接實例化,若是要實例化,抽象類變量必須指向實現全部抽象方法的子類對象,
接口變量必須指向實現全部接口方法的類對象。
二、抽象類要被子類繼承,接口要被類實現。
三、接口只能作方法申明,抽象類中能夠作方法申明,也能夠作方法實現
四、接口裏定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量。
五、抽象類裏的抽象方法必須所有被子類所實現,若是子類不能所有實現父類抽象方法,那麼該子類只能是抽象類。
一樣,一個實現接口的時候,如不能所有實現接口方法,那麼該類也只能爲抽象類。
六、抽象方法只能申明,不能實現,接口是設計的結果 ,抽象類是重構的結果
七、抽象類裏能夠沒有抽象方法
八、若是一個類裏有抽象方法,那麼這個類只能是抽象類
九、抽象方法要被實現,因此不能是靜態的,也不能是私有的。
十、接口可繼承接口,並可多繼承接口,但類只能單根繼承。
堆和棧的區別?
一.堆棧空間分配區別:
1.棧(操做系統):由操做系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧;
2.堆(操做系統): 通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收,分配方式卻是相似於鏈表。
二.堆棧緩存方式區別:
1.棧使用的是一級緩存, 他們一般都是被調用時處於存儲空間中,調用完畢當即釋放;
2.堆是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並非一旦成爲孤兒對象就能被回收)。
因此調用這些對象的速度要相對來得低一些。
三.堆棧數據結構區別:
堆(數據結構):堆能夠被當作是一棵樹,如:堆排序;
棧(數據結構):一種先進後出的數據結構。
Spring Bean生命週期
JDK、JRE、JVM的區別?
JDK ( Java開發工具包)= JRE(Java運行環境) + 開發工具集(例如Javac編譯工具等)
JRE (Java運行環境)= JVM (Java虛擬機)+ Java SE標準類庫
值傳遞和引用傳遞的區別?
值傳遞:方法調用時,實際參數把它的值傳遞給對應的形式參數,方法執行中形式參數值的改變不影響實際參數的值。
引用傳遞:也稱爲傳地址。方法調用時,實際參數的引用(地址,而不是參數的值)被傳遞給方法中相對應的形式參數,
在方法執行中,對形式參數的操做實際上就是對實際參數的操做,方法執行中形式參數值的改變將會影響實際參數的值。
4種訪問控制符區別?
訪問權限 類 包 子類 其餘包
public ∨ ∨ ∨ ∨
protect ∨ ∨ ∨ ×
default ∨ ∨ × ×
private ∨ × × ×
裝箱和拆箱,類型轉換
裝箱:值類型轉換爲引用對象,通常是轉換爲System.Object類型或值類型實現的接口引用類型;
拆箱:引用類型轉換爲值類型,注意,這裏的引用類型只能是被裝箱的引用類型對象;
拆箱與裝箱就是值類型與引用類型的轉換
throw和throws區別
throw表明動做,表示拋出一個異常的動做;
throws表明一種狀態,表明方法可能有異常拋出;
throw用在方法實現中,而throws用在方法聲明中;
throw只能用於拋出一種異常,而throws能夠拋出多個異常。
PreparedStatement比Statement區別?
第一:statement執行的SQL語句必須是一個完整的SQL,而對於PreparedStatement來講,能夠使用「?」做爲
SQL語句當中的佔位符,而後使用PreparedStatement的setXXX方法來給佔位符賦值,最後在執行;
第二:使用Statement時,若是SQL當中出現了「‘」或者「-」等符號時,須要使用轉義字符來進行轉義,而在
PreparedStatement當中,若是佔位符的值當中有這些符號,PreparedStatement會自動的進行轉義;
第三:PreparedStatement會講SQL語句進行預編譯,每次執行的時候只須要將參數設置給相應的佔位符就能夠
運行。而使用Statement時,SQL語句時每次都要進行編譯,因此PreparedStatement的效率相對較高。
doGet()方法和doPost()方法區別?
get方式 參數在地址欄中顯示 經過?name=""&id=""這種形式傳遞的 不安全 只能傳遞2kb的能容
post方式 底層是經過流的形式傳遞 不限制大小 上傳的時候必須用Post方式
doGet:路徑傳參。效率高,安全性差
doPOST:實體傳參。效率第,安全性好
null和undefind的區別?
undefined是訪問一個未初始化的變量時返回的值,而null是訪問一個還沒有存在的對象時所返回的值。
Error和Exception的區別?
Error(錯誤)是系統中的錯誤,程序員是不能改變的和處理的,是在程序編譯時出現的錯誤,只能經過修改程序才能修正。
通常是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢等。
對於這類錯誤的致使的應用程序中斷,僅靠程序自己沒法恢復和和預防,遇到這樣的錯誤,建議讓程序終止。
Exception(異常)表示程序能夠處理的異常,能夠捕獲且可能恢復。遇到這類異常,應該儘量處理異常,使程序恢復運行,
而不該該隨意終止異常。
阻塞和非阻塞以及同步和異步的區別?
1. 同步,就是我調用一個功能,該功能沒有結束前,我死等結果。
2. 異步,就是我調用一個功能,不須要知道該功能結果,該功能有結果後通知我(回調通知)
3. 阻塞,就是調用我(函數),我(函數)沒有接收完數據或者沒有獲得結果以前,我不會返回。
4. 非阻塞,就是調用我(函數),我(函數)當即返回,經過select通知調用者
同步IO和異步IO的區別就在於:數據拷貝的時候進程是否阻塞
阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否當即返回
事務的ACID和事務的隔離性?
1)原子性(Atomic):事務中各項操做,要麼全作要麼全不作,任何一項操做的失敗都會致使整個事務的失敗;
2)一致性(Consistent):事務結束後系統狀態是一致的;
3)隔離性(Isolated):併發執行的事務彼此沒法看到對方的中間狀態;
4)持久性(Durable):事務完成後所作的改動都會被持久化,即便發生災難性的失敗。經過日誌和同步備份能夠在故障發生後重建數據。
髒讀:事務A讀到了事務B未提交的數據。
不可重複讀:事務A第一次查詢獲得一行記錄row1,事務B提交修改後,事務A第二次查詢獲得row1,但列內容發生了變化,側重於次數,
側重於update
幻讀:事務A第一次查詢獲得一行記錄row1,事務B提交修改後,事務A第二次查詢獲得兩行記錄row1和row2,側重於內容,側重於insert
線程的sleep和wait區別?
sleep()不釋放同步鎖,wait()釋放同步鎖.
sleep能夠用時間指定來使他自動醒過來,若是時間不到你只能調用interreput()來強行打斷;
wait()能夠用notify()直接喚起.
sleep和wait的區別還有:
1。這兩個方法來自不一樣的類分別是Thread和Object
2。最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其餘線程能夠使用同步控制塊或者方法。
3。wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用
線程的狀態(階段)?
建立、就緒、運行、阻塞、終止。
一、新建狀態(New):新建立了一個線程對象。
二、就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於「可運行線程池」中,
變得可運行,只等待獲取CPU的使用權。即在就緒狀態的進程除CPU以外,其它的運行所需資源都已所有得到。
三、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。
四、阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。
http和https的區別?
一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
常見的運行時異常?
NullPointerException - 空指針引用異常
ClassCastException - 類型強制轉換異常。
IllegalArgumentException - 傳遞非法參數異常。
ArithmeticException - 算術運算異常
ArrayStoreException - 向數組中存放與聲明類型不兼容對象異常
IndexOutOfBoundsException - 下標越界異常
NegativeArraySizeException - 建立一個大小爲負數的數組錯誤異常
NumberFormatException - 數字格式異常
SecurityException - 安全異常
UnsupportedOperationException - 不支持的操做異常
BIO和NIO區別?
互聯網 強調的是信息/數據在網絡之間的流通,
BIO:堵塞式IO,至關於輪船運輸
NIO:非堵塞式IO:面向緩衝區(buffer),基於通道(chanel)的io操做,至關於火車運輸,效率高
文件->雙向通道((緩衝區))->程序
冒泡排序和天然排序及定製排序怎麼實現的或者手寫出來
冒泡排序
int[] arr={6,3,8,2,9,1};
System.out.println("排序前數組爲:");
for(int num:arr){
System.out.print(num+" ");
}
for(int i=0;i<arr.length-1;i++){//外層循環控制排序趟數
for(int j=0;j<arr.length-1-i;j++){//內層循環控制每一趟排序多少次
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
System.out.println();
System.out.println("排序後的數組爲:");
for(int num:arr){
System.out.print(num+" ");
}
天然排序
一、定義一個類(文章中爲Employee)實現Comparable接口
二、重寫Comparable接口中的compareTo()方法
三、在compareTo()中按指定屬性進行排序
public class Employee implements Comparable{
public int compareTo(Object o) {
if (o instanceof Employee) {
Employee e = (Employee) o;
return this.name.compareTo(e.name);//按name進行排序
}
return 0;
}
}
定製排序
1.建立一個Compartor實現類的對象,並傳入到TreeSet的構造器中
2.重寫compare方法
3.安照某個屬性進行排序
4.向集合中添加元素
TreeSet set = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Student && o2 instanceof Student) {
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int s = s1.getAge() - s2.getAge();
if(s == 0) {
return s1.getName().compareTo(s2.getName());
}
return s;
}
return 0;
}
});
set.add(new Student("aaa", 18));
set.add(new Student("bbb", 8));
set.add(new Student("fff", 38));
set.add(new Student("ccc", 28));
System.out.println(set);
在使用定製排序或是天然排序時,在其用到的類中都要重寫hashCode()與equals()方法
三種遍歷方式?
第一種遍歷方法和輸出結果。
for(int i=1,i<list.size(),i++){
System.out.println(list.get(i));
}
第二種用foreach循環。增強型for循環。推薦方式。
for(String string:list){
System.out.println(string);
}
第三鍾迭代器
List<String> list=new ArrayList<>();
list.add("abc");
list.add("ghi");
for(Iterator<String> it=list.iterator();it.hasNext();){
System.out.println(it.next());
}
講講SpringMVC的工做原理和經常使用註解
一、用戶向服務器發送請求,請求被SpringMVC的前端控制器DispatcherServlet截獲。
二、DispatcherServlet對請求的URL(統一資源定位符)進行解析,獲得URI(請求資源標識符),而後根據該URI,
經過配置或註解調用HandlerMapping找到Handler配置的全部相關的對象,包括Handler對象以及Handler對象對應的攔截器,
這些對象都會被封裝到一個HandlerExecutionChain對象當中返回DispatcherServlet。
三、前端控制器根據得到的Handler,請求HandlerAdapter處理多種Handler,調用Handler實際處理請求的方法。
四、提取請求中的模型數據,開始執行Handler(Controller)
五、Handler執行完成後,向DispatcherServlet返回一個ModelAndView對象。
六、根據返回的ModelAndView對象,請求ViewResolver(視圖解析器)將邏輯視圖解析成真正的視圖並返回view給前端控制器。
七、渲染視圖將model數據轉換爲response響應
八、把響應結果給返回給客戶端。
url和uri的區別?
URI包括URL和URN兩個類別,我的的身份證號就是URN,我的的家庭地址就是URL,URN能夠惟一標識一我的,
而URL能夠告訴郵遞員怎麼把貨送到你手裏。
組件型註解:
@Component 在類定義以前添加@Component註解,他會被spring容器識別,並轉爲bean。
@Repository 對Dao實現類進行註解 (特殊的@Component)
@Service 用於對業務邏輯層進行註解, (特殊的@Component)
@Controller 用於控制層註解 , (特殊的@Component)
請求和參數型註解:
@RequestMapping:用於處理請求地址映射,能夠做用於類和方法上。
@RequestParam:用於獲取傳入參數的值
@PathViriable:用於定義路徑參數值
@ResponseBody:做用於方法上,能夠將整個返回結果以某種格式返回,如json或xml格式。
@CookieValue:用於獲取請求的Cookie值
講講Spring的IOC(DI)和AOP動態代理
傳統的程序開發(不用IOC):舉個簡單的例子,咱們是如何找女友的?常見的狀況是,咱們處處去看哪裏有
長得漂亮身材又好的mm,而後打聽她們的興趣愛好、qq號、電話號、ip號、iq號………,想辦法認識她們,投其
所好送其所要,而後嘿嘿……這個過程是複雜深奧的,咱們必須本身設計和麪對每一個環節。
有IOC:IoC是如何作的呢?有點像經過婚介找女友,在我和女友之間引入了一個第三者:婚姻介紹所。婚
介管理了不少男男女女的資料,我能夠向婚介提出一個列表,告訴它我想找個什麼樣的女友,好比長得像李
嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術像齊達內之類的,而後婚介就會按照咱們的要求,
提供一個mm,咱們只須要去和她談戀愛、結婚就好了。
總結控制反轉:全部的類都會在spring容器中登記,告訴spring你是個什麼東西,你須要什麼東西,而後
spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其餘須要你的東西。全部的類的
建立、銷燬都由 spring來控制,也就是說控制對象生存週期的再也不是引用它的對象,而是spring。對於某個
具體的對象而言,之前是它控制其餘對象,如今是全部對象都被spring控制,因此這叫控制反轉。
理解DI的關鍵是:「誰依賴誰,爲何須要依賴,誰注入誰,注入了什麼」
●誰依賴於誰:固然是應用程序依賴於IoC容器;
●爲何須要依賴:應用程序須要IoC容器來提供對象須要的外部資源;
●誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
●注入了什麼:就是注入某個對象所須要的外部資源(包括對象、資源、常量數據)。
IoC和DI由什麼關係呢?DI(依賴注入)其實就是IOC的另一種說法,其實它們是同一個概念的不一樣角度描述
Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時爲方法生成
一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理經過反射來接收被代理
的類,而且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。若是
目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation
Library),是一個代碼生成的類庫,能夠在運行時動態的生成某個類的子類,注意,CGLIB是經過繼承的方式作
的動態代理,所以若是某個類被標記爲final,那麼它是沒法使用CGLIB作動態代理的。
AOP在事務管理方面,Spring使用AOP來完成聲明式的事務管理有annotation和xml兩種形式。開發中,方便代碼
編寫,不少時候都是在spring配置文件中配置事務管理器並開啓事務控制註解。在業務類或業務類方法中添加
@Transactional實現事務控制。
講講MyBatis框架
(1)mybatis是一個基於java的持久層框架,它內部封裝了jdbc,不須要花費精力去處理加載驅動、建立鏈接等的過程,
消除了JDBC大量冗餘的代碼。
(2)mybatis經過xml或註解的方式將要執行的各類statement配置起來,並經過java對象和statement中
sql的動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射爲java對象並返回。
(3)MyBatis 支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設
置參數以及獲取結果集。MyBatis 能夠使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJO映射成數據庫中的記錄。
(4)提供了不少第三方插件(分頁插件 / 逆向工程);
(5)可以與Spring很好的集成;
(6)MyBatis至關靈活,SQL寫在XML裏,從程序代碼中完全分離,解除sql與程序代碼的耦合,便於統一管理,支持編寫動態SQL語句。
(7) 提供映射標籤,支持對象與數據庫的ORM字段關係映射。
(8)SQL語句依賴於數據庫,致使數據庫移植性差,不能隨意更換數據庫。
講講SpringBoot的特色
Springboot用來簡化spring應用的初始搭建以及開發過程 使用特定的方式來進行配置
(properties或yml文件)
能夠建立獨立的spring引用程序 main方法運行
Springboot嵌入的Tomcat 無需部署war文件
簡化maven配置
講講線程的建立及實現線程幾種方式之間的區別
1:繼承Therad類,2:實現Runnable接口 3:實現Callable接口 4:使用線程池
繼承Thread類,並重寫裏面的run方法
class A extends Thread{
public void run(){
for(int i=1;i<=100;i++){
System.out.println("-----------------"+i);
}
}
}
A a = new A();
a.start();
實現Runnable接口,並實現裏面的run方法
class B implements Runnable{
public void run(){
for(int i=1;i<=100;i++){
System.out.println("-----------------"+i);
}
}
}
B b = new B();
Thread t = new Thread(b);
t.start();
實現Callable
class A implements Callable<String>{
public String call() throws Exception{
//...
}
}
FutureTask<String> ft = new FutureTask<>(new A());
new Thread(ft).start();
線程池
ExcutorService es = Executors.newFixedThreadPool(10);
es.submit(new Runnable(){//任務});
es.submit(new Runnable(){//任務});
...
es.shutdown();
實現Runnable和實現Callable的區別?
實現Callable接口,任務能夠有返回值,Runnable沒有。
實現Callable接口,能夠指定泛型,Runnable沒有。
實現Callable接口,能夠在call方法中聲明異常,Runnable沒有。
Runnable和Thread兩者的區別?
實現Runnable接口的方式,更適合處理有共享資源的狀況。
實現Runnable接口的方式,避免了單繼承的侷限性。
Java自定義類加載器與雙親委派模型
啓動類加載器(Bootstrap)C++
擴展類加載器(Extension)Java
應用程序類加載器(AppClassLoader)Java
雙親委派模型工做原理:若是一個類加載器收到類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請
求委派給父類加載器完成。每一個類加載器都是如此,只有當父加載器在本身的搜索範圍內找不到指定的類時(即
ClassNotFoundException),子加載器纔會嘗試本身去加載。
講講jvm的組成與調優,內存模型,GC,tomcat調優
通常系統的瓶頸
性能測試調優須要先發現瓶頸,那麼系統通常會存在哪些瓶頸:
硬件上的性能瓶頸:
通常指的是CPU、內存、磁盤I/O 方面的問題,分爲服務器硬件瓶頸、網絡瓶頸(對局域網能夠不考慮)、服務器操做系統瓶頸(參數配置)、中間件瓶頸(參數配置、數據庫、web服務器等)、應用瓶頸(SQL 語句、數據庫設計、業務邏輯、算法等)。
應用軟件上的性能瓶頸:
通常指的是應用服務器、web 服務器等應用軟件,還包括數據庫系統。
例如:中間件weblogic 平臺上配置的JDBC鏈接池的參數設置不合理,形成的瓶頸。
應用程序上的性能瓶頸:
通常指的是開發人員新開發出來的應用程序。
例如,程序架構規劃不合理,程序自己設計有問題(串行處理、請求的處理線程不夠),形成系統在大量用戶方位時性能低下而形成的瓶頸。
操做系統上的性能瓶頸:
通常指的是windows、UNIX、Linux等操做系統。
例如,在進行性能測試,出現物理內存不足時,虛擬內存設置也不合理,虛擬內存的交換效率就會大大下降,從而致使行爲的響應時間大大增長,這時認爲操做系統上出現性能瓶頸。
網絡設備上的性能瓶頸:
通常指的是防火牆、動態負載均衡器、交換機等設備。
例如,在動態負載均衡器上設置了動態分發負載的機制,當發現某個應用服務器上的硬件資源已經到達極限時,動態負載均衡器將後續的交易請求發送到其餘負載較輕的應用服務器上。在測試時發現,動態負載均衡器沒有起到相應的做用,這時能夠認爲網絡瓶頸。
通常性能調優步驟
通常性能問題調優的步驟:
步驟一:肯定問題
應用程序代碼:在一般狀況下,不少程序的性能問題都是寫出來的,所以對於發現瓶頸的模塊,應該首先檢查一下代碼。
數據庫配置:常常引發整個系統運行緩慢,一些諸如oracle 的大型數據庫都是須要DBA進行正確的參數調整才能投產的。
操做系統配置:不合理就可能引發系統瓶頸。
硬件設置:硬盤速度、內存大小等都是容易引發瓶頸的緣由,所以這些都是分析的重點。
網絡:網絡負載太重致使網絡衝突和網絡延遲。
步驟二:肯定問題
當肯定了問題以後,咱們要明確這個問題影響的是響應時間吞吐量,仍是其餘問題?是多數用戶仍是少數用戶遇到了問題?若是是少數用戶,這幾個用戶與其它用戶的操做有什麼不用?系統資源監控的結果是否正常?CPU的使用是否到達極限?I/O 狀況如何?問題是否集中在某一類模塊中? 是客戶端仍是服務器出現問題? 系統硬件配置是否夠用?實際負載是否超過了系統的負載能力? 是否未對系統進行優化?
經過這些分析及一些與系統相關的問題,能夠對系統瓶頸有更深刻的瞭解,進而分析出真正的緣由。
步驟三: 肯定調整目標和解決方案
得高系統吞吐理,縮短響應時間,更好地支持併發。
步驟四:測試解決方案
對經過解決方案調優後的系統進行基準測試。(基準測試是指經過設計科學的測試方法、測試工具和測試系統,實現對一類測試對象的某項性能指標進行定量的和可對比的測試)
步驟五:分析調優結果
系統調優是否達到或者超出了預約目標?系統是總體性能獲得了改善,仍是以系統某部分性能來解決其餘問題。調優是否能夠結束了。
最後,若是達到了預期目標,調優工做就基本能夠結束了。
下面算是一個技巧,如面試官問到一個性能問題假設,我不知道性能問題出在哪兒時,能夠按照這個思路回答^_^
• 查找瓶頸時按如下順序,由易到難。
服務器硬件瓶頸---〉網絡瓶頸(對局域網,能夠不考慮)---〉服務器操做系統瓶頸(參數配置)---〉中間件瓶頸(參數配置,數據庫,web服務器等)---〉應用瓶頸(SQL語句、數據庫設計、業務邏輯、算法等)
注:以上過程並非每一個分析中都須要的,要根據測試目的和要求來肯定分析的深度。對一些要求低的,咱們分析到應用系統在未來大的負載壓力(併發用戶數、數據量)下,系統的硬件瓶頸在哪兒就夠了。
• 分段排除法 頗有效
tomcat調優:
增長JVM堆內存大小
修復JRE內存泄漏
線程池設置
壓縮
數據庫性能調優
Tomcat本地庫
JVM調優:
-Xms – 指定初始化時化的堆內存,默認爲物理內存的1/64
-Xmx – 指定最大的內存,默認爲物理內存的1/4
-XX:+PrintGCDetails:輸出詳細的GC處理日誌
在重啓你的Tomcat服務器以後,這些配置的更改纔會有效。
講講高可用的數據與服務怎麼實現,負載均衡策略以及區別,分佈式(及事物),集羣,高併發以及遇到的問題和解決方案
分佈式 :
分佈式架構:把系統按照模塊拆分紅多個子系統,多個子系統分佈在不一樣的網絡計算機上相互協做完成業務流
程,系統之間須要進行通訊。
優勢:
把模塊拆分,使用接口通訊,下降模塊之間的耦合度。
把項目拆分紅若干個子項目,不一樣的團隊負責不一樣的子項目。
增長功能時只須要再增長一個子項目,調用其餘系統的接口就能夠。
能夠靈活的進行分佈式部署。
缺點:
一、系統之間交互須要使用遠程通訊,接口開發增長工做量。
二、各個模塊有一些通用的業務邏輯沒法共用。
基於soa的架構
SOA:面向服務的架構。也就是把工程拆分紅服務層、表現層兩個工程。服務層中包含業務邏輯,只須要對外提
供服務便可。表現層只須要處理和頁面的交互,業務邏輯都是調用服務層的服務來實現。
分佈式架構和soa架構有什麼區別?
SOA,主要仍是從服務的角度,將工程拆分紅服務層、表現層兩個工程。
分佈式,主要仍是從部署的角度,將應用按照訪問壓力進行歸類,主要目標是充分利用服務器的資源,避免資源分配不均
集羣:
一個集羣系統是一羣鬆散結合的服務器組,造成一個虛擬的服務器,爲客戶端用戶提供統一的服務。對於這個
客戶端來講,一般在訪問集羣系統時不會意識到它的服務是由具體的哪一臺服務器提供。集羣的目的,是爲實
現負載均衡、容錯和災難恢復。以達到系統可用性和可伸縮性的要求。集羣系統通常應具高可用性、可伸縮
性、負載均衡、故障恢復和可維護性等特殊性能。通常同一個工程會部署到多臺服務器上。
常見的tomcat集羣,Redis集羣,Zookeeper集羣,數據庫集羣
分佈式與集羣的區別:
分佈式是指將不一樣的業務分佈在不一樣的地方。 而集羣指的是將幾臺服務器集中在一塊兒,實現同一業務。一句
話:分佈式是並聯工做的,集羣是串聯工做的。
分佈式中的每個節點,均可以作集羣。 而集羣並不必定就是分佈式的。
舉例:就好比新浪網,訪問的人多了,他能夠作一個羣集,前面放一個響應服務器,後面幾臺服務器完成同一
業務,若是有業務訪問的時候,響應服務器看哪臺服務器的負載不是很重,就將給哪一臺去完成。
而分佈式,從窄意上理解,也跟集羣差很少, 可是它的組織比較鬆散,不像集羣,有一個組織性,一臺服務器垮了,
其它的服務器能夠頂上來。分佈式的每個節點,都完成不一樣的業務,一個節點垮了,哪這個業務就不可訪問了。
分佈式是以縮短單個任務的執行時間來提高效率的,而集羣則是經過提升單位時間內執行的任務數來提高效率。
舉例:若是一個任務由10個子任務組成,每一個子任務單獨執行需1小時,則在一臺服務器上執行該任務需10小
時。採用分佈式方案,提供10臺服務器,每臺服務器只負責處理一個子任務,不考慮子任務間的依賴關係,執
行完,這個任務只需一個小時。(這種工做模式的一個典型表明就是Hadoop的Map/Reduce分佈式計算模型)
而採用集羣方案,一樣提供10臺服務器,每臺服務器都能獨立處理這個任務。假設有10個任務同時到達,10個
服務器將同時工做,1小時後,10個任務同時完成,這樣,整身來看,仍是1小時內完成一個任務!
高併發:
處理高併發常見的方法有哪些?
1)數據層
數據庫集羣和庫表散列
分表分庫
開啓索引
開啓緩存
表設計優化
Sql語句優化
緩存服務器(提升查詢效率,減輕數據庫壓力)
搜索服務器(提升查詢效率,減輕數據庫壓力)
圖片服務器分離
2)項目層
採用面向服務分佈式架構(分擔服務器壓力,提升併發能力)
採用併發訪問較高的詳情繫統採用靜態頁面,HTML靜態化 freemaker
使用頁面緩存
用ActiveMQ使得業務進一步進行解耦,提升業務處理能力
使用分佈式文件系統存儲海量文件
3)應用層
Nginx服務器來作負載均衡
Lvs作二層負載
鏡像
高可用:
目的:保證服務器硬件故障服務依然可用,數據依然保存並可以被訪問。
高可用的服務
①分級管理:核心應用和服務具備更高的優先級,好比用戶及時付款比可否評價商品更重要;
②超時設置:設置服務調用的超時時間,一旦超時,通訊框架拋出異常,應用程序則根據服務調度策略選擇重試or請求轉移到其餘服務器上
③異步調用:經過消息隊列等異步方式完成,避免一個服務失敗致使整個應用請求失敗的狀況。
不是全部服務均可以異步調用,對於獲取用戶信息這類調用,採用異步方式會延長響應時間,得不償失。對於
那些必須確認服務調用成功後才能繼續進行下一步的操做的應用也不適合異步調用。
④服務降級:網站訪問高峯期間,爲了保證核心應用的正常運行,須要對服務降級。
降級有兩種手段:
一是拒絕服務,拒絕較低優先級的應用的調用,減小服務調用併發數,確保核心應用的正常運行;
二是關閉功能,關閉部分不重要的服務,或者服務內部關閉部分不重要的功能,以節約系統開銷,爲核心應用服務讓出資源;
⑤冪等性設計:保證服務重複調用和調用一次產生的結果相同;
高可用的數據
保證數據高可用的主要手段有兩種:一是數據備份,二是失效轉移機制;
①數據備份:又分爲冷備份和熱備份,冷備份是按期複製,不能保證數據可用性。熱備份又分爲異步熱備
和同步熱備,異步熱備是指多份數據副本的寫入操做異步完成,而同步方式則是指多份數據副本的寫入操做同時完成。
②失效轉移:若數據服務器集羣中任何一臺服務器宕機,那麼應用程序針對這臺服務器的全部讀寫操做都
要從新路由到其餘服務器,保證數據訪問不會失敗。
網站運行監控
」不容許沒有監控的系統上線「
(1)監控數據採集
①用戶行爲日誌收集:服務器端的日誌收集和客戶端的日誌收集;目前許多網站逐步開發基於實時計算框架Storm的日誌統計與分析工具;
②服務器性能監控:收集服務器性能指標,如系統Load、內存佔用、磁盤IO等,及時判斷,防患於未然;
③運行數據報告:採集並報告,彙總後統一顯示,應用程序須要在代碼中處理運行數據採集的邏輯;
(2)監控管理
①系統報警:配置報警閥值和值守人員聯繫方式,系統發生報警時,即便工程師在千里以外,也能夠被及時通知;
②失效轉移:監控系統在發現故障時,主動通知應用進行失效轉移;
③自動優雅降級:爲了應付網站訪問高峯,主動關閉部分功能,釋放部分系統資源,保證核心應用服務的正
常運行;—>網站柔性架構的理想狀態
負載均衡:
1.什麼是負載均衡?
當一臺服務器的性能達到極限時,咱們能夠使用服務器集羣來提升網站的總體性能。那麼,在服務器集羣
中,須要有一臺服務器充當調度者的角色,用戶的全部請求都會首先由它接收,調度者再根據每臺服務器的負
載狀況將請求分配給某一臺後端服務器去處理。
(1)HTTP重定向負載均衡。
原理:當用戶向服務器發起請求時,請求首先被集羣調度者截獲;調度者根據某種分配策略,選擇一臺服務
器,並將選中的服務器的IP地址封裝在HTTP響應消息頭部的Location字段中,並將響應消息的狀態碼設爲
302,最後將這個響應消息返回給瀏覽器。當瀏覽器收到響應消息後,解析Location字段,並向該URL發起請
求,而後指定的服務器處理該用戶的請求,最後將結果返回給用戶。
優勢:比較簡單
缺點:調度服務器只在客戶端第一次向網站發起請求的時候起做用。當調度服務器向瀏覽器返回響應信息後,
客戶端此後的操做都基於新的URL進行的(也就是後端服務器),此後瀏覽器就不會與調度服務器產生關係,瀏
覽器須要每次請求兩次服務器才能拿完成一次訪問,性能較差。並且調度服務器在調度時,沒法知道當前用戶
將會對服務器形成多大的壓力,只不過是把請求次數平均分配給每臺服務器罷了,瀏覽器會與後端服務器直接交互。
(2)DNS域名解析負載均衡
原理:爲了方便用戶記憶,咱們使用域名來訪問網站。經過域名訪問網站以前,首先須要將域名解析成IP地
址,這個工做是由DNS域名服務器完成的。咱們提交的請求不會直接發送給想要訪問的網站,而是首先發給域名
服務器,它會幫咱們把域名解析成IP地址並返回給咱們。咱們收到IP以後纔會向該IP發起請求。一個域名指向
多個IP地址,每次進行域名解析時,DNS只要選一個IP返回給用戶,就可以實現服務器集羣的負載均衡。
調度策略:通常DNS提供商會提供一些調度策略供咱們選擇,如隨機分配、輪詢、根據請求者的地域分配離他最近的服務器。
隨機分配策略:
當調度服務器收到用戶請求後,能夠隨機決定使用哪臺後端服務器,而後將該服務器的IP封裝在HTTP響應消息
的Location屬性中,返回給瀏覽器便可。
輪詢策略(RR) :
調度服務器須要維護一個值,用於記錄上次分配的後端服務器的IP。那麼當新的請求到來時,調度者將請求依
次分配給下一臺服務器。
優勢:配置簡單,將負載均衡工做交給DNS,省略掉了網絡管理的麻煩;
缺點:集羣調度權交給了DNS服務器,從而咱們沒辦法爲所欲爲地控制調度者,沒辦法定製調度策略,沒辦法了
解每臺服務器的負載狀況,只不過把全部請求平均分配給後端服務器罷了。某一臺後端服務器發生故障時,即
使咱們當即將該服務器從域名解析中去除,但因爲DNS服務器會有緩存,該IP仍然會在DNS中保留一段時間,那
麼就會致使一部分用戶沒法正常訪問網站。不過動態DNS可以讓咱們經過程序動態修改DNS服務器中的域名解
析。從而當咱們的監控程序發現某臺服務器掛了以後,能當即通知DNS將其刪掉。
(3)反向代理負載均衡。
原理:反向代理服務器是一個位於實際服務器以前的服務器,全部向咱們網站發來的請求都首先要通過反向代
理服務器,服務器根據用戶的請求要麼直接將結果返回給用戶,要麼將請求交給後端服務器處理,再返回給用
戶。反向代理服務器就能夠充當服務器集羣的調度者,它能夠根據當先後端服務器的負載狀況,將請求轉發給
一臺合適的服務器,並將處理結果返回給用戶。
優勢:
1.部署簡單
2.隱藏後端服務器:與HTTP重定向相比,反向代理可以隱藏後端服務器,全部瀏覽器都不會與後端服務器直接
交互,從而可以確保調度者的控制權,提高集羣的總體性能。
3.故障轉移 :與DNS負載均衡相比,反向代理可以更快速地移除故障結點。當監控程序發現某一後端服務器出
現故障時,可以及時通知反向代理服務器,並當即將其刪除。
4.合理分配任務 :HTTP重定向和DNS負載均衡都沒法實現真正意義上的負載均衡,也就是調度服務器沒法根據
後端服務器的實際負載狀況分配任務。但反向代理服務器支持手動設定每臺後端服務器的權重。咱們能夠根據
服務器的配置設置不一樣的權重,權重的不一樣會致使被調度者選中的機率的不一樣。
缺點:
1.調度者壓力過大 :因爲全部的請求都先由反向代理服務器處理,那麼當請求量超過調度服務器的最大負載
時,調度服務器的吞吐率下降會直接下降集羣的總體性能。
2.制約擴展 :當後端服務器也沒法知足巨大的吞吐量時,就須要增長後端服務器的數量,可沒辦法無限量地增
加,由於會受到調度服務器的最大吞吐量的制約。
3.粘滯會話:反向代理服務器會引發一個問題。若某臺後端服務器處理了用戶的請求,並保存了該用戶的
session或存儲了緩存,那麼當該用戶再次發送請求時,沒法保證該請求仍然由保存了其Session或緩存的服
務器處理,若由其餘服務器處理,先前的Session或緩存就找不到了。
解決辦法1: 能夠修改反向代理服務器的任務分配策略,以用戶IP做爲標識較爲合適。相同的用戶IP會交由同
一臺後端服務器處理,從而就避免了粘滯會話的問題。
解決辦法2: 能夠在Cookie中標註請求的服務器ID,當再次提交請求時,調度者將該請求分配給Cookie中標
注的服務器處理便可。
(4)IP負載均衡。
1.經過NAT實現負載均衡:響應報文通常比較大,每一次都須要NAT轉換的話,大流量的時候,會致使調度器成爲一個瓶頸。
2.經過直接路由實現負載均衡
3.VS/TUN 實現虛擬服務器
優勢:IP負載均衡在內核進程完成數據分發,較反向代理均衡有更好的處理性能。
缺點:負載均衡的網卡帶寬成爲系統的瓶頸,場景:某個服務器跑的應用非高峯期間都能達到500M以
上,晚高峯通常可以超過1G,主流服務器的網卡都是千兆的,超過1G的流量明顯會致使丟包的問題,此時又不
能中止業務對網卡進行更換。
(5)數據鏈路層負載均衡。
對於linux系統來講,數據鏈路層的解決方案就是實現多個網卡綁定聯合提供服務,把多張網卡捆綁作成一個
邏輯網卡。避免負載均衡服務器網卡帶寬成爲瓶頸,是目前大型網站所使用的最廣的一種負載均衡手段。
linux bonding的七種模式,mod=0~6:平衡掄循環策略,主-備份策略,平衡策略,廣播策略,動態連接聚
合,適配器傳輸負載均衡,適配器適應性負載均衡
講講你是怎麼優化數據庫(sql,表的設計)以及索引的使用有哪些限制條件(索引失效)
a,選取最適用的字段:在建立表的時候,爲了得到更好的性能,咱們能夠將表中字段的寬度設得儘量小。另一
個提升效率的方法是在可能的狀況下,應該儘可能把字段設置爲NOTNULL,
b,使用鏈接(JOIN)來代替子查詢(Sub-Queries)
c,使用聯合(UNION)來代替手動建立的臨時表
d,事物:
a)要麼語句塊中每條語句都操做成功,要麼都失敗。換句話說,就是能夠保持數據庫中數據的一致性和完整
性。事物以BEGIN關鍵字開始,COMMIT關鍵字結束。在這之間的一條SQL操做失敗,那麼,ROLLBACK命令就能夠
把數據庫恢復到BEGIN開始以前的狀態。
b) 是當多個用戶同時使用相同的數據源時,它能夠利用鎖定數據庫的方法來爲用戶提供一種安全的訪問方
式,這樣能夠保證用戶的操做不被其它的用戶所幹擾。
e,減小表關聯,加入冗餘字段
f,使用外鍵:鎖定表的方法能夠維護數據的完整性,可是它卻不能保證數據的關聯性。這個時候咱們就能夠使用外鍵。
g,使用索引
h,優化的查詢語句
i,集羣
j,讀寫分離
k,主從複製
l,分表
m,分庫
o,適當的時候能夠使用存儲過程
限制:儘可能用全職索引,最左前綴:查詢從索引的最左前列開始而且不跳過索引中的列;索引列上不操做,範圍之
後全失效; 不等空值還有OR,索引影響要注意;like以通配符%開頭索引失效會變成全表掃描的操做,字符串不
加單引號索引失效
講講Redis緩存,它的數據類型,和其餘緩存之間的區別,及持久化,緩存穿透與雪崩它的解決方案
redis是內存中的數據結構存儲系統,一個key-value類型的非關係型數據庫,可持久化的數據庫,相對於關
系型數據庫(數據主要存在硬盤中),性能高,所以咱們通常用redis來作緩存使用;而且redis支持豐富的數
據類型,比較容易解決各類問題,所以redis能夠用來做爲註冊中心,數據庫、緩存和消息中間件。Redis的
Value支持5種數據類型,string、hash、list、set、zset(sorted set);
String類型:一個key對應一個value
Hash類型:它的key是string類型,value又是一個map(key-value),適合存儲對象。
List類型:按照插入順序的字符串鏈表(雙向鏈表),主要命令是LPUSH和RPUSH,可以支持反向查找和遍歷
Set類型:用哈希表類型的字符串序列,沒有順序,集合成員是惟一的,沒有重複數據,底層主要是由一個
value永遠爲null的hashmap來實現的。
zset類型:和set類型基本一致,不過它會給每一個元素關聯一個double類型的分數(score),這樣就能夠爲
成員排序,而且插入是有序的。
Memcache和redis的區別:
數據支持的類型:redis不只僅支持簡單的k/v類型的數據,同時還支持list、set、zset、hash等數據結構
的存儲;memcache只支持簡單的k/v類型的數據,key和value都是string類型
可靠性:memcache不支持數據持久化,斷電或重啓後數據消失,但其穩定性是有保證的;redis支持數據持久
化和數據恢復,容許單點故障,可是同時也會付出性能的代價
性能上:對於存儲大數據,memcache的性能要高於redis
應用場景:
Memcache:適合多讀少寫,大數據量的狀況(一些官網的文章信息等)
Redis:適用於對讀寫效率要求高、數據處理業務複雜、安全性要求較高的系統
案例:分佈式系統,存在session之間的共享問題,所以在作單點登陸的時候,咱們利用redis來模擬了
session的共享,來存儲用戶的信息,實現不一樣系統的session共享;
redis的持久化方式有兩種:
RDB(半持久化方式):按照配置不按期的經過異步的方式、快照的形式直接把內存中的數據持久化到磁盤的一
個dump.rdb文件(二進制的臨時文件)中,redis默認的持久化方式,它在配置文件(redis.conf)中。
優勢:只包含一個文件,將一個單獨的文件轉移到其餘存儲媒介上,對於文件備份、災難恢復而言,比較實用。
缺點:系統一旦在持久化策略以前出現宕機現象,此前沒有來得及持久化的數據將會產生丟失
AOF(全持久化的方式):把每一次數據變化都經過write()函數將你所執行的命令追加到一個appendonly.aof文件裏面,
Redis默認是不支持這種全持久化方式的,須要在配置文件(redis.conf)中將
appendonly no改爲appendonly yes
優勢:數據安全性高,對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機問題,也
不會破壞日誌文件中已經存在的內容;
缺點:對於數量相同的數據集來講,aof文件一般要比rdb文件大,所以rdb在恢復大數據集時的速度大於AOF;
AOF持久化配置:
在Redis的配置文件中存在三種同步方式,它們分別是:
appendfsync always #每次有數據修改發生時都會都調用fsync刷新到aof文件,很是慢,可是安全;
appendfsync everysec #每秒鐘都調用fsync刷新到aof文件中,很快,可是可能丟失一秒內的數據,推薦使用,兼顧了速度和安全;
appendfsync no #不會自動同步到磁盤上,須要依靠OS(操做系統)進行刷新,效率快,可是安全性就比較差;
二種持久化方式區別:
AOF在運行效率上每每慢於RDB,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB同樣高效;
若是緩存數據安全性要求比較高的話,用aof這種持久化方式(好比項目中的購物車);
若是對於大數據集要求效率高的話,就能夠使用默認的。並且這兩種持久化方式能夠同時使用。
redis-cluster集羣,這種方式採用的是無中心結構,每一個節點保存數據和整個集羣的狀態,每一個節點都和其
他全部節點鏈接。若是使用的話就用redis-cluster集羣。集羣這塊是公司運維搭建的,具體怎麼搭建不是太瞭解。
咱們項目中redis集羣主要搭建了6臺,3主(爲了保證redis的投票機制)3從(高可用),每一個主服務器都有
一個從服務器,做爲備份機。全部的節點都經過PING-PONG機制彼此互相鏈接;客戶端與redis集羣鏈接,只
須要鏈接集羣中的任何一個節點便可;Redis-cluster中內置了16384個哈希槽,Redis-cluster把全部的物
理節點映射到【0-16383】slot上,負責維護。
Redis是有事務的,redis中的事務是一組命令的集合,這組命令要麼都執行,要不都不執行,保證一個事務中
的命令依次執行而不被其餘命令插入。redis的事務是不支持回滾操做的。redis事務的實現,須要用到
MULTI(事務的開始)和EXEC(事務的結束)命令 ;
緩存穿透:緩存查詢通常都是經過key去查找value,若是不存在對應的value,就要去數據庫中查找。若是這
個key對應的value在數據庫中也不存在,而且對該key併發請求很大,就會對數據庫產生很大的壓力,這就叫緩存穿透
解決方案:
1.對全部可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄。
2.將全部可能存在的數據哈希到一個足夠大的bitmap中,一個必定不存在的數據會被這個bitmap攔截掉,從
而避免了對底層存儲系統的查詢壓力。
3.若是一個查詢返回的數據爲空(無論是數 據不存在,仍是系統故障),咱們仍然把這個空結果進行緩存,但
它的過時時間會很短,最長不超過五分鐘。
緩存雪崩:當緩存服務器重啓或者大量緩存集中在一段時間內失效,發生大量的緩存穿透,這樣在失效的瞬間
對數據庫的訪問壓力就比較大,全部的查詢都落在數據庫上,形成了緩存雪崩。 這個沒有完美解決辦法,但可
以分析用戶行爲,儘可能讓失效時間點均勻分佈。大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線
程(進程)寫,從而避免失效時大量的併發請求落到底層存儲系統上。
解決方案:
1.在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢
數據和寫緩存,其餘線程等待。
2.能夠經過緩存reload機制,預先去更新緩存,再即將發生大併發訪問前手動觸發加載緩存
3.不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻
4.作二級緩存,或者雙緩存策略。A1爲原始緩存,A2爲拷貝緩存,A1失效時,能夠訪問A2,A1緩存失效時間
設置爲短時間,A2設置爲長期。
redis的安全機制(大家公司redis的安全這方面怎麼考慮的?)
漏洞介紹:redis默認狀況下,會綁定在bind 0.0.0.0:6379,這樣就會將redis的服務暴露到公網上,若是
在沒有開啓認證的狀況下,能夠致使任意用戶在訪問目標服務器的狀況下,未受權就可訪問redis以及讀取
redis的數據,攻擊者就能夠在未受權訪問redis的狀況下能夠利用redis的相關方法,成功在redis服務器上
寫入公鑰,進而能夠直接使用私鑰進行直接登陸目標主機;
解決方案:
1.禁止一些高危命令。修改redis.conf文件,用來禁止遠程修改DB文件地址
2.以低權限運行redis服務。爲redis服務建立單獨的用戶和根目錄,而且配置禁止登陸;
3.爲redis添加密碼驗證。修改redis.conf文件,添加requirepass mypassword;
4.禁止外網訪問redis。修改redis.conf文件,添加或修改 bind 127.0.0.1,使得redis服務只在當前主機使用;
5.作log監控,及時發現攻擊;
redis的哨兵機制(redis2.6之後出現的)
哨兵機制:
監控:監控主數據庫和從數據庫是否正常運行;
提醒:當被監控的某個redis出現問題的時候,哨兵能夠經過API向管理員或者其餘應用程序發送通知;
自動故障遷移:主數據庫出現故障時,能夠自動將從數據庫轉化爲主數據庫,實現自動切換;
若是master主服務器設置了密碼,記得在哨兵的配置文件(sentinel.conf)裏面配置訪問密碼
redis中對於生存時間的應用
Redis中能夠使用expire命令設置一個鍵的生存時間,到時間後redis會自動刪除;
應用場景:
設置限制的優惠活動的信息;
一些及時須要更新的數據,積分排行榜;
手機驗證碼的時間;
限制網站訪客訪問頻率;
講講ActiveMQ和其餘消息中間件之間的區別
activemq的原理
原理:生產者生產消息, 把消息發送給activemq。 Activemq 接收到消息, 而後查看有多少個消費者,
而後把消息轉發給消費者, 此過程當中生產者無需參與。 消費者接收到消息後作相應的處理和生產者沒有任何關係
對比RabbitMQ
RabbitMQ的協議是AMQP,而ActiveMQ使用的是JMS協議。顧名思義JMS是針對Java體系的傳輸協議,隊列兩
端必須有JVM,因此若是開發環境都是java的話推薦使用ActiveMQ,能夠用Java的一些對象進行傳遞好比
Map、Blob(二進制大數據)、Stream等。而AMQP通用行較強,非java環境常用,傳輸內容就是標準字
符串。RabbitMQ安裝比較麻煩。ActiveMQ解壓便可用不用任何安裝。
對比KafKa
Kafka性能超過ActiveMQ等傳統MQ工具,集羣擴展性好。
弊端是:
在傳輸過程當中可能會出現消息重複的狀況,
不保證發送順序
一些傳統MQ的功能沒有,好比消息的事務功能。
因此一般用Kafka處理大數據日誌。
對比Redis
其實Redis自己利用List能夠實現消息隊列的功能,可是功能不多,並且隊列體積較大時性能會急劇降低。對
於數據量不大、業務簡單的場景能夠使用。
如何解決消息重複問題
所謂消息重複,就是消費者接收到了重複的消息,通常來講咱們對於這個問題的處理要把握下面幾點,
①.消息不丟失(上面已經處理了)
②.消息不重複執行
通常來講咱們能夠在業務段加一張表,用來存放消息是否執行成功,每次業務事物commit以後,告知服務端,已經
處理過該消息,這樣即便你消息重發了,也不會致使重複處理
大體流程以下:業務端的表記錄已經處理消息的id,每次一個消息進來以前先判斷該消息是否執行過,若是執行
過就放棄,若是沒有執行就開始執行消息,消息執行完成以後存入這個消息的id
講講分佈式事務的異步通訊問題解決方案
問題介紹:一個消息發送過去了,無論結果如何發送端都不會原地等待接收端。直到接收端再推送回來回執消息,
發送端才直到結果。可是也有可能發送端消息發送後,石沉大海,杳無音信。這時候就須要一種機制可以對這種不
肯定性進行補充。
解決方案:
你給有不少筆友,平時寫信一去一回,可是有時候會遇到遲遲沒有回信的狀況。那麼針對這種偶爾出現的狀況,你
能夠選擇兩種策略。一種方案是你發信的時候用定個鬧鐘,設定1天之後去問一下對方收沒收到信。另外一種方案就
是天天夜裏定個時間查看一下全部發過信可是已經一天沒收到回覆的信。而後挨個打個電話問一下。
第一種策略就是實現起來就是延遲隊列,第二種策略就是定時輪詢掃描。
兩者的區別是延遲隊列更加精準,可是若是週期太長,任務留在延遲隊列中時間的就會很是長,會把隊列變得冗
長。好比用戶幾天後待辦提醒,生日提醒。
那麼若是遇到這種長週期的事件,並且並不須要精確到分秒級的事件,能夠利用定時掃描來實現,尤爲是比較消耗
性能的大範圍掃描,能夠安排到夜間執行。
講講怎麼解單點登陸的訪問,分佈式session跨域問題
單點登陸是相互信任的系統模塊登陸一個模塊後,其餘模塊不須要重複登陸即認證經過。
採用CAS單點登陸框架,首先CAS有兩大部分:客戶端和服務端。
服務端就是一個web工程部署在tomcat中。在服務端完成用戶認證操做。每次訪問系統模塊時,須要去CAS完成獲
取ticket。當驗證經過後,訪問繼續操做。對於CAS服務端來講,咱們訪問的應用模塊就是CAS客戶端。
什麼是跨域?當異步請求時,訪問的請求地址的協議、ip地址、端口號任意一個與當前站點不一樣時,就會涉及跨域訪問。
何時涉及跨域問題?當涉及前端異步請求的時候才涉及跨域。
解決方案:
一、jQuery提供了jsonp實現
二、W3C標準提供了CORS(跨域資源共享)解決方案。
用了CAS,全部應用項目中若是須要登陸時在web.xml中配置過濾器作請求轉發到cas端工做原理是在cas登陸後會
給瀏覽器發送一個票據(ticket),瀏覽器cookie中會緩存這個ticket,在登陸其餘項目時會拿着瀏覽器的
ticket轉發到cas,到cas後根據票據判斷是否登陸
講講linux命令awk、cat、sort、cut、grep、uniq、wc、top、find、sed等做用
awk:相較於sed 經常做用於一整個行的處理,awk 則比較傾向於一行當中分紅數個『字段』來處理。 所以,awk
至關的適合處理小型的數據數據處理
cat:主要用來查看文件內容,建立文件,文件合併,追加文件內容等功能。
sort:功能:排序文本,默認對整列有效
cut:cut命令能夠從一個文本文件或者文本流中提取文本列
grep:是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹配的行打印出來
uniq:功能:去除重複行,只會統計相鄰的
wc:功能: 統計文件行數、字節、字符數
top:用來監控Linux的系統情況,好比cpu、內存的使用
find:功能: 搜索文件目錄層次結構
sed:sed 是一種在線編輯器,它一次處理一行內容
講講什麼是死鎖,怎麼解決死鎖,表級鎖和行級鎖,悲觀鎖與樂觀鎖以及線程同步鎖區別
死鎖:打個比方,你去面試,面試官問你,你告訴我什麼是死鎖我就讓你進公司。你回答說你讓我進公司我就告訴你什麼是死鎖
互斥條件:資源不能被共享,只能由一個進程使用。
請求與保持條件:進程已得到了一些資源,但因請求其它資源被阻塞時,對已得到的資源保持不放。
不可搶佔條件:有些系統資源是不可搶佔的,當某個進程已得到這種資源後,系統不能強行收回,只能由進程
使用完時本身釋放。
循環等待條件:若干個進程造成環形鏈,每一個都佔用對方申請的下一個資源。
(1) 死鎖預防:破壞致使死鎖必要條件中的任意一個就能夠預防死鎖。例如,要求用戶申請資源時一次性申請
所須要的所有資源,這就破壞了保持和等待條件;將資源分層,獲得上一層資源後,纔可以申請下一層資源,
它破壞了環路等待條件。預防一般會下降系統的效率。
(2) 死鎖避免:避免是指進程在每次申請資源時判斷這些操做是否安全,例如,使用銀行家算法。死鎖避免算
法的執行會增長系統的開銷。
(3) 死鎖檢測:死鎖預防和避免都是事前措施,而死鎖的檢測則是判斷系統是否處於死鎖狀態,若是是,則執
行死鎖解除策略。
(4) 死鎖解除:這是與死鎖檢測結合使用的,它使用的方式就是剝奪。即將某進程所擁有的資源強行收回,分
配給其餘的進程。
表級鎖: 開銷小,加鎖快;不會出現死鎖(由於MyISAM會一次性得到SQL所需的所有鎖);鎖定粒度大,發生鎖衝
突的機率最高,併發度最低。
行級鎖: 開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
悲觀鎖:老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣
別人想拿這個數據就會阻塞直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖
等,讀鎖,寫鎖等,都是在作操做以前先上鎖。再好比Java裏面的同步原語synchronized關鍵字的實現也是悲觀
鎖。經過for update來實現
樂觀鎖:顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會
判斷一下在此期間別人有沒有去更新這個數據,能夠使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣能夠
提升吞吐量,像數據庫提供的相似於write_condition機制,其實都是提供的樂觀鎖。在Java中
java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS實現的。經過version版本字段來實現
同步鎖:
場景:在開發中,遇到耗時的操做,咱們須要把耗時的邏輯放入子線程中執行,防止卡頓。二個線程分別執行兩個
任務,同時執行完成,同時解析文件,獲取數據後,同時插入數據庫,因爲插入的表比較多,這樣容易出現插入錯
亂的bug
採用synchronized:
聲明該方法爲同步方法,若是一個方法正在執行,別的方法調用,則處於等待狀態。當這個方法執行完成後,能夠
調用解鎖方法,wait():釋放佔有的對象鎖,線程進入等待池。
區別:
synchronized是在JVM層面實現的,所以系統能夠監控鎖的釋放與否,而ReentrantLock使用代碼實現的,系統
沒法自動釋放鎖,須要在代碼中finally子句中顯式釋放鎖lock.unlock();
在併發量比較小的狀況下,使用synchronized是個不錯的選擇,可是在併發量比較高的狀況下,其性能降低
很嚴重,此時ReentrantLock是個不錯的方案。
講講怎麼加快訪問速度,怎樣進行程序性能調優
加快訪問:
硬件上加大網絡帶寬、和服務器內存
代碼的處理:靜態頁面、緩存、優化sql、建立索引等方案
系統性能就是兩個事:
Throughput ,吞吐量。也就是每秒鐘能夠處理的請求數,任務數。
Latency, 系統延遲。也就是系統在處理一個請求或一個任務時的延遲。
那麼Latency越好,能支持的Throughput就會越高。由於Latency短說明處理速度快,因而就能夠處理更多的請求。
提升吞吐量:分佈式集羣,模塊解藕,設計模式
系統延遲:異步通訊
講講緩存的設計和優化,緩存和數據庫一致性同步解決方案
1.下降後端負載:對於高消耗的SQL:join結果集、分組統計結果;對這些結果進行緩存。
2.加速請求響應
3.大量寫合併爲批量寫:如計數器先redis累加再批量寫入DB
4.超時剔除:例如expire
5.主動更新:開發控制生命週期(最終一致性,時間間隔比較短)
6.緩存空對象
7.布隆過濾器攔截
8.命令自己的效率:例如sql優化,命令優化
9.網絡次數:減小通訊次數
10.下降接入成本:長連/鏈接池,NIO等。
11.IO訪問合併
目的:要減小緩存重建次數、數據儘量一致、減小潛在危險。
解決方案:
1.互斥鎖setex,setnx:
若是 set(nx 和 ex) 結果爲 true,說明此時沒有其餘線程重建緩存,那麼當前線程執行緩存構建邏輯。
若是 setnx(nx 和 ex) 結果爲 false,說明此時已經有其餘線程正在執行構建緩存的工做,那麼當前線程將休
息指定時間 ( 例如這裏是 50 毫秒,取決於構建緩存的速度 ) 後,從新執行函數,直到獲取到數據。
2永遠不過時:
熱點key,無非是併發特別大一級重建緩存時間比較長,若是直接設置過時時間,那麼時間到的時候,巨大的訪
問量會壓迫到數據庫上,因此要給熱點key的val增長一個邏輯過時時間字段,併發訪問的時候,判斷這個邏輯
字段的時間值是否大於當前時間,大於了說明要對緩存進行更新了,那麼這個時候,依然讓全部線程訪問老的
緩存,由於緩存並無設置過時,可是另開一個線程對緩存進行重構。等重構成功,即執行了redis set操做
以後,全部的線程就能夠訪問到重構後的緩存中的新的內容了
從緩存層面來看,確實沒有設置過時時間,因此不會出現熱點 key 過時後產生的問題,也就是「物理」不過時。
從功能層面來看,爲每一個 value 設置一個邏輯過時時間,當發現超過邏輯過時時間後,會使用單獨的線程去構建緩存。
一致性問題:
1.先刪除緩存,而後在更新數據庫,若是刪除緩存失敗,那就不要更新數據庫,若是說刪除緩存成功,而更新
數據庫失敗,那查詢的時候只是從數據庫裏查了舊的數據而已,這樣就能保持數據庫與緩存的一致性。
2.先去緩存裏看下有沒有數據,若是沒有,能夠先去隊列裏看是否有相同數據在作更新,發現隊列裏有一個請
求了,那麼就不要放新的操做進去了,用一個while(true)循環去查詢緩存,循環個200MS左右再次發送到
隊列裏去,而後同步等待緩存更新完成。
講講消息隊列和消息被重複消費怎麼處理,消費者接收不到消息怎麼辦
什麼是消息隊列?
就是消息的傳輸過程當中保存消息的容器。
消息隊列都解決了什麼問題?
異步,並行,解耦,排隊
消息模式?
訂閱,點對點
1、重複消費:Queue支持存在多個消費者,可是對一個消息而言,只會有一個消費者能夠消費。
2、丟消息:
1.用持久化消息
2.非持久化消息及時處理不要堆積
3.啓動事務,啓動事務後,commit()方法會負責等待服務器的返回,也就不會關閉鏈接致使消息丟失。
3、消息重發:
消息被從新傳遞給客戶端:
一、使用事務會話,並調用滾退()。
二、在調用commit()以前關閉事務會話。
三、會話使用CLIENT_ACKNOWLEDGE簽收模式,並Session .recover()重發被調用。
四、客戶端鏈接超時(也許正在執行的代碼要比配置的超時週期更長)。
4、不消費:去ActiveMQ.DLQ裏找找
什麼是ActiveMQ.DLQ?
1.一旦消息的重發嘗試超過了爲重發策略配置的最大重發次數,一個「Poison ACK」被髮送回the broker,讓
他知道消息被認爲是毒丸。the broker而後接收消息並將其發送到死信隊列,以便之後能夠進行分析。
2.在activemq中死信隊列叫作ActiveMQ.DLQ。全部沒法傳遞的消息將被髮送到這個隊列,這很難管理。
3.所以,您能夠在Activemq.xml配置文件的目標策略映射中設置個體死信策略,它容許您爲隊列或主題指定
特定的死信隊列前綴。
Mq消費者接受不到消息存在2中狀況:
1. 處理失敗 指的是MessageListener的onMessage方法裏拋出RuntimeException。
2. Message頭裏有兩個相關字段:Redelivered默認爲false,redeliveryCounter默認爲0。
3. 消息先由broker發送給consumer,consumer調用listener,若是處理失敗,本地
redeliveryCounter++,給broker一個特定應答,broker端的message裏redeliveryCounter++,延遲一點
時間繼續調用,默認1s。超過6次,則給broker另外一個特定應答,broker就直接發送消息到DLQ。
4. 若是失敗2次,consumer重啓,則broker再推過來的消息裏,redeliveryCounter=2,本地只能再重試4次
即會進入DLQ。
5. 重試的特定應答發送到broker,broker即會在內存將消息的redelivered設置爲
true,redeliveryCounter++,可是這兩個字段都沒有持久化,即沒有修改存儲中的消息記錄。因此broker重
啓時這兩個字段會被重置爲默認值。
講講SOA與分佈式的區別,zookeeper或者activeMQ服務掛了怎麼辦
SOA和分佈式的區別?
SOA,將工程拆分紅服務層、表現層兩個工程,服務層中包含業務邏輯,只須要對外提供服務便可。表現層只須要
處理和頁面的交互,業務邏輯都是調用服務層的服務來實現。
分佈式,主要仍是從部署的角度,將應用按照訪問壓力進行歸類,主要目標是充分利用服務器的資源,避免資源分配不均
若是activeMQ的服務掛了,怎麼辦?
一、在一般的狀況下,非持久化消息是存儲在內存中的,持久化消息是存儲在文件中的,它們的最大限制在配置文
件的<systemUsage>節點中配置。可是,在非持久化消息堆積到必定程度,內存告急的時候,ActiveMQ會將內存
中的非持久化消息寫入臨時文件中,以騰出內存。雖然都保存到了文件裏,但它和持久化消息的區別是,重啓後持
久化消息會從文件中恢復,非持久化的臨時文件會直接刪除。
二、考慮高可用,實現activemq集羣。
若是zookeeper服務掛了怎麼辦?
註冊中心對等集羣,任意一臺宕掉後,會自動切換到另外一臺
註冊中心所有宕掉,服務提供者和消費者仍能夠經過本地緩存通信
服務提供者無狀態,任一臺宕機後,不影響使用
服務提供者所有宕機,服務消費者會沒法使用,並沒有限次重連等待服務者恢復
講講JUC的輔助類
ReentrantReadWriteLock:讀寫鎖
CountDownLatch:減小計數
CyclicBarrier:循環柵欄
Semaphore:信號燈
SSM框架面試問題
講下springmvc框架的工做流程
一、用戶向服務器發送請求,請求被SpringMVC的前端控制器DispatcherServlet截獲。
二、DispatcherServlet對請求的URL(統一資源定位符)進行解析,獲得URI(請求資源標識符),而後根據該URI,調用HandlerMapping得到該Handler配置的全部相關的對象,包括Handler對象以及Handler對象對應的攔截器,這些對象都會被封裝到一個HandlerExecutionChain對象當中返回。
三、DispatcherServlet根據得到的Handler,選擇一個合適的HandlerAdapter。HandlerAdapter的設計符合面向對象中的單一職責原則,代碼結構清晰,便於維護,最爲重要的是,代碼的可複製性高。HandlerAdapter會被用於處理多種Handler,調用Handler實際處理請求的方法。
四、提取請求中的模型數據,開始執行Handler(Controller)。在填充Handler的入參過程當中,根據配置,spring將幫助作一些額外的工做
消息轉換:將請求的消息,如json、xml等數據轉換成一個對象,將對象轉換爲指定的響應信息。
數據轉換:對請求消息進行數據轉換,如String轉換成Integer、Double等。
數據格式化:對請求的消息進行數據格式化,如將字符串轉換爲格式化數字或格式化日期等。
數據驗證:驗證數據的有效性如長度、格式等,驗證結果存儲到BindingResult或Error中。
五、Handler執行完成後,向DispatcherServlet返回一個ModelAndView對象,ModelAndView對象中應該包含視圖名或視圖模型。
六、根據返回的ModelAndView對象,選擇一個合適的ViewResolver(視圖解析器)返回給DispatcherServlet。
七、ViewResolver結合Model和View來渲染視圖。
八、將視圖渲染結果返回給客戶端。
以上8個步驟,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver等對象協同工做,完成SpringMVC請求—>響應的整個工做流程,這些對象完成的工做對於開發者來講都是不可見的,開發者並不須要關心這些對象是如何工做的,開發者,只須要在Handler(Controller)當中完成對請求的業務處理。
圖片怎麼上傳
前端實現異步上傳,後端使用springmvc的MultipartFile類型來接收,放到分佈式圖片服務器中,服務器返回圖片路徑把路徑返回頁面回顯圖片,開發或者測試環境能夠使用FastDFS
微服務和SOA有什麼區別?
若是一句話來談SOA和微服務的區別,即微服務再也不強調傳統SOA架構裏面比較重的ESB企業服務總線,同時SOA的思想進入到單個業務系統內部實現真正的組件化。說的更直白一點就是微服務被拆分的粒度更小
spring框架AOP執行原理簡單說下?還有就是AOP在事務管理方面是怎麼實現的?
Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理經過反射來接收被代理的類,而且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。若是目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,能夠在運行時動態的生成某個類的子類,注意,CGLIB是經過繼承的方式作的動態代理,所以若是某個類被標記爲final,那麼它是沒法使用CGLIB作動態代理的。
AOP在事務管理方面,Spring使用AOP來完成聲明式的事務管理有annotation和xml兩種形式。開發中,方便代碼編寫,不少時候都是在spring配置文件中配置事務管理器並開啓事務控制註解。在業務類或業務類方法中添加@Transactional實現事務控制。
Spring 分佈式事務如何處理的?
回答:
第一種方案:可靠消息最終一致性,須要業務系統結合MQ消息中間件實現,在實現過程當中須要保證消息的成功發送及成功消費。即須要經過業務系統控制MQ的消息狀態
第二種方案:TCC補償性,分爲三個階段TRYING-CONFIRMING-CANCELING。每一個階段作不一樣的處理。
TRYING階段主要是對業務系統進行檢測及資源預留
CONFIRMING階段是作業務提交,經過TRYING階段執行成功後,再執行該階段。默認若是TRYING階段執行成功,CONFIRMING就必定能成功。
CANCELING階段是回對業務作回滾,在TRYING階段中,若是存在分支事務TRYING失敗,則須要調用CANCELING將已預留的資源進行釋放。
Springboot用過沒,跟我說說,他的特色?
Springboot是從無數企業實戰開發中總結出來的一個更加精煉的框架,使得開發更加簡單,能使用寥寥數行代碼,完成一系列任務。
Springboot解決那些問題
a)編碼更簡單
Spring框架因爲超重量級的XML,annotation配置,使得系統變得很笨重,難以維護
Springboot採用約點大於配置的方法,直接引入依賴,便可實現代碼的開發
b)配置更簡單
Xml文件使用javaConfig代替,XML中bean的建立,使用@bean代替後能夠直接注入。
配置文件變少不少,就是application.yml
c)部署更簡單
d)監控更簡單
Spring-boot-start-actuator:
能夠查看屬性配置
線程工做狀態
環境變量
JVM性能監控
支付接口是怎麼作的?
微信支付
調用微信的支付接口,參考微信提供的api
使用了微信的統一下單接口和查詢支付狀態接口
每一個接口須要的參數放入到map中使用微信提供的sdk轉成XML字符串,httpClient遠程提交參數和接收結果。
支付寶支付
SpringBoot相關面試題
什麼是 Spring Boot?
Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各類啓動器,開發者能快速上手。
爲何要用 Spring Boot?
Spring Boot 優勢很是多,如:
獨立運行
簡化配置
自動配置
無代碼生成和XML配置
應用監控
上手容易
Spring Boot 的核心配置文件有哪幾個?它們的區別是什麼?
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。
bootstrap 配置文件有如下幾個應用場景。
使用 Spring Cloud Config 配置中心時,這時須要在 bootstrap 配置文件中添加鏈接到配置中心的配置屬性來加載外部配置中心的配置信息;
一些固定的不能被覆蓋的屬性;
一些加密/解密的場景
Spring Boot 的配置文件有哪幾種格式?它們有什麼區別?
.properties 和 .yml,它們的區別主要是書寫格式不一樣。
Spring Boot 的核心註解是哪一個?它主要由哪幾個註解組成的?
啓動類上面的註解是@SpringBootApplication,它也是 Spring Boot 的核心註解,主要組合包含了如下 3 個註解:
@SpringBootConfiguration:組合了 @Configuration 註解,實現配置文件的功能。
@EnableAutoConfiguration:打開自動配置的功能,也能夠關閉某個自動配置的選項,如關閉數據源自動配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring組件掃描。
開啓 Spring Boot 特性有哪幾種方式?
1)繼承spring-boot-starter-parent項目
2)導入spring-boot-dependencies項目依賴
Spring Boot 須要獨立的容器運行嗎?
能夠不須要,內置了 Tomcat/ Jetty 等容器.
運行 Spring Boot 有哪幾種方式?
1)打包用命令或者放到容器中運行
2)用 Maven/ Gradle 插件運行
3)直接執行 main 方法運行
Spring Boot 自動配置原理是什麼?
註解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。
你如何理解 Spring Boot 中的 Starters?
Starters能夠理解爲啓動器,它包含了一系列能夠集成到應用裏面的依賴包,你能夠一站式集成 Spring 及其餘技術,而不須要處處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數據庫,只要加入 spring-boot-starter-data-jpa 啓動器依賴就能使用了。
Starters包含了許多項目中須要用到的依賴,它們能快速持續的運行,都是一系列獲得支持的管理傳遞性依賴.
如何在 Spring Boot 啓動的時候運行一些特定的代碼?
能夠實現接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現方式同樣,它們都只提供了一個 run 方法.
Spring Boot 有哪幾種讀取配置的方式?
Spring Boot 能夠經過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量
電商項目業務面試問題
哪些狀況用到activeMq?
商品上架後更新ES索引庫、更新靜態頁、發送短信
秒殺的時候,只有最後一件物品,該怎麼去搶或者分配?
秒殺商品的庫存都會放到redis中,在客戶下單時就減庫存,減完庫存會判斷庫存是否爲大於 0,若是小於0,表示庫存不足,剛纔減去的數量再恢復,整個過程使用redis的watch鎖。
你項目對於訂單是怎麼處理的,假如一個客戶在下訂單的時候沒有購買怎麼辦,對於顧客在購買商品的時候大家怎麼處理大家的庫存?
訂單表中設置了一個過時時間,天天會有定時任務來掃描訂單表數據,若是到達預訂的過時時間沒有付款就會取消此訂單交易。
關於庫存的設計是這樣的:
普通商品在發貨時纔去更新庫存,若是庫存不足商家會立刻補貨
秒殺的商品會在客戶下單時就減庫存,若是在規定時間(半個小時)沒有付款,會取消此訂單把庫存還原
redis存儲格式的選擇
redis支持的數據結構總共有5種:hash、value、list、set、zset,其中項目中用到最可能是hash
商品表中的數據是哪裏來的
商品表的數據是在商家管理後臺中由商家錄入的。數據分別錄入到商品表、商品描述表和商品項表
當初設計項目時預計的訪問量計劃是多少
訪問量計劃是3000至5000
簡單介紹一下你的這個項目以及項目中涉及到的技術框架以及使用場景以及你主要負責項目中的哪一塊?
項目介紹時,先總體介紹是什麼項目,項目主要是作啥的,爲何會作這個項目(市場需求)?例如:XXX電商項目,是一個B2B2C綜合電商平臺。由三個系統組成,包含:運營商管理後臺、商家管理後臺、網站前臺。運營商平臺主要負責基礎數據維護、商家審覈、商品審覈等。商家管理後臺主要負責商家入駐、商品錄入/修改、商品上下架等。網站前臺主要負責商品銷售。包含:網站首頁、商品搜索、商品詳情展現、購物車、訂單、支付、用戶中心等模塊。
再介紹本身在項目中作的功能模塊。例如:運營商管理後臺的品牌、規格數據錄入,已經商品管理後臺商品錄入功能。同時,實現了網站前臺系統中的商品搜索、購物車等功能模塊。
而後介紹裏面使用的技術:例如:dubbo分佈式框架、ssm、es、redis、activeMQ、支付寶支付等等。最好是結合技術講解項目功能點如何實現。
秒殺系統中如何防止超售?如何避免腳本進行惡意刷單?
防止超售解決方案:將存庫從MySQL前移到Redis中,全部的寫操做放到內存中,因爲Redis中不存在鎖故不會出現互相等待,而且因爲Redis的寫性能和讀性能都遠高於MySQL,這就解決了高併發下的性能問題。而後經過隊列等異步手段,將變化的數據異步寫入到DB中。當達到庫存閥值的時候就不在消費隊列,並關閉購買功能。
避免腳本惡意刷單:採用IP級別的限流,即針對某一個IP,限制單位時間內發起請求數量。
單點登陸大家是本身編寫的仍是使用通用的CAS?
項目使用通用的CAS框架。
若是一個用戶的token被其餘用戶劫持了,怎樣解決這個安全問題。
a、在存儲的時候把token進行對稱加密存儲,用時解開。
b、將請求URL、時間戳、token三者進行合併加鹽簽名,服務端校驗有效性。
c、HTTPS對URL進行加密
項目部署上線後,運營商管理,商品審覈等後臺流量問題?
回答:
先詢問流量是指哪方面?流量分爲三種,一種是商家流量,另外一種是用戶流量,第三種運營商流量。
解決方案:
這三種流量對系統運行形成很大壓力,隨着項目上線時間增加,壓力會愈來愈大,所以咱們要減輕系統訪問壓力 ,就須要作一系列優化措施。
具體優化以下:
數據層面的優化:
從數據庫層面作優化,好比:索引,緩存,集羣,讀寫分離,主從複製,分表,分庫。
從數據庫設計層面的優化:好比減小表關聯,加入冗餘字段
從緩存方面優化:好比redis實現數據緩存,減輕數據庫壓力
從搜索上進行優化:好比查找索引庫
項目層面的優化:
採用面向服務的分佈式架構:分擔服務器壓力 ,提升項目併發量。 好比dubbox+zookeeper分佈式架構
採用分佈式文件系統實現海量文件存儲:如採用fastdfs實現海量圖片存儲,提升文件的訪問速度。
採用mq使用服務進一步解藕:同步索引庫,同步靜態資源,短信發送
服務器層面的優化:
集羣思想的使用:tomcat,zookeeper,redis,mysql等
Tomcat異步通訊的使用,tomcat鏈接池配置
秒殺和團購業務實現思路
回答:
將商品數量查詢出存入到redis中,全部用戶下單後,減掉redis中的數量
若是併發量很大時,還要考慮高併發問題,因此能夠加入mq消息中間件處理搶單問題,再結合redis實現庫存減小操做。高併發方面還能夠考慮CDN,Nginx負載均衡等
大家項目中使用的安全框架是什麼?
使用springSecurity 或者shiro,校驗用戶登陸和用戶權限!
項目中使用到的應用服務器是什麼?
Tomcat+nginx
講一下每臺服務器的集羣數量:
項目中一共15臺項目服務,那麼爲了每一臺高可用一主一備,但首頁項目高併發設爲四臺服務器,則一共32臺項目服務器,再加redis集羣用了3臺,爲了每一臺高可用一主一備一共6臺,fastdfs一個trackerServer一個storageServer搭建集羣一共6臺,solr集羣7臺服務器,nginx爲了高可用一主一備一共2臺,mysql數據庫集羣3臺!activemq消息中間件高可用2臺;
共計:58臺服務器!
你在項目開發中碰到過哪些重大且棘手的問題
場景一:需求不明確困境
在項目開發中,項目採用迭代開發,開發需求不是很明確,對於項目開發初期來講很是困難,進度很是慢,有時開發的出的產品結果每每不能令老闆滿意,或者是甲方滿意,項目還須要不停的迭代,修改。
好比說:
在開發商城項目的時候,客戶定位是一個綜合性的商務平臺,能夠實如今線第三方商家對接,實現商品的銷售
可是並無明確的需求,所以開發全憑藉電商的項目經驗來實現裏面的相關的業務,後期慢慢迭代。
場景二: ES高亮不能顯示的問題
前臺使用angularJS加載搜索結果,可是發現高亮不能展現。
問題緣由:
angularJS底層使用ajax,異步加載高亮信息返回給頁面後,頁面沒有刷新,就直接顯示返回的數據。此時會把全部的數據做爲普通的文本數據進行加載。所以就沒有高亮的效果。
解決方案:
使用angularJS過濾器過濾文本數據,此時angularJS過濾器把html文本數據解析爲瀏覽器能識別的html標籤。高亮就能展現了。
場景三:Nginx靜態頁面服務跳轉到購物車跨域問題
在Nginx中部署了靜態頁面,添加購物車時必須從靜態頁面跳轉到購物車系統,實現購物車添加操做。
因爲在靜態頁面中使用angularJS實現的跳轉,發現跳轉到購物車系統徹底沒有問題,可是並不能跳轉回到購物車系統頁面。
問題分析:
從靜態詳情繫統跳轉到購物車系統,會存在跨域問題,所以不能進行回調函數的數據傳遞。因此在回調函數中的頁面跳轉就不能實現。
解決方案:
使用angularJS跨域調用及springmvc跨域配置,解決問題。
場景四:activeMQ存在運行時間長了之後,收不到消息的現象
時間長了就會出現,卡死,新的數據不能從隊列接聽到。只能重啓程序。
解決方案:
1)不要頻繁的創建和關閉鏈接
JMS使用長鏈接方式,一個程序,只要和JMS服務器保持一個鏈接就能夠了,不要頻繁的創建和關閉鏈接。頻繁的創建和關閉鏈接,對程序的性能影響仍是很大的。這一點和jdbc仍是不太同樣的。
2)Connection的start()和stop()方法代價很高
JMS的Connection的start()和stop()方法代價很高,不能常常調用。咱們試用的時候,寫了個jms的connection pool,每次將connection取出pool時調用start()方法,歸還時調用stop()方法,然然後來用jprofiler發現,通常的cpu時間都耗在了這兩個方法上。
3)start()後才能收消息
Connection的start()方法調用後,才能收到jms消息。若是不調用這個方法,能發出消息,可是一直收不到消息。不知道其它的jms服務器也是這樣。
4)顯式關閉Session
若是忘記了最後關閉Connection或Session對象,都會致使內存泄漏。這個在我測試的時候也發現了。原本覺得關閉了Connection,由這個Connection生成的Session也會被自動關閉,結果並不是如此,Session並無關閉,致使內存泄漏。因此必定要顯式的關閉Connection和Session。
5)對Session作對象池
對Session作對象池,而不是Connection。Session也是昂貴的對象,每次使用都新建和關閉,代價也很是高。並且後來咱們發現,原來Connection是線程安全的,而Session不是,因此後來改爲了對Session作對象池,而只保留一個Connection。
6) 集羣
ActiveMQ有強大而靈活的集羣功能,可是使用起來仍是會有不少陷阱
場景五:activeMQ存在發出消息太大,形成消息接受不成功
多個線程從activeMQ中取消息,隨着業務的擴大,該機器佔用的網絡帶寬愈來愈高。
仔細分析發現,mq入隊時並無異常高的網絡流量,僅僅在出隊時會產生很高的網絡流量。
最終發現是spring的jmsTemplate與activemq的prefetch機制配合致使的問題。
研究源碼發現jmsTemplate實現機制是:每次調用receive()時都會建立一個新的consumer對象,用完即銷燬。
正常狀況下僅僅會浪費重複建立consumer的資源代價,並不至於產生正常狀況十倍百倍的網絡流量。
可是activeMQ有一個提升性能的機制prefetch,此時就會有嚴重的問題。
prefetch機制:
每次consumer鏈接至MQ時,MQ預先存放許多message到消費者(前提是MQ中存在大量消息),預先存 放message的數量取決於prefetchSize(默認爲1000)。此機制的目的很顯然,是想讓客戶端代碼用一個consumer反覆進行 receive操做,這樣可以大量提升出隊性能。
此機制與jmsTemplate配合時就會產生嚴重的問題,每次jmsTemplate.receive(),都會產生1000個消息的網絡流量, 可是由於jmsTemplae並不會重用consumer,致使後面999個消息都被廢棄。反覆jmsTemplate.receive()時,表面上看 不出任何問題,其實網絡帶寬會形成大量的浪費。
解決方案:
一、若堅持使用jmsTemplate,須要設置prefetch值爲1,至關於禁用了activeMQ的prefetch機制,此時感受最健壯, 就算多線程,反覆調用jmsTemplate.receive()也不會有任何問題。可是會有資源浪費,由於要反覆建立consumer並頻繁與服務器進 行數據通訊,但在性能要求不高的應用中也不算什麼問題。
二、不使用jmsTemplate,手工建立一個consumer,並單線程反覆使用它來receive(),此時能夠充分利用prefetch機制。配合多線程的方式每一個線程擁有本身的一個consumer,此時可以充分發揮MQ在大吞吐量時的速度優點。
切記避免多線程使用一個consumer形成的消息混亂。大吞吐量的應用推薦使用方案2,可以充分利用prefetch機制提升系MQ的吞吐性能。
商品的價格變化後,如何同步redis中數以百萬計的購物車數據。
解決方案:
購物車只存儲商品id,到購物車結算頁面將會重新查詢購物車數據,所以就不會涉及購物車商品價格同步的問題。
系統中的錢是如何保證安全的。
在當前互聯網系統中錢的安全是頭等大事,如何保證錢的安全能夠從如下2個方面來思考:
1)錢計算方面
在系統中必須是浮點數計算類型存儲錢的額度,不然計算機在計算時可能會損失精度。
2)事務處理方面
在當前環境下,高併發訪問,多線程,多核心處理下,很容易出現數據一致性問題,此時必須使用事務進行控制,訪問交易出現安全性的問題,那麼在分佈式系統中,存在分佈式事務問題,能夠有不少解決方案:
使用 jpa能夠解決
使用 tcc 框架能夠解決等等。
作交易或是金融系統安全性須要從哪些方面考慮?沒有用什麼第三方能夠框架
ip黑白名單,訪問日誌明細記錄,防止重複提交,訪問頻率控制,分佈式鎖,數據先後端校驗,自動對帳任務處理,互聯網金融項目通常狀況下,不建議自動重試,最好結合對帳系統,人工進行處理,寫好人工處理的接口就好。其餘就是控制好數據的一致性了,這個最重要,其次還要保證接口的冪等性,不要重複處理訂單。這些是最基本的安全控制了。像這類網站用戶的輸入數據通常都不會太多,通常敏感詞過濾,廣告之類的能夠忽略,若是有的話還要控制這些。安全框架選shiro 了,在系統中分配好角色就行了,控制好用戶的資源訪問。其餘的用springmvc 就夠了
訂單中的事物是如何保證一致性的。
使用分佈式事務來進行控制,保證數據最終結果的一致性。
當商品庫存數量不足時,如何保證不會超賣。
當庫存數量不足時,必須保證庫存不能被減爲負數,若是不加以控制,庫存被減爲小於等於0的數,那麼這就叫作超賣。
那麼如何防止超賣的現象發生呢?
場景一: 若是系統併發要求不是很高
那麼此時庫存就能夠存儲在數據庫中,數據庫中加鎖控制庫存的超賣現象。
場景二:系統的併發量很大
若是系統併發量很大,那麼就不能再使用數據庫來進行減庫存操做了,由於數據庫加鎖操做自己是以損失數據庫的性能來進行控制數據庫數據的一致性的。
可是當併發量很大的時候,將會致使數據庫排隊,發生阻塞。所以必須使用一個高效的nosql數據庫服務器來進行減庫存。
此時能夠使用redis服務器來存儲庫存,redis是一個內存版的數據庫,查詢效率至關的高,能夠使用watch來監控減庫存的操做,一旦發現庫存被減爲0,立馬中止售賣操做。
大家系統的商品模塊和訂單模塊的數據庫是怎麼設計的
商品模塊設計:
商品模塊一共8張表,整個核心就是模板表。採用模板表爲核心的設計方法,來構造商品數據。
訂單設計:
訂單涉及的表有:
1) 收貨人地址
2) 訂單信息
3) 訂單明細
系統中商家活動策劃以及上報相關業務流程。
商城系統中有如下活動:
1) 秒殺活動
a) 後臺設置秒殺商品
b) 設置秒殺開啓時間,定時任務,開啓秒殺
c) 秒殺減庫存(秒殺時間結束,庫存賣完,活動結束)
2) 促銷活動
3) 團購活動
4) 今日推薦
以上活動銷售記錄,統計,使用圖形化報表進行統計,能夠查看銷售狀況。
涉及到積分積累和兌換商品等業務是怎麼設計的
積分累計有2大塊:
積分累計:
根據用戶購買的商品的價格不一樣,沒有購買必定價格的商品,獲取必定的積分。
積分商城:
積分商城是用戶能夠使用積分商品換取商品的區域。
介紹下電商項目,你以爲那些是亮點?
這個項目是爲xxx開發的b2b2c類型綜合購物平臺,主要以銷售xxx,電子產品爲主要的電子商城網站。
項目的亮點是:
1)項目採用面向服務分佈式架構(使用dubbo,zookeeper)
a) 解耦
b) 提升項目併發能力
c) 分擔服務器壓力
2)項目中使用activeMQ對項目進一步解耦
a) 提升項目併發能力
b) 提升任務處理速度
3) 使用微信支付,支付寶支付(本身總結)
4) 使用阿里大魚發生短信
5) 使用第三方分佈式文件系統存儲海量文件
6) Nginx部署靜態頁面實現動靜分離
購物車功能作了嗎,實現原理說一下?
加入購物車
加入購物車插入到庫中一條購物記錄,同時插入到緩存中,緩存的key是記錄的id
未登陸狀態
用戶未登陸時點擊加入購物車,將productId ,skuId,buyNum 轉換成json存到cookie中(同一件商品不一樣的skuId視爲兩個商品,相同的skuId和productId視爲相同商品數量累加),用戶登陸成功的時候接收用戶的消息將cookie中的商品信息保存到數據庫中,而後清空cookie數據(京東)否則會出現登陸成功後刪除購物車商品而後退出,購物車中顯示問題
登陸狀態
點擊加入購物車將long userId,long productId,long skuId,int count 存到庫中,相同的productId和skuId 數量累加,不一樣的skuId新增一條
addToCart(long userId,long skuId,int count); //加入sku到購物車商品
修改商品數量
未登陸狀態
用戶未登陸時,點擊加減數量,根據productId和skuId從cooike中將商品數量進行加減,注意校驗cooike中的數量不能小於0,不能大於庫存數量
登陸狀態
用戶登陸狀態時,點擊加減數量productId和skuId,userId將用戶購物車中某個sku的數量增長或減去differ值,注意校驗庫存數量
updateAmount(long userId,skuId,int differ,List selectedSkuIds); //將用戶購物車中某個sku的數量增長或減去differ值。此方法更新商品後,會根據selectedSkuIds從新計算一遍購物車價格,返回知足條件的優惠券
刪除購物車記錄
未登陸狀態
用戶未登陸時,根據productId和skuId刪除cookie中的記錄
deleteCart(long userId,long skuId, List selectedSkuIds); //將某個sku從用戶購物車移除。此接品,在清除後臺會重複計算selectedSkuIds價格,並會返回選中的sku列表與未選中的sku列表集合。及相應優惠券。
登陸狀態
登陸狀態下,直接根據productId和skuId以及userId刪除庫中數據
4購物車列表展現
未登陸狀態
從cookie中取出productId以及skuId列表展現商品信息
登陸狀態
登陸狀態下根據用戶id查詢庫中的記錄數
getCart(long userId,list selectedSkuIds); //查詢用戶購物車。此接口會從新計算selectedSkuIds,並返回選中與未選中sku列表集合,返回相應的知足條件的優惠券信息。
5.訂單提交成功後更新購物車數量以及修改購物車狀態
訂單提交成功後接收訂單成功消息,更新購物車狀態和數量刪除緩存記錄
6.商品下架後,更新庫存狀態,顯示失效
商品下架後接收消息修改購物車裏的商品狀態爲失效
大家的項目上線了嗎?這麼大的項目怎麼沒上線?
項目上線問題回答:
1) 項目沒有上線
若是你沒有作過電商的項目,能夠說項目沒有上線以前,你離職了,這個一個創業型的公司,或者此項目是給甲方作的項目,你沒有參與上線。以此來回避這個問題.
2) 項目上線
項目已經上線了
上線環境:
a) Centos7
b) Mysql
c) Jdk8
d) Tomcat8
關於上線,那麼面試官必定會問您,上線遇到什麼問題沒有?
所以必須把項目中遇到的問題準備2個,如下能夠做爲參考
問題一:(用戶非正常流程致使的錯誤)
用戶註冊一半就退出來,致使再次註冊不成功或者用證件號登錄觸發空指針異常。
解決辦法:一旦輸入證件號時,檢查數據庫的表是否有相應的證件號記錄,有則把相關記錄所有刪掉,從而讓他成功註冊。空指針異常的解決辦法,作非空驗證的判斷。
問題二:(併發插入,流水號不一致)
出現大量的主鍵惟一約束錯誤,後來想到是產生的預報名號不一樣步,致使有可能大併發量時產生多個相同的流水號,插入就會出現主鍵惟一約束錯誤。
解決辦法:在數據庫裏寫一個insert的觸發器。自動替換掉要插入的主鍵爲 max(key)+1.
問題三:(併發刪除,索引失效)
出現某些表的索引失效,後來發現是插入相同主鍵屢次以後致使表失效。
解決辦法:設定oracle任務,讓數據庫每隔12個小時自動重建全部索引。
問題四:(js代碼的不細緻)
發現報考志願顯示的專業比原來的少一個。
解決辦法:發現時jsp頁面的js少循環一個=號致使的。。。。
問題五:(頁面和後臺代碼太不通用)
用戶需求一旦更改或者程序邏輯有錯誤後,致使要修改不少頁面和後臺代碼,十分不通用,要從業務邏輯上設計的通用點。改一個,就能等同於改所有。用一些設計模式去解決。
訂單怎麼實現的,大家這個功能怎麼這麼簡單?
訂單實現:
從購物車系統跳轉到訂單頁面,選擇默認收貨地址
選擇支付方式
購物清單展現
提交訂單
訂單業務處理:
一個商家一個訂單,不一樣的倉庫發送的貨品也是屬於不一樣的訂單。所以會產出不一樣的訂單號。
訂單處理:根據支付的狀態進行不一樣的處理
1) 在線支付
a) 支付未成功—重新發起支付
b) 支付超時---訂單關閉
2) 貨到付款
大家這個項目有秒殺嗎,怎麼實現的?
所謂「秒殺」,就是網絡賣家發佈一些超低價格的商品,
全部買家在同一時間網上搶購的一種銷售方式。通俗一點講就是網絡商家爲促銷等目的組織的網上限時搶購活動。因爲商品價格低廉,每每一上架就被搶購一空,有時只用一秒鐘。
秒殺商品一般有兩種限制:庫存限制、時間限制。
需求:
(1)商家提交秒殺商品申請,錄入秒殺商品數據,主要包括:商品標題、原價、秒殺價、商品圖片、介紹等信息
(2)運營商審覈秒殺申請
(3)秒殺頻道首頁列出秒殺商品(進行中的)點擊秒殺商品圖片跳轉到秒殺商品詳細頁。
(4)商品詳細頁顯示秒殺商品信息,點擊當即搶購實現秒殺下單,下單時扣減庫存。當庫存爲0或不在活動期範圍內時沒法秒殺。
(5)秒殺下單成功,直接跳轉到支付頁面(微信掃碼),支付成功,跳轉到成功頁,填寫收貨地址、電話、收件人等信息,完成訂單。
(6)當用戶秒殺下單5分鐘內未支付,取消預訂單,調用微信支付的關閉訂單接口,恢復庫存。
數據庫表分析
Tb_seckill_goods 秒殺商品表
Tb_seckill_order 秒殺訂單表
秒殺實現思路
秒殺技術實現核心思想是運用緩存減小數據庫瞬間的訪問壓力!讀取商品詳細信息時運用緩存,當用戶點擊搶購時減小redis中的庫存數量,當庫存數爲0時或活動期結束時,同步到數據庫。 產生的秒殺預訂單也不會馬上寫到數據庫中,而是先寫到緩存,當用戶付款成功後再寫入數據庫。
大家這個項目用的什麼數據庫,數據庫有多少張表?
項目使用mysql數據庫,總共有103張表,其中商品表共計有8張。
項目部署作過嗎,能不能部署?
作過,能夠部署。
項目服務器:集羣部署
數據庫服務器:集羣部署
Nginx集羣:負載均衡
單點登陸怎麼作的,用別人知道原理嗎?
在分佈式項目中實現session共享,完成分佈式系統單點登陸
3) Cookie中共享ticket
4) Redis存儲session
分佈式系統共享用戶身份信息session,必須先獲取ticket票據,而後再根據票據信息獲取redis中用戶身份信息。
實現以上2點便可實現session共享。
目前項目中使用的springsecurity + cas 來實現的單點登陸,cas自動產生ticket票據信息,每次獲取用戶信息,cas將會攜帶ticket信息獲取用戶身份信息。
支付作了嗎,支付寶仍是微信,實現說下?
微信支付
微信支付:
1) 調用微信支付下單接口
2) 返回支付地址,生成二維碼
3) 掃描二維碼便可完成支付
問題: 微信支付二維碼是咱們本身生成的,所以必須時刻監控微信支付二維碼的狀態,確保支付成功。
支付寶支付能夠參考www.alipay.com
緩存及優化方面的面試問題
怎麼提升redis緩存利用率?
一、從業務場景分析,預計會高頻率用到的數據預先存放到redis中,
二、能夠定時掃描命中率低的數據,能夠直接從redis中清除。
怎麼實現數據量大、 併發量高的搜索
建立solr索引庫,數據量特別大時採用solr分佈式集羣
MySQL索引使用限制
不要在列上進行運算。
select * from users where YEAR(adddate)<2007; 將在每一個行上進行運算,這將致使索引失效而進行全表掃描,所以咱們能夠改爲select * from users where adddate<‘2007-01-01’;
like語句操做
若是使用like。like 「%aaa%」 不會使用索引而like 「aaa%」能夠使用索引。
select * from users where name like '%aaa%'不會使用索引
select * from users where name like 'aaa%'能夠使用索引
使用短索引
例如,若是有一個CHAR(255)的列,若是在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。
索引不會包含NULL列
複合索引中若是有一列含有NULL值那麼這個組合索引都將失效,通常須要給默認值0或者 ' '字符串
最左匹配
不按索引最左列開始查詢(多列索引) 例如index(‘c1’, ‘c2’, ‘c3’) ,where ‘c2’ = ‘aaa’ 不使用索引,where ‘c2’ = ‘aaa’ and ‘c3’ = ‘sss’ 不能使用索引。where ‘c1’ = ‘aaa’ and ‘c2’ = ‘bbb’ 能夠使用索引
多列範圍查詢
查詢中某個列有範圍查詢,則其右邊的全部列都沒法使用查詢(多列查詢)。where c1= ‘xxx’ and c2 like = ‘aa%’ and c3=’sss’ 該查詢只會使用索引中的前兩列,c3將不能使用到索引,由於like是範圍查詢。
檢索排序
一個查詢語句中,既有檢索又有排序而且是不一樣的字段,且這兩個列上都有單列索引(獨立索引),那麼只有其中一個列用到索引,由於查詢優化器在作檢索和排序中不能同時使用兩個不一樣的索引
索引散列度
經過索引掃描的記錄超過了表總行數的30%(估計值),則查詢優化器認爲全表掃描的效率更高,因此會變成全表掃描查詢
隱式轉換
隱式轉換致使的索引失效。好比,表的字段tu_mdn定義爲varchar(20),但在查詢時把該字段做爲number類型當作where條件,這樣會致使索引失效. 錯誤的例子:select * from test where tu_mdn=13333333333; 正確的例子:select * from test where tu_mdn='13333333333’;
怎麼分詞
使用第三方的分詞器IKAnalyzer,會按照中國人用此習慣自動分詞。
seo怎麼優化
使用restful,或靜態頁這樣能更好的被搜索引擎收錄。
怎麼加快訪問速度
硬件上加大網絡帶寬、和服務器內存
代碼的處理:靜態頁面、緩存、優化sql、建立索引等方案
講到redis緩存的時候說不清楚
redis中項目中的應用。1.主要應用在門戶網站首頁廣告信息的緩存。由於門戶網站訪問量較大,將廣告緩存到redis中,能夠下降數據庫訪問壓力,提升查詢性能。2.應用在用戶註冊驗證碼緩存。利用redis設置過時時間,當超過指定時間後,redis清理驗證碼,使過時的驗證碼無效。3.用在購物車模塊,用戶登錄系統後,添加的購物車數據須要保存到redis緩存中。
技術角度分析:
內存若是滿了,採用LRU算法進行淘汰。
Redis如何實現負載的?採用Hash槽來運算存儲值,使用CRC16算法取模運算,來保證負載問題。
Redis緩存穿透問題?將數據查詢出來若是沒有強制設置空值,而且設置過時時間,減小頻繁查詢數據庫。
能講下redis的具體使用場景嗎?使用redis存儲長期不改變的數據徹底能夠使用也看靜態化,那麼大家當時是爲何會使用redis?
redis在項目中應用:1.主要應用在門戶網站首頁廣告信息的緩存。由於門戶網站訪問量較大,將廣告緩存到redis中,能夠下降數據庫訪問壓力,提升查詢性能。2.應用在用戶註冊驗證碼緩存。利用redis設置過時時間,當超過指定時間後,redis清理驗證碼,使過時的驗證碼無效。3.用在購物車模塊,用戶登錄系統後,添加的購物車數據須要保存到redis緩存中。
使用redis主要是減小系統數據庫訪問壓力。從緩存中查詢數據,也提升了查詢性能,挺高用戶體驗度。
redis中對一個key進行自增或者自減操做,它是原子性的嗎?
是原子性的。對於Redis而言,命令的原子性指的是:一個操做的不能夠再分,操做要麼執行,要麼不執行。Redis的操做之因此是原子性的,是由於Redis是單線程的。對Redis來講,執行get、set以及eval等API,都是一個一個的任務,這些任務都會由Redis的線程去負責執行,任務要麼執行成功,要麼執行失敗,這就是Redis的命令是原子性的緣由。Redis自己提供的全部API都是原子操做,Redis中的事務實際上是要保證批量操做的原子性。
大家項目中使用到的數據庫是什麼?你有涉及到關於數據庫到建庫建表操做嗎?數據庫建立表的時候會有哪些考慮呢?
項目中使用的是MySQL數據庫,
數據庫建立表時要考慮
a、大數據字段最好剝離出單獨的表,以便影響性能
b、使用varchar,代替char,這是由於varchar會動態分配長度,char指定爲20,即時你存儲字符「1」,它依然是20的長度
c、給表創建主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有必定的影響
d、避免表字段運行爲null,若是不知道添加什麼值,建議設置默認值,特別int類型,好比默認值爲0,在索引查詢上,效率立顯。
e、創建索引,彙集索引則意味着數據的物理存儲順序,最好在惟一的,非空的字段上創建,其它索引也不是越多越好,索引在查詢上優點顯著,在頻繁更新數據的字段上創建彙集索引,後果很嚴重,插入更新至關忙。
f、組合索引和單索引的創建,要考慮查詢實際和具體模式
mysql中哪些狀況下能夠使用索引,哪些狀況不能使用索引?mysql索引失效的情形有哪些?
使用索引:
a、 爲了快速查找匹配WHERE條件中涉及到列。
b、 若是表有一個multiple-column索引,任何一個索引的最左前綴能夠經過使用優化器來查找行
c、 當運行joins時,爲了從其餘表檢索行。MySql能夠更有效的使用索引在多列上若是他們聲明的類型和大小是同樣的話。在這個環境下,VARCHAR和CHAR是同樣的若是他們聲明的大小是同樣的
d、 爲了找到 MIN() or MAX()的值對於一個指定索引的列key_col.
總之,就是常常用到的列就最好建立索引。
不能使用引用:
a) 數據惟一性差(一個字段的取值只有幾種時)的字段不要使用索引
好比性別,只有兩種可能數據。意味着索引的二叉樹級別少,可能是平級。這樣的二叉樹查找無異於全表掃描
b) 頻繁更新的字段不要使用索引
好比logincount登陸次數,頻繁變化致使索引也頻繁變化,增大數據庫工做量,下降效率
c) 字段不在where語句出現時不要添加索引,若是where後含IS NULL /IS NOT NULL/ like ‘%輸入符%’等條件,不建議使用索引只有在where語句出現,mysql纔會去使用索引
d) where 子句裏對索引列使用不等於(<>),使用索引效果通常
索引失效:
a.若是條件中有or,即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由)
注意:要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引
b.對於多列索引,不是使用的第一部分,則不會使用索引
c.like查詢是以%開頭
d.若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引
e.若是mysql估計使用全表掃描要比使用索引快,則不使用索引
8,java中的多線程在大家的這個項目當中有哪些體現?
a,後臺任務:如定時向大量(100W以上)的用戶發送郵件;按期更新配置文件、任務調度(如quartz),一些監控用於按期信息採集
b, 自動做業處理:好比按期備份日誌、按期備份數據庫
c, 異步處理:如發微博、記錄日誌
Redis分佈式鎖理解
回答:
實現思想
獲取鎖的時候,使用setnx加鎖,並使用expire命令爲鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值爲一個隨機生成的UUID,經過此在釋放鎖的時候進行判斷。
獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
釋放鎖的時候,經過UUID判斷是否是該鎖,如果該鎖,則執行delete進行鎖釋放。
Redis怎麼設置過時的?項目過程當中,使用了哪種持久化方式
回答:
設置過時:
this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);
持久化方式:Redis默認的RDB方式
項目添加Redis緩存後,持久化具體怎麼實現的。
回答:
RDB:保存存儲文件到磁盤;同步時間爲15分鐘,5分鐘,1分鐘一次,可能存在數據丟失問題。
AOF:保存命令文件到磁盤;安全性高,修改後當即同步或每秒同步一次。
上述兩種方式在咱們的項目中都有使用到,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據後從數據庫中查詢後保存到redis中
採用默認的RDB方式,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據就從數據庫中查詢後再保存到redis中
項目中有用到過redis,訪問redis是經過什麼訪問的?redis可以存儲的數據類型有哪幾種?
Redis經過SpringDataRedis訪問的.
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
怎樣進行程序性能調優
系統性能就是兩個事:
Throughput ,吞吐量。也就是每秒鐘能夠處理的請求數,任務數。
Latency, 系統延遲。也就是系統在處理一個請求或一個任務時的延遲。
那麼Latency越好,能支持的Throughput就會越高。由於Latency短說明處理速度快,因而就能夠處理更多的請求。
提升吞吐量:
分佈式集羣,模塊解藕,設計模式
系統延遲:
異步通訊
數據庫設計的面試問題
你有了解mysql的隔離級別嗎?mysql默認的隔離級別是什麼?
數據庫事務的隔離級別有四種,隔離級別高的數據庫的可靠性高,但併發量低,而隔離級別低的數據庫可靠性低,但併發量高,系統開銷小。
READ UNCIMMITTED(未提交讀)
READ COMMITTED(提交讀)
REPEATABLE READ(可重複讀)
SERIALIZABLE(可串行化)
mysql默認的事務處理級別是'REPEATABLE-READ',也就是可重複讀。
sql語句中關於查詢語句的優化大家是怎麼作的?
一、應儘可能避免在 where 子句中使用!=或<>操做符,不然將引擎放棄使用索引而進行全表掃描。
二、對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。
三、應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描
四、儘可能避免在 where 子句中使用 or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描
五、in 和 not in 也要慎用,不然會致使全表掃描
六、應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。
七、應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描
八、不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
九、在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使 用,而且應儘量的讓字段順序與索引順序相一致。
十、索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。
十一、儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。
十二、任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
mysql索引失效的場景有哪些?like作模糊查詢的時候會失效嗎?
1.WHERE字句的查詢條件裏有不等於號(WHERE column!=…),MYSQL將沒法使用索引
2.相似地,若是WHERE字句的查詢條件裏使用了函數(如:WHERE DAY(column)=…),MYSQL將沒法使用索引
3.在JOIN操做中(須要從多個數據表提取數據時),MYSQL只有在主鍵和外鍵的數據類型相同時才能使用索引,不然即便創建了索引也不會使用
4.若是WHERE子句的查詢條件裏使用了比較操做符LIKE和REGEXP,MYSQL只有在搜索模板的第一個字符不是通配符的狀況下才能使用索引。好比說,若是查詢條件是LIKE 'abc%',MYSQL將使用索引;若是條件是LIKE '%abc',MYSQL將不使用索引。
5.在ORDER BY操做中,MYSQL只有在排序條件不是一個查詢條件表達式的狀況下才使用索引。儘管如此,在涉及多個數據表的查詢裏,即便有索引可用,那些索引在加快ORDER BY操做方面也沒什麼做用。
6.若是某個數據列裏包含着許多重複的值,就算爲它創建了索引也不會有很好的效果。好比說,若是某個數據列裏包含了淨是些諸如「0/1」或「Y/N」等值,就沒有必要爲它建立一個索引。
7.索引有用的狀況下就太多了。基本只要創建了索引,除了上面提到的索引不會使用的狀況下以外,其餘狀況只要是使用在WHERE條件裏,ORDER BY 字段,聯表字段,通常都是有效的。 創建索引要的就是有效果。 否則還用它幹嘛? 若是不能肯定在某個字段上創建的索引是否有效果,只要實際進行測試下比較下執行時間就知道。
8.若是條件中有or(而且其中有or的條件是不帶索引的),即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由)。注意:要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引
9.若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引
10.若是mysql估計使用全表掃描要比使用索引快,則不使用索引
問題二:Like模糊查詢,創建索引會失效
項目中關於表結構拆分,大家是業務層面的拆分仍是表結構層面的拆分?
表結構層面的拆分。經過mycat數據庫中間件完成數據庫分表操做。
業務層面也有拆分,好比商品模塊拆分紅8張表來實現存儲
有了解過大數據層面的分庫分表嗎?以及mysql的執行計劃嗎?
分庫
經過Mycat結點來管理不一樣服務器上的數據庫,每一個表最多存500萬條記錄
分表
重直切割,水平切割
MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個"EXPLAIN"便可。mysql中的explain語法能夠幫助咱們改寫查詢,優化表的結構和索引的設置,從而最大地提升查詢效率。
有了解過數據庫中的表級鎖和行級鎖嗎?樂觀鎖和悲觀鎖你有哪些瞭解?
MySQL的鎖機制比較簡單,其最顯著的特色是不一樣的存儲引擎支持不一樣的鎖機制。好比,MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖( row-level locking),也支持表級鎖,但默認狀況下是採用行級鎖。
MySQL主要的兩種鎖的特性可大體概括以下:
表級鎖: 開銷小,加鎖快;不會出現死鎖(由於MyISAM會一次性得到SQL所需的所有鎖);鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
行級鎖: 開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
樂觀鎖:經過version版本字段來實現
悲觀鎖:經過for update來實現
Mysql優化有沒有工具
回答:
三個MySQL性能測試工具:The MySQL Benchmark Suite、MySQL super-smack、MyBench。除了第一個爲MySQL性能測試工具,其餘兩個都爲壓力測試工具。
大家項目中使用到的數據庫是什麼?你有涉及到關於數據庫到建庫建表操做嗎?數據庫建立表的時候會有哪些考慮呢?
項目中使用的是MySQL數據庫,
數據庫建立表時要考慮
a、大數據字段最好剝離出單獨的表,以便影響性能
b、使用varchar,代替char,這是由於varchar會動態分配長度,char指定爲20,即時你存儲字符「1」,它依然是20的長度
c、給表創建主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有必定的影響
d、避免表字段運行爲null,若是不知道添加什麼值,建議設置默認值,特別int類型,好比默認值爲0,在索引查詢上,效率立顯。
e、創建索引,彙集索引則意味着數據的物理存儲順序,最好在惟一的,非空的字段上創建,其它索引也不是越多越好,索引在查詢上優點顯著,在頻繁更新數據的字段上創建彙集索引,後果很嚴重,插入更新至關忙。
f、組合索引和單索引的創建,要考慮查詢實際和具體模式
mysql中哪些狀況下能夠使用索引,哪些狀況不能使用索引?mysql索引失效的情形有哪些?
使用索引:
a、 爲了快速查找匹配WHERE條件中涉及到列。
b、 若是表有一個multiple-column索引,任何一個索引的最左前綴能夠經過使用優化器來查找行
c、 當運行joins時,爲了從其餘表檢索行。MySql能夠更有效的使用索引在多列上若是他們聲明的類型和大小是同樣的話。在這個環境下,VARCHAR和CHAR是同樣的若是他們聲明的大小是同樣的
d、 爲了找到 MIN() or MAX()的值對於一個指定索引的列key_col.
總之,就是常常用到的列就最好建立索引。
不能使用引用:
a) 數據惟一性差(一個字段的取值只有幾種時)的字段不要使用索引
好比性別,只有兩種可能數據。意味着索引的二叉樹級別少,可能是平級。這樣的二叉樹查找無異於全表掃描
b) 頻繁更新的字段不要使用索引
好比logincount登陸次數,頻繁變化致使索引也頻繁變化,增大數據庫工做量,下降效率
c) 字段不在where語句出現時不要添加索引,若是where後含IS NULL /IS NOT NULL/ like ‘%輸入符%’等條件,不建議使用索引只有在where語句出現,mysql纔會去使用索引
d) where 子句裏對索引列使用不等於(<>),使用索引效果通常
索引失效:
a.若是條件中有or,即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由)
注意:要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引
b.對於多列索引,不是使用的第一部分,則不會使用索引
c.like查詢是以%開頭
d.若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引
e.若是mysql估計使用全表掃描要比使用索引快,則不使用索引
8,java中的多線程在大家的這個項目當中有哪些體現?
a,後臺任務:如定時向大量(100W以上)的用戶發送郵件;按期更新配置文件、任務調度(如quartz),一些監控用於按期信息採集
b, 自動做業處理:好比按期備份日誌、按期備份數據庫
c, 異步處理:如發微博、記錄日誌
怎樣進行數據庫優化?
a,選取最適用的字段
在建立表的時候,爲了得到更好的性能,咱們能夠將表中字段的寬度設得儘量小。另一個提升效率的方法是在可能的狀況下,應該儘可能把字段設置爲NOTNULL,
b,使用鏈接(JOIN)來代替子查詢(Sub-Queries)
c,使用聯合(UNION)來代替手動建立的臨時表
d,事物:
a)要麼語句塊中每條語句都操做成功,要麼都失敗。換句話說,就是能夠保持數據庫中數據的一致性和完整性。事物以BEGIN關鍵字開始,COMMIT關鍵字結束。在這之間的一條SQL操做失敗,那麼,ROLLBACK命令就能夠把數據庫恢復到BEGIN開始以前的狀態。
b) 是當多個用戶同時使用相同的數據源時,它能夠利用鎖定數據庫的方法來爲用戶提供一種安全的訪問方式,這樣能夠保證用戶的操做不被其它的用戶所幹擾。
e,鎖定表
f,使用外鍵
鎖定表的方法能夠維護數據的完整性,可是它卻不能保證數據的關聯性。這個時候咱們就能夠使用外鍵。
g,使用索引
h,優化的查詢語句
怎樣進行數據庫性能調優
一應用程序優化
(1)把數據庫看成奢侈的資源看待,在確保功能的同時,儘量少地動用數據庫資源。
(2)不要直接執行完整的SQL 語法,儘可能經過存儲過程實現數據庫操做。
(3)客戶與服務器鏈接時,創建鏈接池,讓鏈接儘可能得以重用,以免時間與資源的損耗。
(4)非到不得已,不要使用遊標結構,確實使用時,注意各類遊標的特性。
二基本表設計優化
(1)表設計遵循第三範式。在基於表驅動的信息管理系統中,基本表的設計規範是第三範式。
(2)分割表。分割表可分爲水平分割表和垂直分割表兩種:水平分割是按照行將一個表分割爲多個表。
(3)引入中間表。
三 數據庫索引優化
索引是創建在表上的一種數據組織,它能提升訪問表中一條或多條記錄的特定查詢效率。
彙集索引
一種索引,該索引中鍵值的邏輯順序決定了表中相應行的物理順序。
彙集索引肯定表中數據的物理順序。
非彙集索引
一種索引,該索引中索引的邏輯順序與磁盤上行的物理存儲順序不一樣.
分佈式開發面試問題
分佈式架構session共享問題,如何在集羣裏邊實現共享。
用了CAS,全部應用項目中若是須要登陸時在web.xml中配置過濾器作請求轉發到cas端工做原理是在cas登陸後會給瀏覽器發送一個票據(ticket),瀏覽器cookie中會緩存這個ticket,在登陸其餘項目時會拿着瀏覽器的ticket轉發到cas,到cas後根據票據判斷是否登陸
項目中如何配置集羣?
配置了redis集羣,使用redis3.0版本官方推薦的配置方式
solr集羣使用了solrCloud,使用zookeeper關聯solrCloud的配置文件
zookeeper也配置了集羣
應用層使用Nginx負載均衡
對分佈式,dubbo,zookeeper說的不太清楚
分佈式是從項目業務角度考慮劃分項目整個架構。能夠將項目基於功能模塊劃分再分別部署。Dubbo是實現分佈式項目部署框架。在zookeeper是dubbo分佈式框架的註冊中心,管理服務的註冊和調用。
從前端到後臺的實現的過程描述的也不清楚
項目前端採用angularjs框架在controller控制器中完成數據組裝和數據展現,在服務層(service)代碼完成中後臺請求操做。後端基於前端的接口調用,完成數據的增刪改查操做。先後端數據交互經過json格式字符串完成。
Dubbo爲何選擇Zookeeper,而不選擇Redis
回答:
引入了ZooKeeper做爲存儲媒介,也就把ZooKeeper的特性引進來。
首先是負載均衡,單註冊中心的承載能力是有限的,在流量達到必定程度的時候就須要分流,負載均衡就是爲了分流而存在的,一個ZooKeeper羣配合相應的Web應用就能夠很容易達到負載均衡;
資源同步,單單有負載均衡還不夠,節點之間的數據和資源須要同步,ZooKeeper集羣就自然具有有這樣的功能;
命名服務,將樹狀結構用於維護全局的服務地址列表,服務提供者在啓動 的時候,向ZK上的指定節點/dubbo/${serviceName}/providers目錄下寫入本身的URL地址,這個操做就完成了服務的發佈。 其餘特性還有Mast選舉,分佈式鎖等。
項目中Zookeeper服務器掛了,服務調用能夠進行嗎
回答:
能夠的,消費者在啓動時,消費者會從zk拉取註冊的生產者的地址接口等數據,緩存在本地。
每次調用時,按照本地存儲的地址進行調用
ActiveMq消息被重複消費,丟失,或者不消費怎麼辦
回答:
重複消費:Queue支持存在多個消費者,可是對一個消息而言,只會有一個消費者能夠消費。
丟消息:用持久化消息,或者非持久化消息及時處理不要堆積,或者啓動事務,啓動事務後,commit()方法會負責任的等待服務器的返回,也就不會關閉鏈接致使消息丟失了。
不消費:去ActiveMQ.DLQ裏找找
怎樣解決activeMQ的消息持久化問題?
A:持久化爲文件
這個你裝ActiveMQ時默認就是這種,只要你設置消息爲持久化就能夠了。涉及到的配置和代碼有
<persistenceAdapter>
<kahaDB directory="${activemq.base}/data/kahadb"/>
</persistenceAdapter>
producer.Send(request, MsgDeliveryMode.Persistent, level, TimeSpan.MinValue);
B:持久化爲MySql
加載驅動jar,爲數據中建立三個數據庫表,存儲activemq的消息信息
若是activeMQ的消息沒有發送成功,怎樣確保再次發送成功。
從新傳遞消息的狀況
ActiveMQ在接收消息的Client有如下幾種操做的時候,須要從新傳遞消息:
1:Client用了transactions(事務),且在session中調用了rollback()
2:Client用了transactions,且在調用commit()以前關閉
3:Client在CLIENT_ACKNOWLEDGE的傳遞模式下,在session中調用了recover()
確保客戶端有幾種狀態,檢測狀態,只要提交了那就說明客戶端成功!
Zookeeper怎樣進行服務治理。
接受提供者的接口信息和提供者ip地址進行存儲,而後管理消費者和提供者之間調用關係!
若是activeMQ的服務掛了,怎麼辦?
一、在一般的狀況下,非持久化消息是存儲在內存中的,持久化消息是存儲在文件中的,它們的最大限制在配置文件的<systemUsage>節點中配置。可是,在非持久化消息堆積到必定程度,內存告急的時候,ActiveMQ會將內存中的非持久化消息寫入臨時文件中,以騰出內存。雖然都保存到了文件裏,但它和持久化消息的區別是,重啓後持久化消息會從文件中恢復,非持久化的臨時文件會直接刪除。
二、考慮高可用,實現activemq集羣。
若是zookeeper服務掛了怎麼辦?
註冊中心對等集羣,任意一臺宕掉後,會自動切換到另外一臺
註冊中心所有宕掉,服務提供者和消費者仍能夠經過本地緩存通信
服務提供者無狀態,任一臺宕機後,不影響使用
服務提供者所有宕機,服務消費者會沒法使用,並沒有限次重連等待服務者恢復
Dubbo有3次重試,假如新消息被重複消費怎麼處理
回答:
一、去掉超時重試機制
二、服務端增長冪等校驗,服務器加入校驗機制,若是這個消息已被 消費就再也不重複消費
mq消費者接收不到消息怎麼辦。
Mq消費者接受不到消息存在2中狀況:
1. 處理失敗 指的是MessageListener的onMessage方法裏拋出RuntimeException。
2. Message頭裏有兩個相關字段:Redelivered默認爲false,redeliveryCounter默認爲0。
3. 消息先由broker發送給consumer,consumer調用listener,若是處理失敗,本地redeliveryCounter++,給broker一個特定應答,broker端的message裏redeliveryCounter++,延遲一點時間繼續調用,默認1s。超過6次,則給broker另外一個特定應答,broker就直接發送消息到DLQ。
4. 若是失敗2次,consumer重啓,則broker再推過來的消息裏,redeliveryCounter=2,本地只能再重試4次即會進入DLQ。
5. 重試的特定應答發送到broker,broker即會在內存將消息的redelivered設置爲true,redeliveryCounter++,可是這兩個字段都沒有持久化,即沒有修改存儲中的消息記錄。因此broker重啓時這兩個字段會被重置爲默認值。
系統的高併發問題是怎麼解決的。
併發問題高,這個問題的解決方案是一個系統性的,系統的每一層面都須要作優化:
1) 數據層
a) 集羣
b) 分表分庫
c) 開啓索引
d) 開啓緩存
e) 表設計優化
f) Sql語句優化
g) 緩存服務器(提升查詢效率,減輕數據庫壓力)
h) 搜索服務器(提升查詢效率,減輕數據庫壓力)
2) 項目層
a) 採用面向服務分佈式架構(分擔服務器壓力,提升併發能力)
b) 採用併發訪問較高的詳情繫統採用靜態頁面
c) 使用頁面緩存
d) 用ActiveMQ使得業務進一步進行解耦,提升業務處理能力
e) 使用分佈式文件系統存儲海量文件
3) 應用層
a) Nginx服務器來作負載均衡
b) Lvs作二層負載
併發數多少,項目中怎麼解決併發問題?
面試中項目的併發數不宜說的過大,安裝目前穀粒商城項目拆分規模,這個項目的併發是在10000+,可是學生面試不能說的這麼高。
能夠有如下2方面的回答:
1) 項目併發並不清楚(只是底層程序員)
2) 參與核心業務設計,知道併發是多少(測試峯值,上線併發)
3000---5000吧
面對項目高併發,項目必須作各類優化措施了:
4) 數據層
a) 集羣
b) 分表分庫
c) 開啓索引
d) 開啓緩存
e) 表設計優化
f) Sql語句優化
g) 緩存服務器(提升查詢效率,減輕數據庫壓力)
h) 搜索服務器(提升查詢效率,減輕數據庫壓力)
5) 項目層
a) 採用面向服務分佈式架構(分擔服務器壓力,提升併發能力)
b) 採用併發訪問較高的詳情繫統採用靜態頁面
c) 使用頁面緩存
d) 用ActiveMQ使得業務進一步進行解耦,提升業務處理能力
e) 使用分佈式文件系統存儲海量文件
6) 應用層
a) Nginx服務器來作負載均衡
b) Lvs作二層負載
消息發送失敗怎麼處理,發送數據,數據庫已經保存了數據,可是redis中沒有同步,怎麼辦。或者說如何作到消息同步。
消息發送失敗,能夠進行消息的從新發送,能夠配置消息的重發次數。
若是消息重發完畢後,消息尚未接受成功,重啓服務。
Dubbo的通訊原理?
Dubbo底層使用hessain2進行二進制序列化進行遠程調用
Dubbo底層使用netty框架進行異步通訊。NIO
其餘技術面試問題
單點登陸的訪問或者跨域問題
首先要理解什麼是單點登陸。單點登陸是相互信任的系統模塊登陸一個模塊後,其餘模塊不須要重複登陸即認證經過。項目採用的是CAS單點登陸框架完成的。首先CAS有兩大部分。客戶端和服務端。服務端就是一個web工程部署在tomcat中。在服務端完成用戶認證操做。每次訪問系統模塊時,須要去CAS完成獲取ticket。當驗證經過後,訪問繼續操做。對於CAS服務端來講,咱們訪問的應用模塊就是CAS客戶端。
跨域問題,首先明白什麼是跨域。何時涉及跨域問題。當涉及前端異步請求的時候才涉及跨域。那什麼是跨域呢?當異步請求時,訪問的請求地址的協議、ip地址、端口號任意一個與當前站點不一樣時,就會涉及跨域訪問。解決方案:一、jQuery提供了jsonp實現二、W3C標準提供了CORS(跨域資源共享)解決方案。
shiro安全認證時如何作的
要明白shiro執行流程以及shiro的核心組件,可參考下圖
認證過程:
在application Code應用程序中調用subject的login方法。將頁面收集的用戶名和密碼傳給安全管理器securityManager,將用戶名傳給realm對象。Realm對象能夠理解爲是安全數據橋,realm中認證方法基於用戶名從數據庫中查詢用戶信息。若是用戶存在,將數據庫查詢密碼返回給安全管理器securityManager,而後安全管理器判斷密碼是否正確。
ES的用途
ES在系統中主要完成商品搜索功能,提升搜索性能。
分佈式鎖的問題
針對分佈式鎖的實現,目前比較經常使用的有如下幾種方案:
1.基於數據庫實現分佈式鎖
2.基於緩存(redis,memcached,tair)實現分佈式鎖
3.基於zookeeper實現分佈式鎖
ES索引中使用了IK分詞器,大家項目中使用到了分詞器的哪一種工做模式?
IK分詞器,基本可分爲兩種模式,一種爲smart模式,一種爲非smart模式。
例如:張三說的確實在理
smart模式的下分詞結果爲:
張三 | 說的 | 確實 | 在理
而非smart模式下的分詞結果爲:
張三 | 三 | 說的 | 的確 | 的 | 確實 | 實在 | 在理
可見非smart模式所作的就是將可以分出來的詞所有輸出;smart模式下,IK分詞器則會根據內在方法輸出一個認爲最合理的分詞結果,這就涉及到了歧義判斷。
項目中採用的是smart模塊分詞的。
java中關於多線程的瞭解你有多少?線程池有涉及嗎?
同一類線程共享代碼和數據空間,每一個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。線程分爲五個階段:建立、就緒、運行、阻塞、終止。
Java線程有五種基本狀態
新建狀態(New):當線程對象對建立後,即進入了新建狀態,如:Thread t = new MyThread();
就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經作好了準備,隨時等待CPU調度執行,並非說執行了t.start()此線程當即就會執行;
運行狀態(Running):當CPU開始調度處於就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就 緒狀態是進入到運行狀態的惟一入口,也就是說,線程要想進入運行狀態執行,首先必須處於就緒狀態中;
阻塞狀態(Blocked):處於運行狀態中的線程因爲某種緣由,暫時放棄對CPU的使用權,中止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的緣由不一樣,阻塞狀態又能夠分爲三種:
1.等待阻塞:運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態;
2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(由於鎖被其它線程所佔用),它會進入同步阻塞狀態;
3.其餘阻塞 -- 經過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。
死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
Java中線程的建立常見有如三種基本形式
1.繼承Thread類,重寫該類的run()方法。
2.實現Runnable接口,並重寫該接口的run()方法,
該run()方法一樣是線程執行體,建立Runnable實現類的實例,並以此實例做爲Thread類的target來建立Thread對象,該Thread對象纔是真正的線程對象。
3.使用Callable和Future接口建立線程。
具體是建立Callable接口的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象做爲Thread對象的target來建立線程。
線程池:線程池是一種多線程處理形式,處理過程當中將任務添加到隊列,而後在建立線程後自動啓動這些任務。線程池線程都是後臺線程。每一個線程都使用默認的堆棧大小,以默認的優先級運行,並處於多線程單元中。若是某個線程在託管代碼中空閒(如正在等待某個事件),則線程池將插入另外一個輔助線程來使全部處理器保持繁忙。若是全部線程池線程都始終保持繁忙,但隊列中包含掛起的工做,則線程池將在一段時間後建立另外一個輔助線程但線程的數目永遠不會超過最大值。超過最大值的線程能夠排隊,但他們要等到其餘線程完成後才啓動。
如何實現線程的同步?
爲什麼要使用同步?
java容許多線程併發控制,當多個線程同時操做一個可共享的資源變量時(如數據的增刪改查),將會致使數據不許確,相互之間產生衝突,所以加入同步鎖以免在該線程沒有完成操做以前,被其餘線程的調用,從而保證了該變量的惟一性和準確性。
線程同步(5種同步方式)
1.同步方法 2.同步代碼塊 3.使用特殊域變量(volatile)實現線程同步 4.使用重入鎖實現線程同步 5.使用局部變量實現線程同步
遍歷hashmap有幾種方式?
Map的四種遍歷方式
(1) for each map.entrySet()
(2) 顯示調用map.entrySet()的集合迭代器
(3) for each map.keySet(),再調用get獲取
(4) for each map.entrySet(),用臨時變量保存map.entrySet()
簡單介紹一下Es全文檢索在整個系統中的應用,在更新索引庫的同時會產生索引碎片,這個碎片是如何處理的?
根據商品的名稱,分類,品牌等屬性來建立索引進行商品搜索。
更新索引庫時會先刪除索引,而後再重建。而對於刪除彙集索引,則會致使對應的非彙集索引重建兩次(刪除時重建,創建時再重建).
直接刪除碎片。
java併發包下有哪些併發組件?
分爲兩層組成
外層框架主要有Lock(ReentrantLock、ReadWriteLock等)、同步器(semaphores等)、阻塞隊列(BlockingQueue等)、Executor(線程池)、併發容器(ConcurrentHashMap等)、還有Fork/Join框架;
內層有AQS(AbstractQueuedSynchronizer類,鎖功能都由他實現)、非阻塞數據結構、原子變量類(AtomicInteger等無鎖線程安全類)三種。
講一下jvm調優。
a,堆大小設置
b,回收器選擇
c,輔助信息
JVM提供了大量命令行參數,打印信息,供調試使用;
講一下jvm的組成。
JVM 由類加載器子系統、運行時數據區、執行引擎以及本地方法接口組成
講一下ThreadLocal類。
ThreadLocal,不少地方叫作線程本地變量,也有些地方叫作線程本地存儲,其實意思差很少。可能不少朋友都知道ThreadLocal爲變量在每一個線程中都建立了一個副本,那麼每一個線程能夠訪問本身內部的副本變量;
ThreadLocal在每一個線程中對該變量會建立一個副本,即每一個線程內部都會有一個該變量,且在線程內部任何地方均可以使用,線程之間互不影響,這樣一來就不存在線程安全問題,也不會嚴重影響程序執行性能。
可是要注意,雖然ThreadLocal可以解決上面說的問題,可是因爲在每一個線程中都建立了副本,因此要考慮它對資源的消耗,好比內存的佔用會比不使用ThreadLocal要大;
怎麼確保session共享?
在分佈式項目中實現session共享必須作如下準備工做:
1) Cookie中共享ticket
2) Redis存儲session
分佈式系統共享用戶身份信息session,必須先獲取ticket票據,而後再根據票據信息獲取redis中用戶身份信息。
實現以上2點便可實現session共享。
目前項目中使用的springsecurity + cas 來實現的單點登陸,cas自動產生ticket票據信息,每次獲取用戶信息,cas將會攜帶ticket信息獲取用戶身份信息。
項目中哪塊涉及了線程問題,怎麼處理的?
項目的高併發訪問就是一個多線程問題。
項目中普通的業務開發基本沒有涉及多線程問題,不過你能夠談談你使用的框架中使用的多線程技術:
由於咱們項目使用的框架進行開發的,所以多線程處理多讓框架非咱們處理結束了。
1) 高併發就是多線程,這裏的多線程讓servlet服務器給處理了談談Tomcat多線程配置;
a) 配置線程池,擴大併發能力
b) 開啓NIO能力等等
2) 框架多線程:mybatis 框架底層使用的鏈接池
項目問題
哪些狀況用到activeMq?
商品上架後更新ES索引庫、更新靜態頁、發送短信
提交訂單後清除購物車中的數據
支付未完成時支付完成後修改訂單狀態
秒殺的時候,只有最後一件物品,該怎麼去搶或者分配?
秒殺商品的庫存都會放到redis緩存中,在客戶下單時就減庫存,咱們設置庫存庫存閘值,用於某些商品數量非單件不可分割,減完庫存會判斷庫存是否爲大於庫存閘值,若是小於,表示庫存不足,剛纔減去的數量再恢復,整個過程使用redis的watch鎖 。
你項目對於訂單是怎麼處理的,假如一個客戶在下訂單的時候沒有購買怎麼辦?
訂單表中設置了一個過時時間,天天會有定時任務來掃描訂單表數據,若是到達預訂的過時時間沒有付款就會取消此訂單交易。
對於顧客在購買商品的時候大家怎麼處理大家的庫存?
普通商品只有在發貨時纔去更新庫存,若是庫存不足商家會立刻補貨
秒殺的商品會在客戶下單時就減庫存,若是在規定時間(半個小時)沒有付款,會取消此訂單把庫存還原。
秒殺系統中如何防止超售?如何避免腳本進行惡意刷單?
防止超售解決方案:將存庫從MySQL前移到Redis中,全部的寫操做放到內存中,因爲Redis中不存在鎖故不會出現互相等待,而且因爲Redis的寫性能和讀性能都遠高於MySQL,這就解決了高併發下的性能問題。而後經過隊列等異步手段,將變化的數據異步寫入到DB中。當達到庫存閥值的時候就不在消費隊列,並關閉購買功能。避免腳本惡意刷單:採用IP級別的限流,即針對某一個IP,限制單位時間內發起請求數量。
單點登陸大家是本身編寫的仍是使用通用的CAS?
項目使用通用的CAS框架。
什麼是CAS?
中央認證服務,企業級單點登陸解決方案。CAS Server 須要獨立部署,主要負責對用戶的認證工做;CAS Client 負責處理對客戶端受保護資源的訪問請求,須要登陸時,重定向到 CAS Server。
若是一個用戶的token被其餘用戶劫持了,怎樣解決這個安全問題。
a、在存儲的時候把token進行對稱加密存儲,用時解開。
b、將請求URL、時間戳、token三者進行合併加鹽簽名,服務端校驗有效性。
c.HTTPS對URL進行加密
對系統運行形成很大壓力,隨着項目上線時間增加,壓力會愈來愈大,咱們怎麼減輕系統訪問壓力
流量分爲三種,一種是商家流量,另外一種是用戶流量,第三種運營商流量。
解決方案:
這三種流量對系統運行形成很大壓力,隨着項目上線時間增加,壓力會愈來愈大,所以咱們要減輕系統訪問壓力 ,就須要作一系列優化措施。
具體優化以下:
數據層面的優化:
從數據庫層面作優化,好比:索引,緩存集羣雙緩存,把查詢獨立出來讀寫分離,配置數據庫集羣主從複製,使用Mycat分表,分庫。
從數據庫設計層面的優化:好比減小表關聯,加入冗餘字段
從緩存方面優化:好比redis實現數據緩存,減輕數據庫壓力
從搜索上進行優化:好比查找索引庫,使用es或solr全文搜索
項目層面的優化:
採用面向服務的分佈式架構:分擔服務器壓力 ,提升項目併發量。好比dubbox+zookeeper的SOA分佈式架構
採用分佈式文件系統實現海量文件存儲:如採用fastdfs實現海量圖片存儲,提升文件的訪問速度。
採用mq使用服務進一步解藕:同步索引庫,同步靜態資源,短信發送
服務器層面的優化
集羣思想的使用:tomcat,zookeeper,redis,mysql等
Tomcat異步通訊的使用,tomcat鏈接池配置
秒殺和團購業務實現思路
將商品數量查詢出存入到redis中,全部用戶下單後,減掉redis中的數量
若是併發量很大時,還要考慮高併發問題,因此能夠加入mq消息中間件處理搶單問題,再結合redis實現庫存減小操做。高併發方面還能夠考慮CDN,Nginx負載均衡等
大家項目中使用的安全框架是什麼?
第一種:使用springSecurity
第二種:使用shiro(配置一下再用一下標籤就好了),校驗用戶登陸和用戶權限!
項目中使用到的應用服務器是什麼?
Tomcat+nginx
項目中遇到什麼問題?
ES高亮不能顯示的問題
前臺使用angularJS加載搜索結果,可是發現高亮不能展現。
問題緣由:angularJS底層使用ajax,異步加載高亮信息返回給頁面後,頁面沒有刷新,就直接顯示返回的數據。此時會把全部的數據做爲普通的文本數據進行加載。所以就沒有高亮的效果。
解決方案:使用angularJS過濾器過濾文本數據,此時angularJS過濾器把html文本數據解析爲瀏覽器能識別的html標籤。高亮就能展現了。
activeMQ存在運行時間長了之後,收不到消息的現象。時間長了就會出現,卡死,新的數據不能從隊列接聽到。只能重啓程序。
解決方案:
1)不要頻繁的創建和關閉鏈接:JMS使用長鏈接方式,一個程序,只要和JMS服務器保持一個鏈接就能夠了,不要頻繁的創建和關閉鏈接。頻繁的創建和關閉鏈接,對程序的性能影響仍是很大的。這一點和jdbc仍是不太同樣的。
2)Connection的start()和stop()方法代價很高:JMS的Connection的start()和stop()方法代價很高,不能常常調用。咱們試用的時候,寫了個jms的connection pool,每次將connection取出pool時調用start()方法,歸還時調用stop()方法,然然後來用jprofiler發現,通常的cpu時間都耗在了這兩個方法上。
3)start()後才能收消息:Connection的start()方法調用後,才能收到jms消息。若是不調用這個方法,能發出消息,可是一直收不到消息。不知道其它的jms服務器也是這樣。
4)顯式關閉Session:若是忘記了最後關閉Connection或Session對象,都會致使內存泄漏。這個在我測試的時候也發現了。原本覺得關閉了Connection,由這個Connection生成的Session也會被自動關閉,結果並不是如此,Session並無關閉,致使內存泄漏。因此必定要顯式的關閉Connection和Session。
5)對Session作對象池:對Session作對象池,而不是Connection。Session也是昂貴的對象,每次使用都新建和關閉,代價也很是高。並且後來咱們發現,原來Connection是線程安全的,而Session不是,因此後來改爲了對Session作對象池,而只保留一個Connection。
6) 集羣:ActiveMQ有強大而靈活的集羣功能,可是使用起來仍是會有不少陷阱
activeMQ存在發出消息太大,形成消息接受不成功。多個線程從activeMQ中取消息,隨着業務的擴大,該機器佔用的網絡帶寬愈來愈高。
仔細分析發現,mq入隊時並無異常高的網絡流量,僅僅在出隊時會產生很高的網絡流量。
最終發現是spring的jmsTemplate與activemq的prefetch機制配合致使的問題。
研究源碼發現jmsTemplate實現機制是:每次調用receive()時都會建立一個新的consumer對象,用完即銷燬。
正常狀況下僅僅會浪費重複建立consumer的資源代價,並不至於產生正常狀況十倍百倍的網絡流量。
可是activeMQ有一個提升性能的機制prefetch,此時就會有嚴重的問題。
prefetch機制:
每次consumer鏈接至MQ時,MQ預先存放許多message到消費者(前提是MQ中存在大量消息),預先存 放message的數量取決於prefetchSize(默認爲1000)。此機制的目的很顯然,是想讓客戶端代碼用一個consumer反覆進行 receive操做,這樣可以大量提升出隊性能。
此機制與jmsTemplate配合時就會產生嚴重的問題,每次jmsTemplate.receive(),都會產生1000個消息的網絡流量, 可是由於jmsTemplae並不會重用consumer,致使後面999個消息都被廢棄。反覆jmsTemplate.receive()時,表面上看 不出任何問題,其實網絡帶寬會形成大量的浪費。
解決方案:
一、若堅持使用jmsTemplate,須要設置prefetch值爲1,至關於禁用了activeMQ的prefetch機制,此時感受最健壯, 就算多線程,反覆調用jmsTemplate.receive()也不會有任何問題。可是會有資源浪費,由於要反覆建立consumer並頻繁與服務器進 行數據通訊,但在性能要求不高的應用中也不算什麼問題。
二、不使用jmsTemplate,手工建立一個consumer,並單線程反覆使用它來receive(),此時能夠充分利用prefetch機制。配合多線程的方式每一個線程擁有本身的一個consumer,此時可以充分發揮MQ在大吞吐量時的速度優點。
切記避免多線程使用一個consumer形成的消息混亂。大吞吐量的應用推薦使用方案2,可以充分利用prefetch機制提升系MQ的吞吐性能。
商品的價格變化後,如何同步redis中數以百萬計的購物車數據。
解決方案:購物車只存儲商品id,到購物車結算頁面將會重新查詢購物車數據,所以就不會涉及購物車商品價格同步的問題。
系統中的錢是如何保證安全的。
在當前互聯網系統中錢的安全是頭等大事,如何保證錢的安全能夠從如下2個方面來思考:
1)錢計算方面
在系統中必須是浮點數計算類型存儲錢的額度,不然計算機在計算時可能會損失精度。
2)事務處理方面
在當前環境下,高併發訪問,多線程,多核心處理下,很容易出現數據一致性問題,此時必須使用事務進行控制,訪問交易出現安全性的問題,那麼在分佈式系統中,存在分佈式事務問題,能夠有不少解決方案:
使用 jpa能夠解決
使用 tcc 框架能夠解決等等。
訂單中的事物是如何保證一致性的。
使用分佈式事務來進行控制,保證數據最終結果的一致性。
講講angularJS四大特徵?
MVC 模式
Model:數據,其實就是angular變量($scope.XX);
View: 數據的呈現,Html+Directive(指令);
Controller:操做數據,就是function,數據的增刪改查;
雙向綁定
首先咱們要理解數據綁定。咱們看到的網站頁面中,是由數據和設計兩部分組合而成。將設計轉換成瀏覽器能理解的語言,即是html和css主要作的工做。而將數據顯示在頁面上,而且有必定的交互效果(好比點擊等用戶操做及對應的頁面反應)則是js主要完成的工做。不少時候咱們不可能每次更新數據便刷新頁面(get請求),而是經過向後端請求相關數據,並經過無刷新加載的方式進行更新頁面(post請求)。那麼數據進行更新後,頁面上相應的位置也能自動作出對應的修改,即是數據綁定。
在之前的開發模式中,這一步通常經過jq操做DOM結構,從而進行更新頁面。但這樣帶來的是大量的代碼和大量的操做。若是能在開始的時候,便已經肯定好從後端獲取的數據到頁面上須要進行的操做,當數據發生改變,頁面的相關內容也自動發生變化,這樣便能極大地方便前端工程師的開發。在新的框架中(angualr,react,vue等),經過對數據的監視,發現變化便根據已經寫好的規則進行修改頁面,便實現了數據綁定。能夠看出,數據綁定是M(model,數據)經過VM(model-view,數據與頁面之間的變換規則)向V(view)的一個修改。
而雙向綁定則是增長了一條反向的路。在用戶操做頁面(好比在Input中輸入值)的時候,數據能及時發生變化,而且根據數據的變化,頁面的另外一處也作出對應的修改。有一個常見的例子就是淘寶中的購物車,在商品數量發生變化的時候,商品價格也能及時變化。這樣便實現了V——M——VM——V的一個雙向綁定。
這裏是區別於Jquery的,jq操做的是dom對象,angularJS操做的是變量
依賴注入
對象在建立時,其依賴的對象由框架來自動建立並注入進來。控制器就是經過依賴注入的方式實現對服務的調用。
模塊化設計
高內聚低耦合法則
高內聚:每一個模塊的具體功能具體實現
低耦合:模塊之間儘量的少用關聯和依賴
1)官方提供的模塊 ng(最核心)、ngRoute(路由)、ngAnimate(動畫)
2)用戶自定義的模塊 angular.module('模塊名',[ ])
當商品庫存數量不足時,如何保證不會超賣。
場景一: 若是系統併發要求不是很高
那麼此時庫存就能夠存儲在數據庫中,數據庫中加鎖串行化減庫存,控制庫存的超賣現象。
場景二:系統的併發量很大
若是系統併發量很大,那麼就不能再使用數據庫來進行減庫存操做了,由於數據庫加鎖操做自己是以損失數據庫的性能來進行控制數據庫數據的一致性的。可是當併發量很大的時候,將會致使數據庫排隊,發生阻塞。
所以必須使用一個高效的nosql數據庫服務器來進行減庫存,此時能夠使用redis服務器來存儲庫存,redis是一個內存版的數據庫,查詢效率至關的高,能夠使用watch來監控減庫存的操做,一旦發現庫存被減爲0,立馬中止售賣操做。
商城系統中有如下活動:
1) 秒殺活動
a) 後臺設置秒殺商品
b) 設置秒殺開啓時間,定時任務,開啓秒殺
c) 秒殺減庫存(秒殺時間結束,庫存賣完,活動結束)
2) 促銷活動
3) 團購活動
4) 今日推薦
涉及到積分積累和兌換商品等業務是怎麼設計的
積分累計有2大塊:
積分累計:
根據用戶購買的商品的價格不一樣,購買必定價格的商品,獲取必定的積分。
積分商城:
積分商城是用戶能夠使用積分商品換取商品的區域。
項目的亮點是:
1) 項目採用面向服務分佈式架構(使用dubbo,zookeeper)
a) 解耦
b) 提升項目併發能力
c) 分擔服務器壓力
2) 項目中使用activeMQ對項目進一步解耦
a) 提升項目併發能力
b) 提升任務處理速度
3) 使用支付寶支付
4) 使用先後端分離
5) 使用第三方分佈式文件系統存儲海量文件
6) Nginx部署靜態頁面實現動靜分離
購物車流程:
秒殺商品流程:
(1)商家提交秒殺商品申請,錄入秒殺商品數據,主要包括:商品標題、原價、秒殺價、商品圖片、介紹等信息
(2)運營商審覈秒殺申請
(3)秒殺頻道首頁列出秒殺商品(進行中的)點擊秒殺商品圖片跳轉到秒殺商品詳細頁。將秒殺的商品放入緩存減小數據庫瞬間的訪問壓力!
(4)商品詳細頁顯示秒殺商品信息,點擊當即搶購實現秒殺下單,下單時扣減庫存。當庫存爲0或不在活動期範圍內時沒法秒殺。讀取商品詳細信息時運用緩存,當用戶點擊搶購時減小redis中的庫存數量,當庫存數爲0時或活動期結束時,同步到數據庫。
(5)秒殺下單成功,直接跳轉到支付頁面(微信掃碼),支付成功,跳轉到成功頁,填寫收貨地址、電話、收件人等信息,完成訂單。
(6)當用戶秒殺下單5分鐘內未支付,取消預訂單,調用微信支付的關閉訂單接口,恢復庫存。產生的秒殺預訂單也不會馬上寫到數據庫中,而是先寫到緩存,當用戶付款成功後再寫入數據庫。
單點登陸怎麼作的,知道原理嗎?
在分佈式項目中實現session共享,完成分佈式系統單點登陸
Cookie中共享ticket
Redis存儲session
分佈式系統共享用戶身份信息session,必須先獲取ticket票據,而後再根據票據信息獲取redis中用戶身份信息。
實現以上2點便可實現session共享。目前項目中使用的Shiro+ cas 來實現的單點登陸,cas自動產生ticket票據信息,每次獲取用戶信息,cas將會攜帶ticket信息獲取用戶身份信息。
介紹一下本身的項目?
我最近的一個項目是一個電商項目,我主要負責的是後臺管理和商品詳情的模塊,而後也會參與到購物車和訂單模塊。這個項目是以SpringBoot和mybatis爲框架,應爲springBoot相對於SSM來講 配置方面,還有操做方面簡單不少。而後是採用zookeeper加dubbo分佈式架構和RPC遠程調用,由於他Dubbo實現了軟負載均衡,其特色是成本低,但也會有缺點,就是負載能力會受服務器自己影響,而後爲了解決軟負載均衡的缺點,咱們使用了Nginx進行負載均衡的輪詢算法,但Nginx主要在咱們項目仍是實現反向代理,就是能夠防止外網對內網服務器的惡性攻擊、緩存以減小服務器的壓力和訪問安全控制。基礎模塊就有後臺管理,商品詳情,訂單,支付,物流狀況,庫存服務。而後SpringBoot整合Thymeleaf模塊技術開發項目商品詳情模塊,easyUI開發後臺管理項目。至於我負責的兩個模塊呢,就是後臺管理和商品詳情,其中呢使用了sku和spu的數據表結構進行增刪改查,spu就比如咱們要買一臺Mate20,可是咱們沒有選擇它是什麼配置,那麼關於詳細的配置就是sku了,就是我要買一臺Mate20,黑色,內存是128G的。商品詳情和商品列表模塊使用Nginx實現集羣,使用Redis解決應用服務器的cpu和內存壓力,減小io的讀操做,減輕io的壓力,使用分佈式鎖防止Redis緩存擊穿。其中Redis的做用我是以爲挺大的,由於他能夠防止過多的用戶去直接訪問咱們的數據庫,固然,Redis也會在高併發的時候宕機,在使用Redis作緩存的時候,咱們使用Redis持久化功能,防止Redis宕機後數據丟失,若是Redis宕機了,用戶就會大量的去訪問數據庫,從而咱們數據庫也會崩潰吧。這個時候咱們就用了一個分佈式鎖,用戶須要得到一個鎖才能訪問咱們的數據庫,固然啦,並不僅是隻有一個鎖,而是鎖的數量是有限的,當一位用戶查完了數據以後,鎖就會釋放,給下位用戶,這也就是服務降降級。沒有得到鎖的用戶,頁面就一直刷新直到本身拿到鎖爲止。redis提供了持久化功能——RDB和AOF。通俗的講就是將內存中的數據寫入硬盤中。在實際應用中,用戶若是要查詢商品的話呢,首先回到Redis緩存裏面找的,若是找不到,就會到數據庫裏面找,而後緩存到Redis中,那麼下一次或者下一個用戶須要查找這個數據就沒必要到數據庫中查找了!而後我還參與了購物車和訂單模塊的開發。購物車模塊裏面呢,我先和您講下他的業務邏輯吧。就像你逛網頁淘寶同樣,在沒有登陸的時候,把東西放入購物車,它是不會和你的帳號裏的商品合併的,這個時候,商品就會以cookie的形式,放到你的瀏覽器裏面。這個時候若是你想購買這些商品的時候,你就要登陸,這個時候就會使用到單點登陸這一個技術。用戶跳轉到訂單頁面的時候,咱們會用攔截器去進行判斷用戶是否已經登陸。咱們是用cookie中是否有token,若是沒有token的話就跳轉到登陸頁面,而後生成token,至於token的生成呢,咱們是用本地的IP,用戶的id,保存在map中,還有一個常量,這個咱們一般會以項目名稱來命名的。至於爲何要token呢,實際上是由於cookie是不太安全的,它很容易被僞造,因此咱們就須要token,而後有了token以後,咱們用JWT這個鹽值生成最後的token。並把它保存到cookie當中。下一次支付的時候咱們也還會用到這個token,用一個加密算法再去運算驗證一下就能夠了!而後就是合併購物車了。這個的話我所知道的就是將客戶端的cookie複印一份到緩存中進行修改而後送回客戶端進行覆蓋,再接着就是數據庫的修改了。那這個若是登錄了的就直接從數據庫中取得數據跳到訂單系統了。而後訂單模塊裏面,簡單來講就是從購物車中勾選的商品遷移到訂單裏面。可是呢訂單模塊實際上是會聯繫到另外兩個模塊的,就是庫存和支付。若是你點擊了提交訂單,商品就會在購物車裏移除。而後咱們提交訂單避免他反覆的提交同一個訂單,就會經過交易碼防止訂單重複提交。咱們會吧tradecode放在緩存裏面,以用戶id爲key商品的交易爲value在Redis裏面保存這個交易碼。到最後選好收貨地址,留言以後,提交訂單了,就會用本身的tradecode和在Redis裏面經過用戶的id去獲取tradecode進行對比,若是能跳轉到支付頁面,那麼緩存中的交易碼就會刪除掉。到最後就是支付功能,這一步的話我是不太清楚其中的技術點了,只知道這個模塊調用了支付寶的接口和用了消息隊列,異步通知。
↵
Spring 特性
Spring的核心特性就是IOC和AOP,IOC(Inversion of Control),即「控制反轉」;AOP(Aspect-OrientedProgramming),即「面向切面編程」。
IOC:IOC,另一種說法叫DI(Dependency Injection),即依賴注入。它並非一種技術實現,而是一種設計思想。在任何一個有實際開發意義的程序項目中,咱們會使用不少類來描述它們特有的功能,而且經過類與類之間的相互協做來完成特定的業務邏輯。這個時候,每一個類都須要負責管理與本身有交互的類的引用和依賴,代碼將會變的異常難以維護和極度的高耦合。而IOC的出現正是用來解決這個問題,咱們經過IOC將這些相互依賴對象的建立、協調工做交給Spring容器去處理,每一個對象只須要關注其自身的業務邏輯關係就能夠了。在這樣的角度上來看,得到依賴的對象的方式,進行了反轉,變成了由spring容器控制對象如何獲取外部資源(包括其餘對象和文件資料等等)。
AOP:面向切面編程,每每被定義爲促使軟件系統實現關注點的分離的技術。系統是由許多不一樣的組件所組成的,每個組件各負責一塊特定功能。除了實現自身核心功能以外,這些組件還常常承擔着額外的職責。例如日誌、事務管理和安全這樣的核心服務常常融入到自身具備核心業務邏輯的組件中去。這些系統服務常常被稱爲橫切關注點,由於它們會跨越系統的多個組件。
JDBC的理解
JDBC(Java DataBase Connectivity,java數據庫鏈接)是一種用於執行SQL語句的Java API,能夠爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此能夠構建更高級的工具和接口,使數據庫開發人員可以編寫數據庫應用程序
有了JDBC,向各類關係數據發送SQL語句就是一件很容易的事。換言之,有了JDBC API,就沒必要爲訪問Sybase數據庫專門寫一個程序,爲訪問Oracle數據庫又專門寫一個程序,或爲訪問Informix數據庫又編寫另外一個程序等等,程序員只需用JDBC API寫一個程序就夠了,它可向相應數據庫發送SQL調用。
Ajax異步和同步
同步是指:發送方發出數據後,等接收方發回響應之後才發下一個數據包的通信方式。
異步是指:發送方發出數據後,不等接收方發回響應,接着發送下個數據包的通信方式。
同步通訊方式要求通訊雙方以相同的時鐘頻率進行,並且準確協調,經過共享一個單個時鐘或定時脈衝源保證發送方和接收方的準確同步,效率較高;
異步通訊方式不要求雙方同步,收發方可採用各自的時鐘源,雙方遵循異步的通訊協議,以字符爲數據傳輸單位,發送方傳送字符的時間間隔不肯定,發送效率比同步傳送效率低。
使用者能夠同步或異步實現服務調用。從使用者的觀點來看,這兩種方式的不一樣之處在於:
同步——使用者經過單個線程調用服務;該線程發送請求,在服務運行時阻塞,而且等待響應。
異步——使用者經過兩個線程調用服務;一個線程發送請求,而另外一個單獨的線程接收響應。
秒殺活動
秒殺架構設計理念
限流: 鑑於只有少部分用戶可以秒殺成功,因此要限制大部分流量,只容許少部分流量進入服務後端。
削峯:對於秒殺系統瞬時會有大量用戶涌入,因此在搶購一開始會有很高的瞬間峯值。高峯值流量是壓垮系統很重要的緣由,因此如何把瞬間的高流量變成一段時間平穩的流量也是設計秒殺系統很重要的思路。實現削峯的經常使用的方法有利用緩存和消息中間件等技術。
異步處理:秒殺系統是一個高併發系統,採用異步處理模式能夠極大地提升系統併發量,其實異步處理就是削峯的一種實現方式。
內存緩存:秒殺系統最大的瓶頸通常都是數據庫讀寫,因爲數據庫讀寫屬於磁盤IO,性能很低,若是可以把部分數據或業務邏輯轉移到內存緩存,效率會有極大地提高。
可拓展:固然若是咱們想支持更多用戶,更大的併發,最好就將系統設計成彈性可拓展的,若是流量來了,拓展機器就行了。像淘寶、京東等雙十一活動時會增長大量機器應對交易高峯。
前端方案
瀏覽器端(js):
頁面靜態化:將活動頁面上的全部能夠靜態的元素所有靜態化,並儘可能減小動態元素。經過CDN來抗峯值。
禁止重複提交:用戶提交以後按鈕置灰,禁止重複提交
用戶限流:在某一時間段內只容許用戶提交一次請求,好比能夠採起IP限流
後端方案
服務端控制器層(網關層)
限制uid(UserID)訪問頻率:咱們上面攔截了瀏覽器訪問的請求,但針對某些惡意攻擊或其它插件,在服務端控制層須要針對同一個訪問uid,限制訪問頻率。
服務層
上面只攔截了一部分訪問請求,當秒殺的用戶量很大時,即便每一個用戶只有一個請求,到服務層的請求數量仍是很大。好比咱們有100W用戶同時搶100臺手機,服務層併發請求壓力至少爲100W。
採用消息隊列緩存請求:既然服務層知道庫存只有100臺手機,那徹底沒有必要把100W個請求都傳遞到數據庫啊,那麼能夠先把這些請求都寫到消息隊列緩存一下,數據庫層訂閱消息減庫存,減庫存成功的請求返回秒殺成功,失敗的返回秒殺結束。
利用緩存應對讀請求:對相似於12306等購票業務,是典型的讀多寫少業務,大部分請求是查詢請求,因此能夠利用緩存分擔數據庫壓力。
利用緩存應對寫請求:緩存也是能夠應對寫請求的,好比咱們就能夠把數據庫中的庫存數據轉移到Redis緩存中,全部減庫存操做都在Redis中進行,而後再經過後臺進程把Redis中的用戶秒殺請求同步到數據庫中。
數據庫層
數據庫層是最脆弱的一層,通常在應用設計時在上游就須要把請求攔截掉,數據庫層只承擔「能力範圍內」的訪問請求。因此,上面經過在服務層引入隊列和緩存,讓最底層的數據庫高枕無憂。
案例:利用消息中間件和緩存實現簡單的秒殺系統
Redis是一個分佈式緩存系統,支持多種數據結構,咱們能夠利用Redis輕鬆實現一個強大的秒殺系統。
咱們能夠採用Redis 最簡單的key-value數據結構,用一個原子類型的變量值(AtomicInteger)做爲key,把用戶id做爲value,庫存數量即是原子變量的最大值。對於每一個用戶的秒殺,咱們使用 RPUSH key value插入秒殺請求, 當插入的秒殺請求數達到上限時,中止全部後續插入。
而後咱們能夠在臺啓動多個工做線程,使用 LPOP key 讀取秒殺成功者的用戶id,而後再操做數據庫作最終的下訂單減庫存操做。
固然,上面Redis也能夠替換成消息中間件如ActiveMQ、RabbitMQ等,也能夠將緩存和消息中間件 組合起來,緩存系統負責接收記錄用戶請求,消息中間件負責將緩存中的請求同步到數據庫。
單點登錄若是在另外一臺電腦上登錄並修改了密碼怎麼辦?
(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。
當用戶第一次訪問應用系統的時候,由於尚未登陸,會被引導到認證系統中進行登陸;根據用戶提供的登陸信息,認證系統進行身份校驗,若是經過校驗,應該返回給用戶一個認證的憑據--ticket;用戶再訪問別的應用的時候,就會將這個ticket帶上,做爲本身認證的憑據,應用系統接受到請求以後會把ticket送到認證系統進行校驗,檢查ticket的合法性。若是經過校驗,用戶就能夠在不用再次登陸的狀況下訪問應用系統2和應用系統3了。
要實現SSO,須要如下主要的功能:
全部應用系統共享一個身份認證系統。
統一的認證系統是SSO的前提之一。認證系統的主要功能是將用戶的登陸信息和用戶信息庫相比較,對用戶進行登陸認證;認證成功後,認證系統應該生成統一的認證標誌(ticket),返還給用戶。另外,認證系統還應該對ticket進行效驗,判斷其有效性。
全部應用系統可以識別和提取ticket信息
要實現SSO的功能,讓用戶只登陸一次,就必須讓應用系統可以識別已經登陸過的用戶。應用系統應該能對ticket進行識別和提取,經過與認證系統的通信,能自動判斷當前用戶是否登陸過,從而完成單點登陸的功能。
當用戶在另外一終端登錄並修改密碼,則對應的ticket附帶的信息會發生改變,致使原有ticket因沒法經過校驗而失效。所以要求用戶使用新的密碼從新登錄。
在咱們的電商項目中,單點登錄使用的驗證字符串叫token。這裏的ticket是門票的意思,與咱們學的token對應相同。
Redis宕機以後,購物車中的數據如何處理?如何緩解mysql壓力?
用redis保存的*.rdb文件恢復便可。
另外redis還有AOF功能,啓動時能夠自動恢復到前一條查詢。
這樣作在必定程度上減小數據丟失。但重啓redis會須要從關係型數據庫中讀取數據,增大mysql的壓力。
依據實際狀況,若是redis以前有主從複製,則可在其餘節點redis上拿到數據。若是公司沒錢,則只能暫時限制客戶端訪問量,優先恢復redis數據。
Zookeeper待機的狀況下,dubbo如何工做?
1. Zookeeper的做用:
zookeeper用來註冊服務和進行負載均衡,哪個服務由哪個機器來提供必需讓調用者知道,簡單來講就是ip地址和服務名稱的對應關係。固然也能夠 經過硬編碼的方式把這種對應關係在調用方業務代碼中實現,可是若是提供服務的機器掛掉調用者沒法知曉,若是不更改代碼會繼續請求掛掉的機器提供服務。 zookeeper經過心跳機制能夠檢測掛掉的機器並將掛掉機器的ip和服務對應關係從列表中刪除。至於支持高併發,簡單來講就是橫向擴展,在不更改代碼 的狀況經過添加機器來提升運算能力。經過添加新的機器向zookeeper註冊服務,服務的提供者多了能服務的客戶就多了。
2. dubbo:
是管理中間層的工具,在業務層到數據倉庫間有很是多服務的接入和服務提供者須要調度,dubbo提供一個框架解決這個問題。
注意這裏的dubbo只是一個框架,至於你架子上放什麼是徹底取決於你的,就像一個汽車骨架,你須要配你的輪子引擎。這個框架中要完成調度必需要有一個分佈式的註冊中心,儲存全部服務的元數據,你能夠用zk,也能夠用別的,只是你們都用zk。
3. zookeeper和dubbo的關係:
Dubbo的將註冊中心進行抽象,是得它能夠外接不一樣的存儲媒介給註冊中心提供服務,有ZooKeeper,Memcached,Redis等。
引入了ZooKeeper做爲存儲媒介,也就把ZooKeeper的特性引進來。首先是負載均衡,單註冊中心的承載能力是有限的,在流量達到必定程度的時 候就須要分流,負載均衡就是爲了分流而存在的,一個ZooKeeper羣配合相應的Web應用就能夠很容易達到負載均衡;資源同步,單單有負載均衡還不 夠,節點之間的數據和資源須要同步,ZooKeeper集羣就自然具有有這樣的功能;命名服務,將樹狀結構用於維護全局的服務地址列表,服務提供者在啓動 的時候,向ZK上的指定節點/dubbo/${serviceName}/providers目錄下寫入本身的URL地址,這個操做就完成了服務的發佈。 其餘特性還有Mast選舉,分佈式鎖等。
從MQ在完成訂單以後,發送消息鎖定庫存。消息始終失敗。
網關是如何實現?
就是定義一個Servlet接收請求。而後通過preFilter(封裝請求參數),routeFilter(轉發請求),postFilter(輸出內容)。三個過濾器之間,共享request、response以及其餘的一些全局變量。
(1)將request,response放入threadlocal中
(2)執行三組過濾器
(3)清除threadlocal中的的環境變量
Redis和mysql數據同步是先刪除redis仍是先刪除mysql?
無論是先寫庫,再刪除緩存;仍是先刪緩存,再寫庫,都有可能出現數據不一致的狀況
由於寫和讀是併發的,無法保證順序,若是刪了緩存,尚未來得及寫庫,另外一個線程就來讀取,發現緩存爲空,則去數據庫中讀取數據寫入緩存,此時緩存中爲髒數據。若是先寫了庫,再刪除緩存前,寫庫的線程宕機了,沒有刪除掉緩存,則也會出現數據不一致狀況。 若是是redis集羣,或者主從模式,寫主讀從,因爲redis複製存在必定的時間延遲,也有可能致使數據不一致。
這時候,考慮先刪除數據庫內容,再刪redis。由於在庫存等實時數據都是直接在數據庫中讀取,從業務邏輯上來講,咱們容許查詢時的數據緩存偏差,可是不容許結算時的數據存在偏差。
Hashmap爲何線程不安全,如何讓它線程安全
HashMap在put的時候,插入的元素超過了容量(由負載因子決定)的範圍就會觸發擴容操做,就是rehash,這個會從新將原數組的內容從新hash到新的擴容數組中,在多線程的環境下,存在同時其餘的元素也在進行put操做,若是hash值相同,可能出現同時在同一數組下用鏈表表示,形成閉環,致使在get時會出現死循環,因此HashMap是線程不安全的。
使用 java.util.Hashtable 類,此類是線程安全的。
使用 java.util.concurrent.ConcurrentHashMap,此類是線程安全的。
使用 java.util.Collections.synchronizedMap() 方法包裝 HashMap object,獲得線程安全的Map,並在此Map上進行操做。
Spring cloud原理 網關
Eureka是微服務架構中的註冊中心,專門負責服務的註冊與發現。Eureka Client組件,這個組件專門負責將這個服務的信息註冊到Eureka Server中。Eureka Server是一個註冊中心,裏面有一個註冊表,保存了各服務所在的機器和端口號。
Zuul,也就是微服務網關。這個組件是負責網絡路由的。並且有一個網關以後,還有不少好處,好比能夠作統一的降級、限流、認證受權、安全,等等。
Dubbo+zookeeper如何集羣
Dubbo 是Alibaba開源的分佈式服務框架,它最大的特色是按照分層的方式來架構,使用這種方式能夠使各個層之間解耦合(或者最大限度地鬆耦合)。從服務模型的角度來看,Dubbo採用的是一種很是簡單的模型,要麼是提供方提供服務,要麼是消費方消費服務,因此基於這一點能夠抽象出服務提供方(Provider)和服務消費方(Consumer)兩個角色。
ZooKeeper 是 Apache 的一個頂級項目,爲分佈式應用提供高效、高可用的分佈式協調服務,提供了諸如數據發佈/訂閱、負載均衡、命名服務、分佈式協調/通知和分佈式鎖等分佈式基礎服務。因爲 ZooKeeper 便捷的使用方式、卓越的性能和良好的穩定性,被普遍地應用於諸如 Hadoop、HBase、Kafka 和 Dubbo 等大型分佈式系統中。
Nginx 是一款自由的、開源的、高性能的HTTP服務器和反向代理服務器;同時也是一個IMAP、POP三、SMTP代理服務器;Nginx能夠做爲一個HTTP服務器進行網站的發佈處理,另外Nginx能夠做爲反向代理進行負載均衡的實現。
設計模式在項目中如何體現
一、模板方法模式
定義一個操做中的算法的骨架,而將一些步驟延遲到子類中,如JdbcTemplate
二、代理
spring的Proxy模式在aop中有體現
三、觀察者
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。
spring中Observer模式經常使用的地方是listener的實現。如ApplicationListener。
四、適配器(Adapter )
MethodBeforeAdviceAdapter類
五、策略模式
使用了java的繼承和多態
案例1:加減法計算器,定義一個計算類接口,加法和減法類都實現它,加的時候傳入加法對象。
案例2:導出excel,pdf,word時,分別建立不一樣的對象
簡單理解:執行多個事情時,建立多個對象
六、單例模式
解決一個全局使用的類頻繁的建立與銷燬
七、工廠模式
分爲三種:簡單工廠,工廠方法,抽象工廠
根據「需求」生產「產品」,解耦「需求」「工廠」和「產品」。
簡單工廠:經過構造時傳入的標識來生產產品,不一樣產品都在同一個工廠中生產,每新增長一種產品,須要改工廠類,來判斷,這種判斷會隨着產品的增長而增長,給擴展和維護帶來麻煩
簡單工廠項目案例:根據傳入的 不一樣(好比1對應支付流水,2 對應訂單流水),生成不一樣類型的流水號
工廠方法:(使一個類的使用延遲到子類)
其中的工廠類根據傳入的A.class類型,反射出實例。
產品接口,產品類A,產品類B,工廠類能夠生成不一樣的產品類對象,若是要隨着產品的增長而增長,工廠類不變,只需新增一個產品類C便可。
項目案例:郵件服務器,有三種協議,POP3,IMAP,HTTP,把這三種作完產品類,在定義個工廠方法
抽象工廠:一個工廠生產多個產品,它們是一個產品族,不一樣的產品族的產品派生於不一樣的抽象產品
MQ丟包如何解決
transaction機制就是說,發送消息前,開啓事物(channel.txSelect()),而後發送消息,若是發送過程當中出現什麼異常,事物就會回滾(channel.txRollback()),若是發送成功則提交事物(channel.txCommit())。然而缺點就是吞吐量降低了。
全部在該信道上面發佈的消息都將會被指派一個惟一的ID(從1開始),一旦消息被投遞到全部匹配的隊列以後,rabbitMQ就會發送一個Ack給生產者(包含消息的惟一ID),這就使得生產者知道消息已經正確到達目的隊列了.若是rabiitMQ沒能處理該消息,則會發送一個Nack消息給你,你能夠進行重試操做。
分佈式事務在項目中如何體現
1、兩階段提交(2PC)
兩階段提交這種解決方案屬於犧牲了一部分可用性來換取的一致性。在實現方面,在 .NET 中,能夠藉助 TransactionScop 提供的 API 來編程實現分佈式系統中的兩階段提交,好比WCF中就有實現這部分功能。不過在多服務器之間,須要依賴於DTC來完成事務一致性
優勢: 儘可能保證了數據的強一致,適合對數據強一致要求很高的關鍵領域。(其實也不能100%保證強一致)
缺點: 實現複雜,犧牲了可用性,對性能影響較大,不適合高併發高性能場景,若是分佈式系統跨接口調用,目前 .NET 界尚未實現方案
2、補償事務(TCC)
TCC 其實就是採用的補償機制,其核心思想是:針對每一個操做,都要註冊一個與其對應的確認和補償(撤銷)操做。它分爲三個階段:
Try 階段主要是對業務系統作檢測及資源預留
Confirm 階段主要是對業務系統作確認提交,Try階段執行成功並開始執行 Confirm階段時,默認 Confirm階段是不會出錯的。即:只要Try成功,Confirm必定成功。
Cancel 階段主要是在業務執行錯誤,須要回滾的狀態下執行的業務取消,預留資源釋放。
優勢: 跟2PC比起來,實現以及流程相對簡單了一些,但數據的一致性比2PC也要差一些
缺點: 缺點仍是比較明顯的,在2,3步中都有可能失敗。TCC屬於應用層的一種補償方式,因此須要程序員在實現的時候多寫不少補償的代碼,在一些場景中,一些業務流程可能用TCC不太好定義及處理
3、本地消息表(異步確保)(使用最多的技術方案)
消息生產方,須要額外建一個消息表,並記錄消息發送狀態。消息表和業務數據要在一個事務裏提交,也就是說他們要在一個數據庫裏面。而後消息會通過MQ發送到消息的消費方。若是消息發送失敗,會進行重試發送。
消息消費方,須要處理這個消息,並完成本身的業務邏輯。此時若是本地事務處理成功,代表已經處理成功了,若是處理失敗,那麼就會重試執行。若是是業務上面的失敗,能夠給生產方發送一個業務補償消息,通知生產方進行回滾等操做。
生產方和消費方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發送一遍。
4、MQ 事務消息
有一些第三方的MQ是支持事務消息的,好比RocketMQ,他們支持事務消息的方式也是相似於採用的二階段提交,可是市面上一些主流的MQ都是不支持事務消息的,好比 RabbitMQ 和 Kafka 都不支持。
以阿里的 RocketMQ 中間件爲例,其思路大體爲:
第一階段Prepared消息,會拿到消息的地址。
第二階段執行本地事務,第三階段經過第一階段拿到的地址去訪問消息,並修改狀態。
也就是說在業務方法內要想消息隊列提交兩次請求,一次發送消息和一次確認消息。若是確認消息發送失敗了RocketMQ會按期掃描消息集羣中的事務消息,這時候發現了Prepared消息,它會向消息發送者確認,因此生產方須要實現一個check接口,RocketMQ會根據發送端設置的策略來決定是回滾仍是繼續發送確認消息。這樣就保證了消息發送與本地事務同時成功或同時失敗。
Spring管理bean的做用域,爲何不會被GC處理?
當經過spring容器建立一個Bean實例時,不只能夠完成Bean實例的實例化,還能夠爲Bean指定特定的做用域。Spring支持以下5種做用域:
singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個實例
prototype:原型模式,每次經過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean實例
request:對於每次HTTP請求,使用request定義的Bean都將產生一個新實例,即每次HTTP請求將會產生不一樣的Bean實例。只有在Web應用中使用Spring時,該做用域纔有效
session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新實例。一樣只有在Web應用中使用Spring時,該做用域纔有效
globalsession:每一個全局的HTTP Session,使用session定義的Bean都將產生一個新實例。典型狀況下,僅在使用portlet context的時候有效。一樣只有在Web應用中使用Spring時,該做用域纔有效
其中比較經常使用的是singleton和prototype兩種做用域。對於singleton做用域的Bean,每次請求該Bean都將得到相同的實例。容器負責跟蹤Bean實例的狀態,負責維護Bean實例的生命週期行爲;若是一個Bean被設置成prototype做用域,程序每次請求該id的Bean,Spring都會新建一個Bean實例,而後返回給程序。在這種狀況下,Spring容器僅僅使用new 關鍵字建立Bean實例,一旦建立成功,容器不在跟蹤實例,也不會維護Bean實例的狀態。
若是不指定Bean的做用域,Spring默認使用singleton做用域。Java在建立Java實例時,須要進行內存申請;銷燬實例時,須要完成垃圾回收,這些工做都會致使系統開銷的增長。所以,prototype做用域Bean的建立、銷燬代價比較大。而singleton做用域的Bean實例一旦建立成功,能夠重複使用。所以,除非必要,不然儘可能避免將Bean被設置成prototype做用域。
spring底層使用map來存放bean實體,而map的鍵值是強引用,因此不會被GC,能夠重複使用
上傳圖片的過程當中圖片是在前端壓縮仍是後端壓縮
前端,減小服務器壓力,從最開始就下降了傳輸的數據量。
分佈式事務的具體實現?有哪些模塊運用了?
實現:前面有
運用:
Redis和MySQL如何對接
應用Redis實現數據的讀寫,同時利用隊列處理器定時將數據寫入mysql,此種狀況存在的問題主要是如何保證mysql與redis的數據同步,兩者數據同步的關鍵在於mysql數據庫中主鍵,方案是在redis啓動時去mysql讀取全部表鍵值存入redis中,往redis寫數據時,對redis主鍵自增並進行讀取,若mysql更新失敗,則須要及時清除緩存及同步redis主鍵。
Spring aop註解
設置事務隔離級別
多線程問題(原理)如何查看Stop以後的線程
Spring對bean是如何解析
所謂bean的解析就是將咱們的xml文件中的bean解析出來,上面的入口看到使用的是ClassPathXmlApplicationContext來獲取ApplicationContext,因此,分析的入口也就從ClassPathXmlApplicationContext類中相應的構造函數開始。
getBean() 方法開始建立過程,getBean()有一系列的重載方法,最終都是調用doGetBean() 方法
getSingleton 方法嘗試從緩存中獲取單例 bean
當前 bean 是單例且緩存不存在則經過 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法建立單例對象
主要包含下下面三個主要方法:
createBeanInstance
populateBean
initializeBean
createBeanInstance 方法用於建立 Bean 實例
populateBean 方法主要給 Bean 進行屬性注入
initializeBean 方法主要處理各類回調
爲何InnoDB支持事務而myisam不支持
MyISAM:這個是默認類型,它是基於傳統的ISAM類型,ISAM是Indexed Sequential Access Method (有索引的順序訪問方法) 的縮寫,它是存儲記錄和文件的標準方法.與其餘存儲引擎比較,MyISAM具備檢查和修復表格的大多數工具. MyISAM表格能夠被壓縮,並且它們支持全文搜索.它們不是事務安全的,並且也不支持外鍵。若是事物回滾將形成不徹底回滾,不具備原子性。若是執行大量的SELECT,MyISAM是更好的選擇。
InnoDB:這種類型是事務安全的.它與BDB類型具備相同的特性,它們還支持外鍵.InnoDB表格速度很快.具備比BDB還豐富的特性,所以若是須要一個事務安全的存儲引擎,建議使用它.若是你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表
冪等性防止訂單重複提交
一、token機制,防止頁面重複提交
二、惟一索引,防止新增髒數據
三、悲觀鎖樂觀鎖機制
四、 分佈式鎖
Mysql除了能夠作讀寫分離集羣外還能夠作什麼集羣
Mysql有主從複製集羣和讀寫分離集羣
項目中哪些體現了動態代理
Aop面向切面使用動態代理,有jdk和cglig
CurrentHashmap的併發度 Synchronized和writeeverywhere
樂觀鎖和悲觀鎖在代碼層面和sql層面如何實現
Sql層面:
1、悲觀鎖
一、排它鎖,當事務在操做數據時把這部分數據進行鎖定,直到操做完畢後再解鎖,其餘事務操做纔可操做該部分數據。這將防止其餘進程讀取或修改表中的數據。
二、實現:大多數狀況下依靠數據庫的鎖機制實現
通常使用 select ...for update 對所選擇的數據進行加鎖處理,例如select * from account where name=」Max」 for update, 這條sql 語句鎖定了account 表中全部符合檢索條件(name=」Max」)的記錄。本次事務提交以前(事務提交時會釋放事務過程當中的鎖),外界沒法修改這些記錄。
2、樂觀鎖
一、若是有人在你以前更新了,你的更新應當是被拒絕的,可讓用戶從新操做。
二、實現:大多數基於數據版本(Version)記錄機制實現
具體可經過給表加一個版本號或時間戳字段實現,當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當咱們提交更新的時候,判斷當前版本信息與第一次取出來的版本值大小,若是數據庫表當前版本號與第一次取出來的version值相等,則予以更新,不然認爲是過時數據,拒絕更新,讓用戶從新操做。
代碼層面:
悲觀鎖:一段執行邏輯加上悲觀鎖,不一樣線程同時執行時,只能有一個線程執行,其餘的線程在入口處等待,直到鎖被釋放.
樂觀鎖:一段執行邏輯加上樂觀鎖,不一樣線程同時執行時,能夠同時進入執行,在最後更新數據的時候要檢查這些數據是否被其餘線程修改了(版本和執行初是否相同),沒有修改則進行更新,不然放棄本次操做。
Jdk1.7和1.8以後的鎖有什麼不一樣
MySQL存儲過程
SQL語句須要先編譯而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。
存儲過程是可編程的函數,在數據庫中建立並保存,能夠由SQL語句和控制結構組成。當想要在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬,它容許控制數據的訪問方式。
存儲過程的優勢:
(1).加強SQL語言的功能和靈活性:存儲過程能夠用控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。
(2).標準組件式編程:存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
(3).較快的執行速度:若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
(4).減小網絡流量:針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織進存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大減小網絡流量並下降了網絡負載。
(5).做爲一種安全機制來充分利用:經過對執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。
MySQL存儲過程的建立
語法
CREATE PROCEDURE 過程名([[IN|OUT|INOUT] 參數名 數據類型[,[IN|OUT|INOUT] 參數名 數據類型…]]) [特性 ...] 過程體
DELIMITER //
CREATE PROCEDURE myproc(OUT s int)
BEGIN
SELECT COUNT(*) INTO s FROM students;
END
//
DELIMITER ;
分隔符
MySQL默認以";"爲分隔符,若是沒有聲明分割符,則編譯器會把存儲過程當成SQL語句進行處理,所以編譯過程會報錯,因此要事先用「DELIMITER //」聲明當前段分隔符,讓編譯器把兩個"//"之間的內容當作存儲過程的代碼,不會執行這些代碼;「DELIMITER ;」的意爲把分隔符還原。
參數
存儲過程根據須要可能會有輸入、輸出、輸入輸出參數,若是有多個參數用","分割開。MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT:
· IN參數的值必須在調用存儲過程時指定,在存儲過程當中修改該參數的值不能被返回,爲默認值
· OUT:該值可在存儲過程內部被改變,並可返回
· INOUT:調用時指定,而且可被改變和返回
過程體
過程體的開始與結束使用BEGIN與END進行標識。
Spring boot和spring cloud的區別與聯繫
Spring boot 是 Spring 的一套快速配置腳手架,能夠基於spring boot 快速開發單個微服務,Spring Boot,看名字就知道是Spring的引導,就是用於啓動Spring的,使得Spring的學習和使用變得快速無痛。不只適合替換原有的工程結構,更適合微服務開發。
Spring Cloud基於Spring Boot,爲微服務體系開發中的架構問題,提供了一整套的解決方案——服務註冊與發現,服務消費,服務保護與熔斷,網關,分佈式調用追蹤,分佈式配置管理等。
Spring Cloud是一個基於Spring Boot實現的雲應用開發工具;Spring boot專一於快速、方便集成的單個個體,Spring Cloud是關注全局的服務治理框架;spring boot使用了默認大於配置的理念,不少集成方案已經幫你選擇好了,能不配置就不配置,Spring Cloud很大的一部分是基於Spring boot來實現。
分佈式鎖(zookeeper,redis,數據庫)如何實現
1、基於數據庫實現的分佈式鎖
CREATE TABLE `methodLock` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '鎖定的方法名',
`desc` varchar(1024) NOT NULL DEFAULT '備註信息',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存數據時間,自動生成',
PRIMARY KEY (`id`),
UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='鎖定中的方法';
當咱們想要鎖住某個方法時,執行如下SQL:
insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)
由於咱們對method_name作了惟一性約束,這裏若是有多個請求同時提交到數據庫的話,數據庫會保證只有一個操做能夠成功,那麼咱們就能夠認爲操做成功的那個線程得到了該方法的鎖,能夠執行方法體內容。
當方法執行完畢以後,想要釋放鎖的話,須要執行如下Sql:
delete from methodLock where method_name ='method_name'
上面這種簡單的實現有如下幾個問題:
這把鎖強依賴數據庫的可用性,數據庫是一個單點,一旦數據庫掛掉,會致使業務系統不可用。
這把鎖沒有失效時間,一旦解鎖操做失敗,就會致使鎖記錄一直在數據庫中,其餘線程沒法再得到到鎖。
這把鎖只能是非阻塞的,由於數據的insert操做,一旦插入失敗就會直接報錯。沒有得到鎖的線程並不會進入排隊隊列,要想再次得到鎖就要再次觸發得到鎖操做。
這把鎖是非重入的,同一個線程在沒有釋放鎖以前沒法再次得到該鎖。由於數據中數據已經存在了。
這把鎖是非公平鎖,全部等待鎖的線程憑運氣去爭奪鎖。
固然,咱們也能夠有其餘方式解決上面的問題。
數據庫是單點?搞兩個數據庫,數據以前雙向同步。一旦掛掉快速切換到備庫上。
沒有失效時間?只要作一個定時任務,每隔必定時間把數據庫中的超時數據清理一遍。
非阻塞的?搞一個while循環,直到insert成功再返回成功。
非重入的?在數據庫表中加個字段,記錄當前得到鎖的機器的主機信息和線程信息,那麼下次再獲取鎖的時候先查詢數據庫,若是當前機器的主機信息和線程信息在數據庫能夠查到的話,直接把鎖分配給他就能夠了。
非公平的?再建一張中間表,將等待鎖的線程全記錄下來,並根據建立時間排序,只有最早建立的容許獲取鎖
除了能夠經過增刪操做數據表中的記錄之外,其實還能夠藉助數據中自帶的鎖來實現分佈式的鎖。
咱們還用剛剛建立的那張數據庫表。能夠經過數據庫的排他鎖來實現分佈式鎖。 基於MySql的InnoDB引擎,能夠使用如下方法來實現加鎖操做:
public boolean lock(){
connection.setAutoCommit(false);
while(true){
try{
result = select * from methodLock where method_name=xxx for update;
if(result==null){
return true;
}
}catch(Exception e){
}
sleep(1000);
}
return false;
}
在查詢語句後面增長for update,數據庫會在查詢過程當中給數據庫表增長排他鎖。當某條記錄被加上排他鎖以後,其餘線程沒法再在該行記錄上增長排他鎖。
咱們能夠認爲得到排它鎖的線程便可得到分佈式鎖,當獲取到鎖以後,能夠執行方法的業務邏輯,執行完方法以後,再經過如下方法解鎖:
public void unlock(){ connection.commit(); }
經過connection.commit();操做來釋放鎖。
這種方法能夠有效的解決上面提到的沒法釋放鎖和阻塞鎖的問題。
阻塞鎖? for update語句會在執行成功後當即返回,在執行失敗時一直處於阻塞狀態,直到成功。
鎖定以後服務宕機,沒法釋放?使用這種方式,服務宕機以後數據庫會本身把鎖釋放掉。
可是仍是沒法直接解決數據庫單點、可重入和公平鎖的問題。
總結一下使用數據庫來實現分佈式鎖的方式,這兩種方式都是依賴數據庫的一張表,一種是經過表中的記錄的存在狀況肯定當前是否有鎖存在,另一種是經過數據庫的排他鎖來實現分佈式鎖。
直接藉助數據庫,容易理解。
會有各類各樣的問題,在解決問題的過程當中會使整個方案變得愈來愈複雜。
操做數據庫須要必定的開銷,性能問題須要考慮。
相比較於基於數據庫實現分佈式鎖的方案來講,基於緩存來實如今性能方面會表現的更好一點。
目前有不少成熟的緩存產品,包括Redis,memcached等。這裏以Redis爲例來分析下使用緩存實現分佈式鎖的方案。
基於Redis實現分佈式鎖在網上有不少相關文章,其中主要的實現方式是使用Jedis.setNX方法來實現。
public boolean trylock(String key) {
ResultCode code = jedis.setNX(key, "This is a Lock.");
if (ResultCode.SUCCESS.equals(code))
return true;
else
return false;
}
public boolean unlock(String key){
ldbTairManager.invalid(NAMESPACE, key);
}
以上實現方式一樣存在幾個問題:
一、單點問題。
二、這把鎖沒有失效時間,一旦解鎖操做失敗,就會致使鎖記錄一直在redis中,其餘線程沒法再得到到鎖。
三、這把鎖只能是非阻塞的,不管成功仍是失敗都直接返回。
四、這把鎖是非重入的,一個線程得到鎖以後,在釋放鎖以前,沒法再次得到該鎖,由於使用到的key在redis中已經存在。沒法再執行setNX操做。
五、這把鎖是非公平的,全部等待的線程同時去發起setNX操做,運氣好的線程能獲取鎖。
固然,一樣有方式能夠解決。
如今主流的緩存服務都支持集羣部署,經過集羣來解決單點問題。
沒有失效時間?redis的setExpire方法支持傳入失效時間,到達時間以後數據會自動刪除。
非阻塞?while重複執行。
非可重入?在一個線程獲取到鎖以後,把當前主機信息和線程信息保存起來,下次再獲取以前先檢查本身是否是當前鎖的擁有者。
非公平?在線程獲取鎖以前先把全部等待的線程放入一個隊列中,而後按先進先出原則獲取鎖。
redis集羣的同步策略是須要時間的,有可能A線程setNX成功後拿到鎖,可是這個值尚未更新到B線程執行setNX的這臺服務器,那就會產生併發問題。
redis的做者Salvatore Sanfilippo,提出了Redlock算法,該算法實現了比單一節點更安全、可靠的分佈式鎖管理(DLM)。
Redlock算法假設有N個redis節點,這些節點互相獨立,通常設置爲N=5,這N個節點運行在不一樣的機器上以保持物理層面的獨立。
算法的步驟以下:
一、客戶端獲取當前時間,以毫秒爲單位。
二、客戶端嘗試獲取N個節點的鎖,(每一個節點獲取鎖的方式和前面說的緩存鎖同樣),N個節點以相同的key和value獲取鎖。客戶端須要設置接口訪問超時,接口超時時間須要遠遠小於鎖超時時間,好比鎖自動釋放的時間是10s,那麼接口超時大概設置5-50ms。這樣能夠在有redis節點宕機後,訪問該節點時能儘快超時,而減少鎖的正常使用。
三、客戶端計算在得到鎖的時候花費了多少時間,方法是用當前時間減去在步驟一獲取的時間,只有客戶端得到了超過3個節點的鎖,並且獲取鎖的時間小於鎖的超時時間,客戶端纔得到了分佈式鎖。
四、客戶端獲取的鎖的時間爲設置的鎖超時時間減去步驟三計算出的獲取鎖花費時間。
五、若是客戶端獲取鎖失敗了,客戶端會依次刪除全部的鎖。
使用Redlock算法,能夠保證在掛掉最多2個節點的時候,分佈式鎖服務仍然能工做,這相比以前的數據庫鎖和緩存鎖大大提升了可用性,因爲redis的高效性能,分佈式緩存鎖性能並不比數據庫鎖差。
可是,有一位分佈式的專家寫了一篇文章《How to do distributed locking》,質疑Redlock的正確性。
該專家提到,考慮分佈式鎖的時候須要考慮兩個方面:性能和正確性。
若是使用高性能的分佈式鎖,對正確性要求不高的場景下,那麼使用緩存鎖就足夠了。
若是使用可靠性高的分佈式鎖,那麼就須要考慮嚴格的可靠性問題。而Redlock則不符合正確性。爲何不符合呢?專家列舉了幾個方面。
如今不少編程語言使用的虛擬機都有GC功能,在Full GC的時候,程序會停下來處理GC,有些時候Full GC耗時很長,甚至程序有幾分鐘的卡頓,文章列舉了HBase的例子,HBase有時候GC幾分鐘,會致使租約超時。並且Full GC何時到來,程序沒法掌控,程序的任什麼時候候均可能停下來處理GC,好比下圖,客戶端1得到了鎖,正準備處理共享資源的時候,發生了Full GC直到鎖過時。這樣,客戶端2又得到了鎖,開始處理共享資源。在客戶端2處理的時候,客戶端1 Full GC完成,也開始處理共享資源,這樣就出現了2個客戶端都在處理共享資源的狀況。
給鎖帶上token,token就是version的概念,每次操做鎖完成,token都會加1,在處理共享資源的時候帶上token,只有指定版本的token可以處理共享資源。
使用緩存實現分佈式鎖的優勢
性能好。
實現過於負責,須要考慮的因素太多。
基於zookeeper臨時有序節點能夠實現的分佈式鎖。
大體思想即爲:每一個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個惟一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只須要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除便可。同時,其能夠避免服務宕機致使的鎖沒法釋放,而產生的死鎖問題。
來看下Zookeeper能不能解決前面提到的問題。
鎖沒法釋放?使用Zookeeper能夠有效的解決鎖沒法釋放的問題,由於在建立鎖的時候,客戶端會在ZK中建立一個臨時節點,一旦客戶端獲取到鎖以後忽然掛掉(Session鏈接斷開),那麼這個臨時節點就會自動刪除掉。其餘客戶端就能夠再次得到鎖。
非阻塞鎖?使用Zookeeper能夠實現阻塞的鎖,客戶端能夠經過在ZK中建立順序節點,而且在節點上綁定監聽器,一旦節點有變化,Zookeeper會通知客戶端,客戶端能夠檢查本身建立的節點是否是當前全部節點中序號最小的,若是是,那麼本身就獲取到鎖,即可以執行業務邏輯了。
不可重入?使用Zookeeper也能夠有效的解決不可重入的問題,客戶端在建立節點的時候,把當前客戶端的主機信息和線程信息直接寫入到節點中,下次想要獲取鎖的時候和當前最小的節點中的數據比對一下就能夠了。若是和本身的信息同樣,那麼本身直接獲取到鎖,若是不同就再建立一個臨時的順序節點,參與排隊。
單點問題?使用Zookeeper能夠有效的解決單點問題,ZK是集羣部署的,只要集羣中有半數以上的機器存活,就能夠對外提供服務。
公平問題?使用Zookeeper能夠解決公平鎖問題,客戶端在ZK中建立的臨時節點是有序的,每次鎖被釋放時,ZK能夠通知最小節點來獲取鎖,保證了公平。
問題又來了,咱們知道Zookeeper須要集羣部署,會不會出現Redis集羣那樣的數據同步問題呢?
Zookeeper是一個保證了弱一致性即最終一致性的分佈式組件。
Zookeeper採用稱爲Quorum Based Protocol的數據同步協議。假如Zookeeper集羣有N臺Zookeeper服務器(N一般取奇數,3臺可以知足數據可靠性同時有很高讀寫性能,5臺在數據可靠性和讀寫性能方面平衡最好),那麼用戶的一個寫操做,首先同步到N/2 + 1臺服務器上,而後返回給用戶,提示用戶寫成功。基於Quorum Based Protocol的數據同步協議決定了Zookeeper可以支持什麼強度的一致性。
在分佈式環境下,知足強一致性的數據儲存基本不存在,它要求在更新一個節點的數據,須要同步更新全部的節點。這種同步策略出如今主從同步複製的數據庫中。可是這種同步策略,對寫性能的影響太大而不多見於實踐。由於Zookeeper是同步寫N/2+1個節點,還有N/2個節點沒有同步更新,因此Zookeeper不是強一致性的。
用戶的數據更新操做,不保證後續的讀操做可以讀到更新後的值,可是最終會呈現一致性。犧牲一致性,並非徹底無論數據的一致性,不然數據是混亂的,那麼系統可用性再高分佈式再好也沒有了價值。犧牲一致性,只是再也不要求關係型數據庫中的強一致性,而是隻要系統能達到最終一致性便可。
Zookeeper是否知足因果一致性,須要看客戶端的編程方式。
不知足因果一致性的作法
A進程向Zookeeper的/z寫入一個數據,成功返回
A進程通知B進程,A已經修改了/z的數據
B讀取Zookeeper的/z的數據
因爲B鏈接的Zookeeper的服務器有可能尚未獲得A寫入數據的更新,那麼B將讀不到A寫入的數據
知足因果一致性的作法
B進程監聽Zookeeper上/z的數據變化
A進程向Zookeeper的/z寫入一個數據,成功返回前,Zookeeper須要調用註冊在/z上的監聽器,Leader將數據變化的通知告訴B
B進程的事件響應方法獲得響應後,去取變化的數據,那麼B必定可以獲得變化的值
這裏的因果一致性提如今Leader和B之間的因果一致性,也就是是Leader通知了數據有變化
第二種事件監聽機制也是對Zookeeper進行正確編程應該使用的方法,因此,Zookeeper應該是知足因果一致性的
因此咱們在基於Zookeeper實現分佈式鎖的時候,應該使用知足因果一致性的作法,即等待鎖的線程都監聽Zookeeper上鎖的變化,在鎖被釋放的時候,Zookeeper會將鎖變化的通知告訴知足公平鎖條件的等待線程。
能夠直接使用zookeeper第三方庫客戶端,這個客戶端中封裝了一個可重入的鎖服務。
Dubbo原理,ES權重如何實現
Spring boot和dubbo的區別
Ik分詞器分出中英文的緣由是什麼
後臺訂單倒計時如何對接(同步)前端頁面
Spring代理是什麼
項目上線後,日誌如何處理
輸出成文本文檔保存記錄
如何使用集合分組
ThreadLocal做用和使用場景,數據傳遞是否同步
ThreadLocal提供一個方便的方式,能夠根據不一樣的線程存放一些不一樣的特徵屬性,能夠方便的在線程中進行存取。
在Hibernate中是經過使用ThreadLocal來實現的。在getSession方法中,若是ThreadLocal存在session,則返回session,不然建立一個session放入ThreadLocal中
總結一下就是在ThreadLocal中存放了一個session。
實際上ThreadLocal中並無存聽任何的對象或引用,在上面的的代碼中ThreadLocal的實例threadSession只至關於一個標記的做用。而存放對象的真正位置是正在運行的Thread線程對象,每一個Thread對象中都存放着一個ThreadLocalMap類型threadLocals對象,這是一個映射表map,這個map的鍵是一個ThreadLocal對象,值就是咱們想存的局部對象。
在線程中存放一些就像session的這種特徵變量,會針對不一樣的線程,有不一樣的值。
所以,不一樣步。
線程池滿了怎麼辦
Dubbo失敗策略
Failover Cluster 模式
1.失敗自動切換,當出現失敗,重試其它服務器。(缺省)
2. 一般用於讀操做,但重試會帶來更長延遲。
3. 可經過retries=」2」來設置重試次數(不含第一次)。
Failfast Cluster
快速失敗,只發起一次調用,失敗當即報錯。
一般用於非冪等性的寫操做,好比新增記錄。
Failsafe Cluster
失敗安全,出現異常時,直接忽略。
一般用於寫入審計日誌等操做。
.Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。
一般用於消息通知操做。
Forking Cluster
並行調用多個服務器,只要一個成功即返回。
一般用於實時性要求較高的讀操做,但須要浪費更多服務資源。
可經過forks=」2」來設置最大並行數。
Broadcast Cluster
廣播調用全部提供者,逐個調用,任意一臺報錯則報錯。(2.1.0開始支持)
一般用於通知全部提供者更新緩存或日誌等本地資源信息。
Redis中watch機制和原理
咱們經常使用redis的watch和multi來處理一些涉及併發的操做,redis的watch+multi實際是一種樂觀鎖
watch命令描述
WATCH命令能夠監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),以後的事務就不會執行。監控一直持續到EXEC命令(事務中的命令是在EXEC以後才執行的,因此在MULTI命令後能夠修改WATCH監控的鍵值)
SpringMVC、Springboot、Mybatis、Dubbo、Zookeeper、Redis、Elasticsearch、Nginx 、Fastdfs、ActiveMQ
SpringMVC:
簡單的介紹一下Spring Mvc的工做原理?
一、用戶向服務器發送請求,請求被SpringMVC的前端控制器DispatcherServlet截獲。
二、DispatcherServlet對請求的URL(統一資源定位符)進行解析,獲得URI(請求資源標識符),而後根據該URI,調用HandlerMapping得到該Handler配置的全部相關的對象,包括Handler對象以及Handler對象對應的攔截器,這些對象都會被封裝到一個HandlerExecutionChain對象當中返回。
三、DispatcherServlet根據得到的Handler,選擇一個合適的HandlerAdapter。HandlerAdapter的設計符合面向對象中的單一職責原則,代碼結構清晰,便於維護,最爲重要的是,代碼的可複製性高。HandlerAdapter會被用於處理多種Handler,調用Handler實際處理請求的方法。
四、提取請求中的模型數據,開始執行Handler(Controller)。在填充Handler的入參過程當中,根據配置,spring將幫助作一些額外的工做消息轉換:將請求的消息,如json、xml等數據轉換成一個對象,將對象轉換爲指定的響應信息。數據轉換:對請求消息進行數據轉換,如String轉換成Integer、Double等。 數據格式化:對請求的消息進行數據格式化,如將字符串轉換爲格式化數字或格式化日期等。數據驗證:驗證數據的有效性如長度、格式等,驗證結果存儲到BindingResult或Error中。
五、Handler執行完成後,向DispatcherServlet返回一個ModelAndView對象,ModelAndView對象中應該包含視圖名或視圖模型。
六、根據返回的ModelAndView對象,選擇一個合適的ViewResolver(視圖解析器)返回給DispatcherServlet。
七、ViewResolver結合Model和View來渲染視圖。
八、將視圖渲染結果返回給客戶端。
url和uri的區別?
URI包括URL和URN兩個類別,我的的身份證號就是URN,我的的家庭地址就是URL,URN能夠惟一標識一我的,而URL能夠告訴郵遞員怎麼把貨送到你手裏。
Springboot:
簡單的介紹一下Springboot?
Springboot用來簡化spring應用的初始搭建以及開發過程 使用特定的方式來進行配置(properties或yml文件)
能夠建立獨立的spring引用程序 main方法運行
Springboot嵌入的Tomcat 無需部署war文件
簡化maven配置
starters自動依賴與版本控制
Mybatis:
一、什麼是mybatis?
(1)mybatis是一個優秀的基於java的持久層框架,它內部封裝了jdbc,使開發者只須要關注sql語句自己,而不須要花費精力去處理加載驅動、建立鏈接、建立statement等繁雜的過程。
(2)mybatis經過xml或註解的方式將要執行的各類statement配置起來,並經過java對象和statement中sql的動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射爲java對象並返回。
(3)MyBatis 支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 能夠使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJO映射成數據庫中的記錄。
二、Mybait的優勢:
(1)簡單易學,容易上手(相比於Hibernate) —- 基於SQL編程;
(2)JDBC相比,減小了50%以上的代碼量,消除了JDBC大量冗餘的代碼,不須要手動開關鏈接;
(3)很好的與各類數據庫兼容(由於MyBatis使用JDBC來鏈接數據庫,因此只要JDBC支持的數據庫MyBatis都支持,而JDBC提供了可擴展性,因此只要這個數據庫有針對Java的jar包就能夠就能夠與MyBatis兼容),開發人員不須要考慮數據庫的差別性。
(4)提供了不少第三方插件(分頁插件 / 逆向工程);
(5)可以與Spring很好的集成;
(6)MyBatis至關靈活,不會對應用程序或者數據庫的現有設計強加任何影響,SQL寫在XML裏,從程序代碼中完全分離,解除sql與程序代碼的耦合,便於統一管理和優化,並可重用。
(7)提供XML標籤,支持編寫動態SQL語句。
(8) 提供映射標籤,支持對象與數據庫的ORM字段關係映射。
(9)提供對象關係映射標籤,支持對象關係組建維護。
三、MyBatis框架的缺點:
(1)SQL語句的編寫工做量較大,尤爲是字段多、關聯表多時,更是如此,對開發人員編寫SQL語句的功底有必定要求。
(2)SQL語句依賴於數據庫,致使數據庫移植性差,不能隨意更換數據庫。
四、MyBatis框架適用場合:
(1)MyBatis專一於SQL自己,是一個足夠靈活的DAO層解決方案。
(2)對性能的要求很高,或者需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。
五、#{}和${}的區別是什麼?
#{}是預編譯處理,${}是字符串替換。
Mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值;
Mybatis在處理${}時,就是把${}替換成變量的值。
使用#{}能夠有效的防止SQL注入,提升系統安全性。
Dubbo:
簡單的介紹一下Dubbo?(Dubbo是什麼)
dubbo就是個服務調用的東東。
爲何怎麼說呢?
由於Dubbo是由阿里開源的一個RPC分佈式框架
那麼RPC是什麼呢?
就是不一樣的應用部署到不一樣的服務器上,應用之間想要調用沒有辦法直接調用,由於不在一個內存空間,須要經過網絡通信來調用,或者傳達調用的數據。並且RPC會將遠程調用的細節隱藏起來,讓調用遠程服務像調用本地服務同樣簡單。
dubbo有哪些組件?
主要有五個角色/核心組件,分爲是Container(容器)、Provider(服務的提供方)、Registry(註冊中心)、Consumer(服務的消費方)、Monitor(監控中心)。
容器:主要負責啓動、加載、運行服務提供者;
註冊中心:註冊中心只負責地址的註冊和查找
監控中心:監控中心負責統計各服務調用次數、調用時間
Dubbo支持什麼協議?
Dubbo協議:缺省協議、採用了單一長鏈接和NIO異步通信、使用線程池併發處理請求,能減小握手和加大併發效率
Zookeeper:
Zookeeper的實現原理?(工做原理)
Zookeeper會維護一個相似於標準的文件系統的具備層次關係的數據結構。這個文件系統中每一個子目錄項都被稱爲znode節點,這個znode節點也能夠有子節點,每一個節點均可以存儲數據,客戶端也能夠對這些node節點進行getChildren,getData,exists方法,同時也能夠在znode tree路徑上設置watch(相似於監聽),當watch路徑上發生節點create、delete、update的時候,會通知到client。client能夠獲得通知後,再獲取數據,執行業務邏輯操做。Zookeeper 的做用主要是用來維護和監控存儲的node節點上這些數據的狀態變化,經過監控這些數據狀態的變化,從而達到基於數據的集羣管理。
爲何要用zookeeper做爲dubbo的註冊中心?能選擇其餘的嗎?
Zookeeper的數據模型是由一系列的Znode數據節點組成,和文件系統相似。zookeeper的數據所有存儲在內存中,性能高;zookeeper也支持集羣,實現了高可用;同時基於zookeeper的特性,也支持事件監聽(服務的暴露方發生變化,能夠進行推送),因此zookeeper適合做爲dubbo的註冊中心區使用。redis、Simple也能夠做爲dubbo的註冊中心來使用。
項目中主要用zookeeper作了什麼?(做用)
做爲註冊中心用;主要是在服務器上搭建zookeeper,其次在spring管理的dubbo的配置文件中配置(暴露方和消費方都須要配置)
Redis:
簡單介紹一個redis?
redis是內存中的數據結構存儲系統,一個key-value類型的非關係型數據庫,可持久化的數據庫,相對於關係型數據庫(數據主要存在硬盤中),性能高,所以咱們通常用redis來作緩存使用;而且redis支持豐富的數據類型,比較容易解決各類問題,所以redis能夠用來做爲註冊中心,數據庫、緩存和消息中間件。Redis的Value支持5種數據類型,string、hash、list、set、zset(sorted set);
String類型:一個key對應一個value
Hash類型:它的key是string類型,value又是一個map(key-value),適合存儲對象。
List類型:按照插入順序的字符串鏈表(雙向鏈表),主要命令是LPUSH和RPUSH,可以支持反向查找和遍歷
Set類型:用哈希表類型的字符串序列,沒有順序,集合成員是惟一的,沒有重複數據,底層主要是由一個value永遠爲null的hashmap來實現的。
zset類型:和set類型基本一致,不過它會給每一個元素關聯一個double類型的分數(score),這樣就能夠爲成員排序,而且插入是有序的。
你還用過其餘的緩存嗎?這些緩存有什麼區別?都在什麼場景下去用?
對於緩存瞭解過redis和memcache
Memcache和redis的區別:
數據支持的類型:redis不只僅支持簡單的k/v類型的數據,同時還支持list、set、zset、hash等數據結構的存儲;memcache只支持簡單的k/v類型的數據,key和value都是string類型
可靠性:memcache不支持數據持久化,斷電或重啓後數據消失,但其穩定性是有保證的;redis支持數據持久化和數據恢復,容許單點故障,可是同時也會付出性能的代價
性能上:對於存儲大數據,memcache的性能要高於redis
應用場景:
Memcache:適合多讀少寫,大數據量的狀況(一些官網的文章信息等)
Redis:適用於對讀寫效率要求高、數據處理業務複雜、安全性要求較高的系統
案例:分佈式系統,存在session之間的共享問題,所以在作單點登陸的時候,咱們利用redis來模擬了session的共享,來存儲用戶的信息,實現不一樣系統的session共享;
對redis的持久化了解不?
redis的持久化方式有兩種:
RDB(半持久化方式):按照配置不按期的經過異步的方式、快照的形式直接把內存中的數據持久化到磁盤的一個dump.rdb文件(二進制的臨時文件)中,redis默認的持久化方式,它在配置文件(redis.conf)中。
優勢:只包含一個文件,將一個單獨的文件轉移到其餘存儲媒介上,對於文件備份、災難恢復而言,比較實用。
缺點:系統一旦在持久化策略以前出現宕機現象,此前沒有來得及持久化的數據將會產生丟失
RDB持久化配置:
Redis會將數據集的快照dump到dump.rdb文件中。此外,咱們也能夠經過配置文件來修改Redis服務器dump快照的頻率,在打開6379.conf文件以後,咱們搜索save,能夠看到下面的配置信息:
save 900 1 #在900秒(15分鐘)以後,若是至少有1個key發生變化,則dump內存快照。
save 300 10 #在300秒(5分鐘)以後,若是至少有10個key發生變化,則dump內存快照。
save 60 10000 #在60秒(1分鐘)以後,若是至少有10000個key發生變化,則dump內存快照。
AOF(全持久化的方式):把每一次數據變化都經過write()函數將你所執行的命令追加到一個appendonly.aof文件裏面,Redis默認是不支持這種全持久化方式的,須要在配置文件(redis.conf)中將appendonly no改爲appendonly yes
優勢:數據安全性高,對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機問題,也不會破壞日誌文件中已經存在的內容;
缺點:對於數量相同的數據集來講,aof文件一般要比rdb文件大,所以rdb在恢復大數據集時的速度大於AOF;
AOF持久化配置:
在Redis的配置文件中存在三種同步方式,它們分別是:
appendfsync always #每次有數據修改發生時都會都調用fsync刷新到aof文件,很是慢,可是安全;
appendfsync everysec #每秒鐘都調用fsync刷新到aof文件中,很快,可是可能丟失一秒內的數據,推薦使用,兼顧了速度和安全;
appendfsync no #不會自動同步到磁盤上,須要依靠OS(操做系統)進行刷新,效率快,可是安全性就比較差;
二種持久化方式區別:
AOF在運行效率上每每慢於RDB,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB同樣高效;
若是緩存數據安全性要求比較高的話,用aof這種持久化方式(好比項目中的購物車);
若是對於大數據集要求效率高的話,就能夠使用默認的。並且這兩種持久化方式能夠同時使用。
作過redis的集羣嗎?大家作集羣的時候搭建了幾臺,都是怎麼搭建的?
Redis的數據是存放在內存中的,不適合存儲大數據,大數據存儲通常公司經常使用hadoop中的Hbase或者MogoDB。redis主要用來處理高併發的,用咱們的項目來講,電商項目若是併發大的話,一臺單獨的redis是不能足夠支持咱們的併發,這就須要咱們擴展多臺設備協同合做,即用到集羣。
Redis搭建集羣的方式有多種,例如:客戶端分片、Twemproxy、Codis等,可是redis3.0以後就支持redis-cluster集羣,這種方式採用的是無中心結構,每一個節點保存數據和整個集羣的狀態,每一個節點都和其餘全部節點鏈接。若是使用的話就用redis-cluster集羣。集羣這塊是公司運維搭建的,具體怎麼搭建不是太瞭解。
咱們項目中redis集羣主要搭建了6臺,3主(爲了保證redis的投票機制)3從(高可用),每一個主服務器都有一個從服務器,做爲備份機。全部的節點都經過PING-PONG機制彼此互相鏈接;客戶端與redis集羣鏈接,只須要鏈接集羣中的任何一個節點便可;Redis-cluster中內置了16384個哈希槽,Redis-cluster把全部的物理節點映射到【0-16383】slot上,負責維護。
redis有事務嗎?
Redis是有事務的,redis中的事務是一組命令的集合,這組命令要麼都執行,要不都不執行,保證一個事務中的命令依次執行而不被其餘命令插入。redis的事務是不支持回滾操做的。redis事務的實現,須要用到MULTI(事務的開始)和EXEC(事務的結束)命令 ;
緩存穿透
緩存查詢通常都是經過key去查找value,若是不存在對應的value,就要去數據庫中查找。若是這個key對應的value在數據庫中也不存在,而且對該key併發請求很大,就會對數據庫產生很大的壓力,這就叫緩存穿透
解決方案:
1.對全部可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄。
2.將全部可能存在的數據哈希到一個足夠大的bitmap中,一個必定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
3.若是一個查詢返回的數據爲空(無論是數 據不存在,仍是系統故障),咱們仍然把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。
緩存雪崩
當緩存服務器重啓或者大量緩存集中在一段時間內失效,發生大量的緩存穿透,這樣在失效的瞬間對數據庫的訪問壓力就比較大,全部的查詢都落在數據庫上,形成了緩存雪崩。 這個沒有完美解決辦法,但能夠分析用戶行爲,儘可能讓失效時間點均勻分佈。大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線程(進程)寫,從而避免失效時大量的併發請求落到底層存儲系統上。
解決方案:
1.在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。
2.能夠經過緩存reload機制,預先去更新緩存,再即將發生大併發訪問前手動觸發加載緩存
3.不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻
4.作二級緩存,或者雙緩存策略。A1爲原始緩存,A2爲拷貝緩存,A1失效時,能夠訪問A2,A1緩存失效時間設置爲短時間,A2設置爲長期。
redis的安全機制(大家公司redis的安全這方面怎麼考慮的?)
漏洞介紹:redis默認狀況下,會綁定在bind 0.0.0.0:6379,這樣就會將redis的服務暴露到公網上,若是在沒有開啓認證的狀況下,能夠致使任意用戶在訪問目標服務器的狀況下,未受權就可訪問redis以及讀取redis的數據,攻擊者就能夠在未受權訪問redis的狀況下能夠利用redis的相關方法,成功在redis服務器上寫入公鑰,進而能夠直接使用私鑰進行直接登陸目標主機;
解決方案:
禁止一些高危命令。修改redis.conf文件,用來禁止遠程修改DB文件地址,好比 rename-command FLUSHALL "" 、rename-command CONFIG"" 、rename-command EVAL 「」等;
以低權限運行redis服務。爲redis服務建立單獨的用戶和根目錄,而且配置禁止登陸;
爲redis添加密碼驗證。修改redis.conf文件,添加requirepass mypassword;
禁止外網訪問redis。修改redis.conf文件,添加或修改 bind 127.0.0.1,使得redis服務只在當前主機使用;
作log監控,及時發現攻擊;
redis的哨兵機制(redis2.6之後出現的)
哨兵機制:
監控:監控主數據庫和從數據庫是否正常運行;
提醒:當被監控的某個redis出現問題的時候,哨兵能夠經過API向管理員或者其餘應用程序發送通知;
自動故障遷移:主數據庫出現故障時,能夠自動將從數據庫轉化爲主數據庫,實現自動切換;
具體的配置步驟參考的網上的文檔。要注意的是,若是master主服務器設置了密碼,記得在哨兵的配置文件(sentinel.conf)裏面配置訪問密碼
redis中對於生存時間的應用
Redis中能夠使用expire命令設置一個鍵的生存時間,到時間後redis會自動刪除;
應用場景:
設置限制的優惠活動的信息;
一些及時須要更新的數據,積分排行榜;
手機驗證碼的時間;
限制網站訪客訪問頻率;
Elasticsearch:
簡單介紹一個Elasticsearch?
ElasticSearch是一個基於Lucene的搜索服務器。經過HTTP使用JSON進行數據索引,用於分佈式全文檢索,解決人們對於搜索的衆多要求。
lucene與elasticsearch(solr)有什麼區別?
lucene只是一個提供全文搜索功能類庫的核心工具包,而真正使用它還須要一個完善的服務框架搭建起來的應用。比如lucene是相似於jdk,而搜索引擎軟件就是tomcat 的。elasticsearch和solr,這兩款都是基於lucene的搭建的,能夠獨立部署啓動的搜索引擎服務軟件。
基本概念:
cluster集羣 |
整個elasticsearch 默認就是集羣狀態,整個集羣是一份完整、互備的數據。 |
node節點 |
集羣中的一個節點,通常只一個進程就是一個node |
shard分片 |
分片,即便是一個節點中的數據也會經過hash算法,分紅多個片存放,默認是5片。 |
index邏輯數據庫 |
至關於rdbms的database, 對於用戶來講是一個邏輯數據庫,雖然物理上會被分多個shard存放,也可能存放在多個node中。 |
type |
相似於rdbms的table,可是與其說像table,其實更像面向對象中的class , 同一Json的格式的數據集合。 |
document |
相似於rdbms的 row、面向對象裏的object |
field |
至關於字段、屬性 |
與MySQL對比
利用kibana學習 elasticsearch restful api (DSL)
Kibana 是一個開源分析和可視化平臺,可視化操做 Elasticsearch 。Kibana能夠用來搜索,查看和與存儲在 Elasticsearch 索引中的數據進行交互。能夠輕鬆地進行高級數據分析,並可在各類圖表,表格和地圖中顯示數據。
ES提供了基於JSON的query DSL查詢語言
es中保存的數據結構
public class Movie { String id; String name; Double doubanScore; List<Actor> actorList; }
public class Actor{ String id; String name; } |
這兩個對象若是放在關係型數據庫保存,會被拆成2張表,可是elasticsearch是用一個json來表示一個document。
因此它保存到es中應該是:
{ 「id」:」1」, 「name」:」operation red sea」, 「doubanScore」:」8.5」, 「actorList」:[ {「id」:」1」,」name」:」zhangyi」}, {「id」:」2」,」name」:」haiqing」}, {「id」:」3」,」name」:」zhanghanyu」} ] } |
es 的java 客戶端的選擇
目前市面上有兩類客戶端
一類是TransportClient 爲表明的ES原生客戶端,不能執行原生dsl語句必須使用它的Java api方法。
另一種是以Rest Api爲主的missing client,最典型的就是jest。 這種客戶端能夠直接使用dsl語句拼成的字符串,直接傳給服務端,而後返回json字符串再解析。
兩種方式各有優劣,可是最近elasticsearch官網,宣佈計劃在7.0之後的版本中廢除TransportClient。以RestClient爲主。在官方的RestClient 基礎上,進行了簡單包裝的Jest客戶端,就成了首選,並且該客戶端也與springboot完美集成。
中文分詞
elasticsearch自己自帶的中文分詞,就是單純把中文一個字一個字的分開,根本沒有詞彙的概念。
問題:
一、 es大量的寫操做會影響es 性能,由於es須要更新索引,並且es不是內存數據庫,會作相應的io操做。
二、並且修改某一個值,在高併發狀況下會有衝突,形成更新丟失,須要加鎖,而es的樂觀鎖會惡化性能問題。
解決思路:
用redis作精確計數器,redis是內存數據庫讀寫性能都很是快,利用redis的原子性的自增能夠解決併發寫操做。
redis每計100次數(能夠被100整除)咱們就更新一次es ,這樣寫操做就被稀釋了100倍,這個倍數能夠根據業務狀況靈活設定。
增量同步索引庫
推薦使用MQ(RabbitMQ)
原理:使用MQ作增量同步,即當修改數據以後就將此數據發送至MQ,由MQ將此數據同步到ES上
Nginx:
一、請解釋一下什麼是Nginx?
nginx本是一個web服務器和反向代理服務器,但因爲豐富的負載均衡策略,經常被用於客戶端可真實的服務器之間,做爲負載均衡的實現。用於HTTP、HTTPS、SMTP、POP3和IMAP協議。
二、請列舉Nginx的一些特性?
1)反向代理/L7負載均衡器
2)嵌入式Perl解釋器
3)動態二進制升級
4)可用於從新編寫URL,具備很是好的PCRE支持
三、nginx和apache的區別?
1)輕量級,一樣起web 服務,比apache 佔用更少的內存及資源
2)抗併發,nginx 處理請求是異步非阻塞的,而apache 則是阻塞型的,在高併發下nginx 能保持低資源低消耗高性能
3)高度模塊化的設計,編寫模塊相對簡單
4)最核心的區別在於apache是同步多進程模型,一個鏈接對應一個進程;nginx是異步的,多個鏈接(萬級別)能夠對應一個進程
4.nginx是如何實現高併發的?
一個主進程,多個工做進程,每一個工做進程能夠處理多個請求,每進來一個request,會有一個worker進程去處理。但不是全程的處理,處理到可能發生阻塞的地方,好比向上遊(後端)服務器轉發request,並等待請求返回。那麼,這個處理的worker繼續處理其餘請求,而一旦上游服務器返回了,就會觸發這個事件,worker纔會來接手,這個request纔會接着往下走。因爲web server的工做性質決定了每一個request的大部份生命都是在網絡傳輸中,實際上花費在server機器上的時間片很少。這是幾個進程就解決高併發的祕密所在。即@skoo所說的webserver恰好屬於網絡io密集型應用,不算是計算密集型。
五、請解釋Nginx如何處理HTTP請求?
Nginx使用反應器模式。主事件循環等待操做系統發出準備事件的信號,這樣數據就能夠從套接字讀取,在該實例中讀取到緩衝區並進行處理。單個線程能夠提供數萬個併發鏈接。
六、在Nginx中,如何使用未定義的服務器名稱來阻止處理請求?
只需將請求刪除的服務器就能夠定義爲:Server {listen 80; server_name 「 「 ;return 444;}這裏,服務器名被保留爲一個空字符串,它將在沒有「主機」頭字段的狀況下匹配請求,而一個特殊的Nginx的非標準代碼444被返回,從而終止鏈接。七、 使用「反向代理服務器」的優勢是什麼?答:反向代理服務器能夠隱藏源服務器的存在和特徵。它充當互聯網雲和web服務器之間的中間層。這對於安全方面來講是很好的,特別是當您使用web託管服務時。
八、請列舉Nginx服務器的最佳用途?
Nginx服務器的最佳用法是在網絡上部署動態HTTP內容,使用SCGI、WSGI應用程序服務器、用於腳本的FastCGI處理程序。它還能夠做爲負載均衡器。
九、請解釋Nginx服務器上的Master和Worker進程分別是什麼?
Master進程:讀取及評估配置和維持Worker進程:處理請求
十、請解釋你如何經過不一樣於80的端口開啓Nginx?
爲了經過一個不一樣的端口開啓Nginx,你必須進入/etc/Nginx/sites-enabled/,若是這是默認文件,那麼你必須打開名爲「default」的文件。編輯文件,並放置在你想要的端口:Like server {listen 81;}
十一、請解釋是否有可能將Nginx的錯誤替換爲502錯誤、503?
502 =錯誤網關 503 =服務器超載 有可能,可是您能夠確保fastcgi_intercept_errors被設置爲ON,並使用錯誤頁面指令。Location / { fastcgi_pass 127.0.01:9001; fastcgi_intercept_errors on; error_page 502 =503/error_page.html; #… }
十二、在Nginx中,解釋如何在URL中保留雙斜線?答:要在URL中保留雙斜線,就必須使用merge_slashes_off;語法:merge_slashes [on/off]默認值: merge_slashes on環境: http,server
1三、請解釋ngx_http_upstream_module的做用是什麼?
ngx_http_upstream_module用於定義可經過fastcgi傳遞、proxy傳遞、uwsgi傳遞、memcached傳遞和scgi傳遞指令來引用的服務器組。
1四、請解釋什麼是C10K問題?C10K問題是指沒法同時處理大量客戶端(10,000)的網絡套接字。
1五、請陳述stub_status和sub_filter指令的做用是什麼?
1)Stub_status指令:該指令用於瞭解Nginx當前狀態的當前狀態,如當前的活動鏈接,接受和處理當前讀/寫/等待鏈接的總數 2)Sub_filter指令:它用於搜索和替換響應中的內容,並快速修復陳舊的數據
1六、解釋Nginx是否支持將請求壓縮到上游?
您能夠使用Nginx模塊gunzip將請求壓縮到上游。gunzip模塊是一個過濾器,它能夠對不支持「gzip」編碼方法的客戶機或服務器使用「內容編碼:gzip」來解壓縮響應。
1七、解釋如何在Nginx中得到當前的時間?要得到Nginx的當前時間,必須使用SSI模塊、$date_gmt和$date_local的變量。Proxy_set_header THE-TIME $date_gmt;
1八、用Nginx服務器解釋-s的目的是什麼?用於運行Nginx -s參數的可執行文件。
1九、解釋如何在Nginx服務器上添加模塊?在編譯過程當中,必須選擇Nginx模塊,由於Nginx不支持模塊的運行時間選擇。
20、什麼是反向代理和正向代理?
正向代理:被代理的是客戶端,好比經過XX代理訪問國外的某些網站,實際上客戶端沒有權限訪問國外的網站,客戶端請求XX代理服務器,XX代理服務器訪問國外網站,將國外網站返回的內容傳給真正的用戶。用戶對於服務器是隱藏的,服務器並不知道真實的用戶。
反向代理:被代理的是服務器,也就是客戶端訪問了一個所謂的服務器,服務器會將請求轉發給後臺真實的服務器,真實的服務器作出響應,經過代理服務器將結果返給客戶端。服務器對於用戶來講是隱藏的,用戶不知道真實的服務器是哪一個。
關於正向代理和反向代理,聽起來比較繞,仔細理解,體會也不難明白究竟是什麼意思。
用nginx作實現服務的高可用,nginx自己可能成爲單點,碰見的兩種解決方案,一種是公司搭建本身的DNS,將請求解析到不一樣的NGINX,另外一隻是配合keepalive實現服務的存活檢測。
Fastdfs:
簡單介紹一下FastDFS?
1.開源的分佈式文件系統,主要對文件進行存儲、同步、上傳、下載,有本身的容災備份、負載均衡、線性擴容機制;
2.FastDFS架構主要包含Tracker(跟蹤) server和Storage(組,卷) server。客戶端請求Tracker server進行文件上傳、下載的時候,經過Tracker server調度最終由Storage server完成文件上傳和下載。
3.Tracker server:跟蹤器或者調度器,主要起負載均衡和調度做用。經過Tracker server在文件上傳時能夠根據一些策略找到Storage server提供文件上傳服務。
Storage server:存儲服務器,做用主要是文件存儲,完成文件管理的全部功能。客戶端上傳的文件主要保存在Storage server上,Storage server沒有實現本身的文件系統而是利用操做系統的文件系統去管理文件。
存儲服務器採用了分組/分卷的組織方式。
整個系統由一個組或者多個組組成;
組與組之間的文件是相互獨立的;
全部組的文件容量累加就是整個存儲系統的文件容量;
一個組能夠由多臺存儲服務器組成,一個組下的存儲服務器中的文件都是相同的,組中的多臺存儲服務器起到了冗餘備份和負載均衡的做用;
在組內增長服務器時,若是須要同步數據,則由系統自己完成,同步完成以後,系統自動將新增的服務器切換到線上提供使用;
當存儲空間不足或者耗盡時,能夠動態的添加組。只須要增長一臺服務器,併爲他們配置一個新的組,即擴大了存儲系統的容量。
咱們在項目中主要使用fastdfs來存儲整個項目的圖片。
爲何要使用FastDFS做爲大家的圖片服務器?
首先基於fastDFS的特色:存儲空間可擴展、提供了統一的訪問方式、訪問效率高、容災性好 等特色,再結合咱們項目中圖片的容量大、併發大等特色,所以咱們選擇了FastDFS做爲咱們的圖片服務器;
Nginx也能夠做爲一臺圖片服務器來使用,由於nginx能夠做爲一臺http服務器來使用,做爲網頁靜態服務器,經過location標籤配置;在公司中有的時候也用ftp做爲圖片服務器來使用。
FastDFS中文件上傳下載的具體流程?
客戶端上傳文件後生成一個file_id,返回給客戶端,客戶端利用這個file_id結合ip地址,生成一個完成圖片的url,保存在數據庫中。生成的那個file_id用於之後訪問該文件的索引信息。
FastDFS文件下載的流程
ActiveMQ:
什麼是activemq
activeMQ是一種開源的,面向消息的中間件,用來系統之間進行通訊的
activemq的原理
原理就是生產者生產消息, 把消息發送給activemq。 Activemq 接收到消息, 而後查看有多少個消費者, 而後把消息轉發給消費者, 此過程當中生產者無需參與。 消費者接收到消息後作相應的處理和生產者沒有任何關係
對比RabbitMQ
RabbitMQ的協議是AMQP,而ActiveMQ使用的是JMS協議。顧名思義JMS是針對Java體系的傳輸協議,隊列兩端必須有JVM,因此若是開發環境都是java的話推薦使用ActiveMQ,能夠用Java的一些對象進行傳遞好比Map、Blob(二進制大數據)、Stream等。而AMQP通用行較強,非java環境常用,傳輸內容就是標準字符串。
另一點就是RabbitMQ用Erlang開發,安裝前要裝Erlang環境,比較麻煩。ActiveMQ解壓便可用不用任何安裝。
對比KafKa
Kafka性能超過ActiveMQ等傳統MQ工具,集羣擴展性好。
弊端是:
在傳輸過程當中可能會出現消息重複的狀況,
不保證發送順序
一些傳統MQ的功能沒有,好比消息的事務功能。
因此一般用Kafka處理大數據日誌。
對比Redis
其實Redis自己利用List能夠實現消息隊列的功能,可是功能不多,並且隊列體積較大時性能會急劇降低。對於數據量不大、業務簡單的場景能夠使用。
如何解決消息重複問題
所謂消息重複,就是消費者接收到了重複的消息,通常來講咱們對於這個問題的處理要把握下面幾點,
①.消息不丟失(上面已經處理了)
②.消息不重複執行
通常來講咱們能夠在業務段加一張表,用來存放消息是否執行成功,每次業務事物commit以後,告知服務端,已經處理過該消息,
這樣即便你消息重發了,也不會致使重複處理
大體流程以下:
業務端的表記錄已經處理消息的id,每次一個消息進來以前先判斷該消息是否執行過,若是執行過就放棄,若是沒有執行就開始執行消息,消息執行完成以後存入這個消息的id
關於事務控制
獲取session連接的時候 設置參數 默認不開啓
producer提交時的事務 |
事務開啓 |
只執行send並不會提交到隊列中,只有當執行session.commit()時,消息才被真正的提交到隊列中。 |
事務不開啓 |
只要執行send,就進入到隊列中。 |
|
consumer 接收時的事務 |
事務開啓,簽收必須寫 Session.SESSION_TRANSACTED
|
收到消息後,消息並無真正的被消費。消息只是被鎖住。一旦出現該線程死掉、拋異常,或者程序執行了session.rollback()那麼消息會釋放,從新回到隊列中被別的消費端再次消費。 |
事務不開啓,簽收方式選擇 Session.AUTO_ACKNOWLEDGE |
只要調用comsumer.receive方法 ,自動確認。 |
|
事務不開啓,簽收方式選擇 Session.CLIENT_ACKNOWLEDGE |
須要客戶端執行 message.acknowledge(),不然視爲未提交狀態,線程結束後,其餘線程還能夠接收到。 這種方式跟事務模式很像,區別是不能手動回滾,並且能夠單獨確認某個消息。 手動簽收 |
|
事務不開啓,簽收方式選擇 Session.DUPS_OK_ACKNOWLEDGE |
在Topic模式下作批量簽收時用的,能夠提升性能。可是某些狀況消息可能會被重複提交,使用這種模式的consumer要能夠處理重複提交的問題。
|
持久化與非持久化
經過producer.setDeliveryMode(DeliveryMode.PERSISTENT) 進行設置
持久化的好處就是當activemq宕機的話,消息隊列中的消息不會丟失。非持久化會丟失。可是會消耗必定的性能。
分佈式 、高併發、集羣、負載均衡、高可用
分佈式 :
分佈式架構:把系統按照模塊拆分紅多個子系統,多個子系統分佈在不一樣的網絡計算機上相互協做完成業務流程,系統之間須要進行通訊。
優勢:
把模塊拆分,使用接口通訊,下降模塊之間的耦合度。
把項目拆分紅若干個子項目,不一樣的團隊負責不一樣的子項目。
增長功能時只須要再增長一個子項目,調用其餘系統的接口就能夠。
能夠靈活的進行分佈式部署。
缺點:
一、系統之間交互須要使用遠程通訊,接口開發增長工做量。
二、各個模塊有一些通用的業務邏輯沒法共用。
基於soa的架構
SOA:面向服務的架構。也就是把工程拆分紅服務層、表現層兩個工程。服務層中包含業務邏輯,只須要對外提供服務便可。表現層只須要處理和頁面的交互,業務邏輯都是調用服務層的服務來實現。
分佈式架構和soa架構有什麼區別?
SOA,主要仍是從服務的角度,將工程拆分紅服務層、表現層兩個工程。
分佈式,主要仍是從部署的角度,將應用按照訪問壓力進行歸類,主要目標是充分利用服務器的資源,避免資源分配不均
集羣:
一個集羣系統是一羣鬆散結合的服務器組,造成一個虛擬的服務器,爲客戶端用戶提供統一的服務。對於這個客戶端來講,一般在訪問集羣系統時不會意識到它的服務是由具體的哪一臺服務器提供。集羣的目的,是爲實現負載均衡、容錯和災難恢復。以達到系統可用性和可伸縮性的要求。集羣系統通常應具高可用性、可伸縮性、負載均衡、故障恢復和可維護性等特殊性能。通常同一個工程會部署到多臺服務器上。
常見的tomcat集羣,Redis集羣,Zookeeper集羣,數據庫集羣
分佈式與集羣的區別:
分佈式是指將不一樣的業務分佈在不一樣的地方。 而集羣指的是將幾臺服務器集中在一塊兒,實現同一業務。一句話:分佈式是並聯工做的,集羣是串聯工做的。
分佈式中的每個節點,均可以作集羣。 而集羣並不必定就是分佈式的。
舉例:就好比新浪網,訪問的人多了,他能夠作一個羣集,前面放一個響應服務器,後面幾臺服務器完成同一業務,若是有業務訪問的時候,響應服務器看哪臺服務器的負載不是很重,就將給哪一臺去完成。
而分佈式,從窄意上理解,也跟集羣差很少, 可是它的組織比較鬆散,不像集羣,有一個組織性,一臺服務器垮了,其它的服務器能夠頂上來。
分佈式的每個節點,都完成不一樣的業務,一個節點垮了,哪這個業務就不可訪問了。
分佈式是以縮短單個任務的執行時間來提高效率的,而集羣則是經過提升單位時間內執行的任務數來提高效率。
舉例:若是一個任務由10個子任務組成,每一個子任務單獨執行需1小時,則在一臺服務器上執行該任務需10小時。
採用分佈式方案,提供10臺服務器,每臺服務器只負責處理一個子任務,不考慮子任務間的依賴關係,執行完這個任務只需一個小時。(這種工做模式的一個典型表明就是Hadoop的Map/Reduce分佈式計算模型)
而採用集羣方案,一樣提供10臺服務器,每臺服務器都能獨立處理這個任務。假設有10個任務同時到達,10個服務器將同時工做,1小時後,10個任務同時完成,這樣,整身來看,仍是1小時內完成一個任務!
高併發:
處理高併發常見的方法有哪些?
一、HTML靜態化 freemaker
其實你們都知道,效率最高、消耗最小的就是純靜態化的html頁面,因此咱們儘量使咱們的網站上的頁面採 用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。可是對於大量內容而且頻繁更新的網站,咱們沒法所有手動去挨個實現,因而出現了咱們常見的信息 發佈系統CMS,像咱們常訪問的各個門戶站點的新聞頻道,甚至他們的其餘頻道,都是經過信息發佈系統來管理和實現的,信息發佈系統能夠實現最簡單的信息錄 入自動生成靜態頁面,還能具有頻道管理、權限管理、自動抓取等功能,對於一個大型網站來講,擁有一套高效、可管理的CMS是必不可少的。
除了門戶和信息發佈類型的網站,對於交互性要求很高的社區類型網站來講,儘量的靜態化也是提升性能的必要手段,將社區內的帖子、文章進行實時的靜態化,有更新的時候再從新靜態化也是大量使用的策略,像Mop的大雜燴就是使用了這樣的策略,網易社區等也是如此。
同 時,html靜態化也是某些緩存策略使用的手段,對於系統中頻繁使用數據庫查詢可是內容更新很小的應用,能夠考慮使用html靜態化來實現,好比論壇中論 壇的公用設置信息,這些信息目前的主流論壇均可以進行後臺管理而且存儲再數據庫中,這些信息其實大量被前臺程序調用,可是更新頻率很小,能夠考慮將這部分 內容進行後臺更新的時候進行靜態化,這樣避免了大量的數據庫訪問請求。
二、圖片服務器分離
你們知道,對於Web服務器來講,無論 是 Apache、IIS仍是其餘容器,圖片是最消耗資源的,因而咱們有必要將圖片與頁面進行分離,這是基本上大型網站都會採用的策略,他們都有獨立的圖片服 務器,甚至不少臺圖片服務器。這樣的架構能夠下降提供頁面訪問請求的服務器系統壓力,而且能夠保證系統不會由於圖片問題而崩潰,在應用服務器和圖片服務器 上,能夠進行不一樣的配置優化,好比apache在配置ContentType的時候能夠儘可能少支持,儘量少的LoadModule,保證更高的系統消耗 和執行效率。
三、數據庫集羣和庫表散列
大型網站都有複雜的應用,這些應用必須使用數據庫,那麼在面對大量訪問的時候,數據庫的瓶頸很快就能顯現出來,這時一臺數據庫將很快沒法知足應用,因而咱們須要使用數據庫集羣或者庫表散列。
在數據庫集羣方面,不少數據庫都有本身的解決方案,Oracle、Sybase等都有很好的方案,經常使用的MySQL提供的Master/Slave也是相似的方案,您使用了什麼樣的DB,就參考相應的解決方案來實施便可。
上 面提到的數據庫集羣因爲在架構、成本、擴張性方面都會受到所採用DB類型的限制,因而咱們須要從應用程序的角度來考慮改善系統架構,庫表散列是經常使用而且最 有效的解決方案。咱們在應用程序中安裝業務和應用或者功能模塊將數據庫進行分離,不一樣的模塊對應不一樣的數據庫或者表,再按照必定的策略對某個頁面或者功能 進行更小的數據庫散列,好比用戶表,按照用戶ID進行表散列,這樣就可以低成本的提高系統的性能而且有很好的擴展性。sohu的論壇就是採用了這樣的架 構,將論壇的用戶、設置、帖子等信息進行數據庫分離,而後對帖子、用戶按照板塊和ID進行散列數據庫和表,最終能夠在配置文件中進行簡單的配置便能讓系統 隨時增長一臺低成本的數據庫進來補充系統性能。
四、緩存
緩存一詞搞技術的都接觸過,不少地方用到緩存。網站架構和網站開發中的緩存也是很是重要。這裏先講述最基本的兩種緩存。高級和分佈式的緩存在後面講述。
架構方面的緩存,對Apache比較熟悉的人都能知道Apache提供了本身的緩存模塊,也能夠使用外加的Squid模塊進行緩存,這兩種方式都可以有效的提升Apache的訪問響應能力。
網 站程序開發方面的緩存,Linux上提供的Memory Cache是經常使用的緩存接口,能夠在web開發中使用,好比用Java開發的時候就能夠調用MemoryCache對一些數據進行緩存和通信共享,一些大 型社區使用了這樣的架構。另外,在使用web語言開發的時候,各類語言基本都有本身的緩存模塊和方法,PHP有Pear的Cache模塊,Java就更多 了,.net不是很熟悉,相信也確定有。
五、鏡像
鏡像是大型網站常採用的提升性能和數據安全性的方式,鏡像的技術能夠解決不一樣網 絡接入商和地域帶來的用戶訪問速度差別,好比ChinaNet和EduNet之間的差別就促使了不少網站在教育網內搭建鏡像站點,數據進行定時更新或者實 時更新。在鏡像的細節技術方面,這裏不闡述太深,有不少專業的現成的解決架構和產品可選。也有廉價的經過軟件實現的思路,好比Linux上的rsync等 工具。
六、負載均衡
負載均衡將是大型網站解決高負荷訪問和大量併發請求採用的終極解決辦法。
負載均衡技術發展了多年,有不少專業的服務提供商和產品能夠選擇,我我的接觸過一些解決方法,其中有兩個架構能夠給你們作參考。
高可用:
一般企業級應用系統(特別是政府部門和大企業的應用系統)通常會採用安規的軟硬件設備,如IOE(IBM的小型機、Oracle數據、EMC存儲設備)系列。而通常互聯網公司更多地採用PC級服務器(x86),開源的數據庫(MySQL)和操做系統(Linux)組建廉價且高容錯(硬件故障是常態)的應用集羣。
(1)設計的目的?
保證服務器硬件故障服務依然可用,數據依然保存並可以被訪問。
(2)主要的手段?
數據和服務的①冗餘備份以及②失效轉移:
對於服務而言,一旦某個服務器宕機,就將服務切換到其餘可用的服務器上;
對於數據而言,若是某個磁盤損壞,就從備份的磁盤(事先就作好了數據的同步複製)讀取數據。
高可用的服務
高可用的服務模塊爲業務產品提供基礎公共服務,在大型站點中這些服務一般都獨立分佈式部署,被具體應用遠程調用。
在具體實踐中,有如下幾點高可用的服務策略能夠參考:
①分級管理:核心應用和服務具備更高的優先級,好比用戶及時付款比可否評價商品更重要;
②超時設置:設置服務調用的超時時間,一旦超時後,通訊框架拋出異常,應用程序則根據服務調度策略選擇重試or請求轉移到其餘服務器上;
③異步調用:經過消息隊列等異步方式完成,避免一個服務失敗致使整個應用請求失敗的狀況。
不是全部服務均可以異步調用,對於獲取用戶信息這類調用,採用異步方式會延長響應時間,得不償失。對於那些必須確認服務調用成功後才能繼續進行下一步的操做的應用也不適合異步調用。
④服務降級:網站訪問高峯期間,爲了保證核心應用的正常運行,須要對服務降級。
降級有兩種手段:一是拒絕服務,拒絕較低優先級的應用的調用,減小服務調用併發數,確保核心應用的正常運行;二是關閉功能,關閉部分不重要的服務,或者服務內部關閉部分不重要的功能,以節約系統開銷,爲核心應用服務讓出資源;
⑤冪等性設計:保證服務重複調用和調用一次產生的結果相同;
高可用的數據
保證數據高可用的主要手段有兩種:一是數據備份,二是失效轉移機制;
①數據備份:又分爲冷備份和熱備份,冷備份是按期複製,不能保證數據可用性。熱備份又分爲異步熱備和同步熱備,異步熱備是指多份數據副本的寫入操做異步完成,而同步方式則是指多份數據副本的寫入操做同時完成。
關係數據庫的熱備機制就是一般所說的主從同步機制,實踐中一般使用讀寫分離的方法來訪問Master和Slave數據庫,也就是說寫操做只訪問Master庫,讀操做均訪問Slave庫。
②失效轉移:若數據服務器集羣中任何一臺服務器宕機,那麼應用程序針對這臺服務器的全部讀寫操做都要從新路由到其餘服務器,保證數據訪問不會失敗。
網站運行監控
」不容許沒有監控的系統上線「
(1)監控數據採集
①用戶行爲日誌收集:服務器端的日誌收集和客戶端的日誌收集;目前許多網站逐步開發基於實時計算框架Storm的日誌統計與分析工具;
②服務器性能監控:收集服務器性能指標,如系統Load、內存佔用、磁盤IO等,及時判斷,防患於未然;
③運行數據報告:採集並報告,彙總後統一顯示,應用程序須要在代碼中處理運行數據採集的邏輯;
(2)監控管理
①系統報警:配置報警閥值和值守人員聯繫方式,系統發生報警時,即便工程師在千里以外,也能夠被及時通知;
②失效轉移:監控系統在發現故障時,主動通知應用進行失效轉移;
③自動優雅降級:爲了應付網站訪問高峯,主動關閉部分功能,釋放部分系統資源,保證核心應用服務的正常運行;—>網站柔性架構的理想狀態
主從切換
很好理解,當其中一臺機器的服務宕機後,對於服務調用者來講,可以迅速的切換到其餘可用服務,從服務升級爲主服務,這種切換速度應當控制在秒級別(幾秒鐘)。
當宕機的服務恢復以後,自動變爲從服務,主從服務角色切換。主從切換必定是要付出代價的,因此當主服務恢復以後,也就再也不替換現有的主服務。
負載均衡
當服務的請求量比較高的時候,一臺服務不能知足需求,這時候須要多臺機器提供一樣的服務,將全部請求分發到不一樣機器上。
高可用架構中應該具備豐富的負載均衡策略和易調節負載的方式。
甚至能夠自動化智能調節,例如因爲機器性能的緣由,響應時間可能不同,這時候能夠向性能差的機器少一點分發量,保證各個機器響應時間的均衡。
易橫向擴展
當用戶量愈來愈多,已有服務不能承載更多的用戶的時候,便須要對服務進行擴展,擴展的方式最好是不觸動原有服務,對於服務的調用者是透明的。
負載均衡:
1.什麼是負載均衡?
當一臺服務器的性能達到極限時,咱們能夠使用服務器集羣來提升網站的總體性能。那麼,在服務器集羣中,須要有一臺服務器充當調度者的角色,用戶的全部請求都會首先由它接收,調度者再根據每臺服務器的負載狀況將請求分配給某一臺後端服務器去處理。
那麼在這個過程當中,調度者如何合理分配任務,保證全部後端服務器都將性能充分發揮,從而保持服務器集羣的總體性能最優,這就是負載均衡問題。
下面詳細介紹負載均衡的實現方式。
(1)HTTP重定向負載均衡。
這種負載均衡方案的優勢是比較簡單;
缺點是瀏覽器須要每次請求兩次服務器才能拿完成一次訪問,性能較差。
(2)DNS域名解析負載均衡
優勢是將負載均衡工做交給DNS,省略掉了網絡管理的麻煩;
缺點就是DNS可能緩存A記錄,不受網站控制。
(3)反向代理負載均衡。
優勢是部署簡單;
缺點是反向代理服務器是全部請求和響應的中轉站,其性能可能會成爲瓶頸。
(4)IP負載均衡。
優勢:IP負載均衡在內核進程完成數據分發,較反向代理均衡有更好的處理性能。
缺點:負載均衡的網卡帶寬成爲系統的瓶頸。
(5)數據鏈路層負載均衡。
避免負載均衡服務器網卡帶寬成爲瓶頸,是目前大型網站所使用的最廣的一種負載均衡手段。
當用戶向服務器發起請求時,請求首先被集羣調度者截獲;調度者根據某種分配策略,選擇一臺服務器,並將選中的服務器的IP地址封裝在HTTP響應消息頭部的Location字段中,並將響應消息的狀態碼設爲302,最後將這個響應消息返回給瀏覽器。
當瀏覽器收到響應消息後,解析Location字段,並向該URL發起請求,而後指定的服務器處理該用戶的請求,最後將結果返回給用戶。
在使用HTTP重定向來實現服務器集羣負載均衡的過程當中,須要一臺服務器做爲請求調度者。用戶的一項操做須要發起兩次HTTP請求,一次向調度服務器發送請求,獲取後端服務器的IP,第二次向後端服務器發送請求,獲取處理結果。
調度服務器收到用戶的請求後,究竟選擇哪臺後端服務器處理請求,這由調度服務器所使用的調度策略決定。
隨機分配策略
當調度服務器收到用戶請求後,能夠隨機決定使用哪臺後端服務器,而後將該服務器的IP封裝在HTTP響應消息的Location屬性中,返回給瀏覽器便可。
輪詢策略(RR)
調度服務器須要維護一個值,用於記錄上次分配的後端服務器的IP。那麼當新的請求到來時,調度者將請求依次分配給下一臺服務器。
因爲輪詢策略須要調度者維護一個值用於記錄上次分配的服務器IP,所以須要額外的開銷;此外,因爲這個值屬於互斥資源,那麼當多個請求同時到來時,爲了不線程的安全問題,所以須要鎖定互斥資源,從而下降了性能。而隨機分配策略不須要維護額外的值,也就不存在線程安全問題,所以性能比輪詢要高。
優缺點分析
採用HTTP重定向來實現服務器集羣的負載均衡實現起來較爲容易,邏輯比較簡單,但缺點也較爲明顯。
在HTTP重定向方法中,調度服務器只在客戶端第一次向網站發起請求的時候起做用。當調度服務器向瀏覽器返回響應信息後,客戶端此後的操做都基於新的URL進行的(也就是後端服務器),此後瀏覽器就不會與調度服務器產生關係,進而會產生以下幾個問題:
因爲不一樣用戶的訪問時間、訪問頁面深度有所不一樣,從而每一個用戶對各自的後端服務器所形成的壓力也不一樣。而調度服務器在調度時,沒法知道當前用戶將會對服務器形成多大的壓力,所以這種方式沒法實現真正意義上的負載均衡,只不過是把請求次數平均分配給每臺服務器罷了。
若分配給該用戶的後端服務器出現故障,而且若是頁面被瀏覽器緩存,那麼當用戶再次訪問網站時,請求都會發給出現故障的服務器,從而致使訪問失敗。
DNS負載均衡
DNS是什麼?
瞭解DNS負載均衡以前,咱們首先須要瞭解DNS域名解析的過程。
咱們知道,數據包採用IP地址在網絡中傳播,而爲了方便用戶記憶,咱們使用域名來訪問網站。那麼,咱們經過域名訪問網站以前,首先須要將域名解析成IP地址,這個工做是由DNS完成的。也就是域名服務器。
咱們提交的請求不會直接發送給想要訪問的網站,而是首先發給域名服務器,它會幫咱們把域名解析成IP地址並返回給咱們。咱們收到IP以後纔會向該IP發起請求。
那麼,DNS服務器有一個自然的優點,若是一個域名指向了多個IP地址,那麼每次進行域名解析時,DNS只要選一個IP返回給用戶,就可以實現服務器集羣的負載均衡。
具體作法
首先須要將咱們的域名指向多個後端服務器(將一個域名解析到多個IP上),再設置一下調度策略,那麼咱們的準備工做就完成了,接下來的負載均衡就徹底由DNS服務器來實現。
當用戶向咱們的域名發起請求時,DNS服務器會自動地根據咱們事先設定好的調度策略選一個合適的IP返回給用戶,用戶再向該IP發起請求。
調度策略
通常DNS提供商會提供一些調度策略供咱們選擇,如隨機分配、輪詢、根據請求者的地域分配離他最近的服務器。
優缺點分析
DNS負載均衡最大的優勢就是配置簡單。服務器集羣的調度工做徹底由DNS服務器承擔,那麼咱們就能夠把精力放在後端服務器上,保證他們的穩定性與吞吐量。並且徹底不用擔憂DNS服務器的性能,即使是使用了輪詢策略,它的吞吐率依然卓越。
此外,DNS負載均衡具備較強了擴展性,你徹底能夠爲一個域名解析較多的IP,並且不用擔憂性能問題。
可是,因爲把集羣調度權交給了DNS服務器,從而咱們沒辦法爲所欲爲地控制調度者,沒辦法定製調度策略。
DNS服務器也沒辦法瞭解每臺服務器的負載狀況,所以沒辦法實現真正意義上的負載均衡。它和HTTP重定向同樣,只不過把全部請求平均分配給後端服務器罷了。
此外,當咱們發現某一臺後端服務器發生故障時,即便咱們當即將該服務器從域名解析中去除,但因爲DNS服務器會有緩存,該IP仍然會在DNS中保留一段時間,那麼就會致使一部分用戶沒法正常訪問網站。這是一個致命的問題!好在這個問題能夠用動態DNS來解決。
動態DNS
動態DNS可以讓咱們經過程序動態修改DNS服務器中的域名解析。從而當咱們的監控程序發現某臺服務器掛了以後,能當即通知DNS將其刪掉。
DNS負載均衡是一種粗獷的負載均衡方法,這裏只作介紹,不推薦使用。
反向代理服務器是一個位於實際服務器以前的服務器,全部向咱們網站發來的請求都首先要通過反向代理服務器,服務器根據用戶的請求要麼直接將結果返回給用戶,要麼將請求交給後端服務器處理,再返回給用戶。
以前咱們介紹了用反向代理服務器實現靜態頁面和經常使用的動態頁面的緩存。接下來咱們介紹反向代理服務器更經常使用的功能——實現負載均衡。
咱們知道,全部發送給咱們網站的請求都首先通過反向代理服務器。那麼,反向代理服務器就能夠充當服務器集羣的調度者,它能夠根據當先後端服務器的負載狀況,將請求轉發給一臺合適的服務器,並將處理結果返回給用戶。
優勢
隱藏後端服務器。
與HTTP重定向相比,反向代理可以隱藏後端服務器,全部瀏覽器都不會與後端服務器直接交互,從而可以確保調度者的控制權,提高集羣的總體性能。
故障轉移
與DNS負載均衡相比,反向代理可以更快速地移除故障結點。當監控程序發現某一後端服務器出現故障時,可以及時通知反向代理服務器,並當即將其刪除。
合理分配任務
HTTP重定向和DNS負載均衡都沒法實現真正意義上的負載均衡,也就是調度服務器沒法根據後端服務器的實際負載狀況分配任務。但反向代理服務器支持手動設定每臺後端服務器的權重。咱們能夠根據服務器的配置設置不一樣的權重,權重的不一樣會致使被調度者選中的機率的不一樣。
缺點
調度者壓力過大
因爲全部的請求都先由反向代理服務器處理,那麼當請求量超過調度服務器的最大負載時,調度服務器的吞吐率下降會直接下降集羣的總體性能。
制約擴展
當後端服務器也沒法知足巨大的吞吐量時,就須要增長後端服務器的數量,可沒辦法無限量地增長,由於會受到調度服務器的最大吞吐量的制約。
反向代理服務器會引發一個問題。若某臺後端服務器處理了用戶的請求,並保存了該用戶的session或存儲了緩存,那麼當該用戶再次發送請求時,沒法保證該請求仍然由保存了其Session或緩存的服務器處理,若由其餘服務器處理,先前的Session或緩存就找不到了。
解決辦法1:
能夠修改反向代理服務器的任務分配策略,以用戶IP做爲標識較爲合適。相同的用戶IP會交由同一臺後端服務器處理,從而就避免了粘滯會話的問題。
解決辦法2:
能夠在Cookie中標註請求的服務器ID,當再次提交請求時,調度者將該請求分配給Cookie中標註的服務器處理便可。
基於IP的負載均衡方式
1.經過NAT實現負載均衡
運做過程
客戶端會向一個ip地址發出請求,這個ip地址是一個VIP(虛擬IP),這也是調度器向外公佈的一個地址。
請求達到調度器,調度器會根據負載均衡算法(詳情請見8種負載均衡算法)從RealServer列表中選取一個負載不高的服務器,而後把請求報文的目標地址,也就是VIP和端口經過iptables進行NAT轉換成選中的服務器的真實ip地址。最後,調度器會把其鏈接保存在一個hash表中,只要這個鏈接下次再發請求報文過來就會把其分發到上次選定的服務器中。
RealServer收到報文以後,會把響應返回給調度器。
調度器收到報文以後,會把源地址和源端口改成虛擬ip和端口,最後再返回給客戶端。
特色
1.RealServer和調度器必須位於一個ip網絡之中。
2.調度器位於RealServer和客戶端之間,處理進出的通訊。
3.RIP一般是內部地址,僅用於集羣之間通訊。
4.RealServer的網關必須指向調度器。
5.支持端口映射,RealServer不必跟調度器一個端口。
限制
響應報文通常比較大,每一次都須要NAT轉換的話,大流量的時候,會致使調度器成爲一個瓶頸。
配圖
image.png
2.經過直接路由實現負載均衡
描述
因爲網絡請求有一個特色,就是響應報文每每都是比請求報文大不少的,這就會形成上面的nat每次轉發收到機器負載的影響,會成爲這個請求的一個瓶頸。所以VS/DR這個方案能夠經過直接路由的方式,只轉發請求,而相應則由RealServer去直接響應給客戶端,這樣能夠極高提升吞吐量。
運做過程
客戶端請求一個VIP,這個ip地址就是調度器對外公佈的地址。
請求到達調度器以後,調度器根據負載算法去調度請求,分發給特定的RealServer,調度器不會修改ip和端口,只會mac地址改成把選出的RealServer的mac地址,RealServer將會收到對應的報文。
RealServer收到報文以後,發現報文的目標地址VIP,處理結束以後,會經過路由表將響應返回給客戶端。
特色
集羣節點,RealServer和調度器要在同一個物理網絡之中。
RIP一般是私有網絡,固然也能夠是公開網絡,方便監控和管理。
調度器只負責調度請求,響應會由服務器直接對客戶端進行響應。
RealServer不能指向調度器的網關。
不支持端口映射。
3. VS/TUN 實現虛擬服務器
描述:因爲VS/DR限制RealServer和調度器在同一個物理網絡,所以沒法分散在各地,VS/TUN就能解決這個問題。
運做過程:
1.客戶端經過VIP發送請求,經過一個ip隧道,將一個ip報文封裝到另外一個ip報文,這樣可讓目標爲一個ip的地址數據轉發到另外一個ip地址。
2.調度器根據負載均衡算法去選擇一臺RealServer,再把封裝後的ip報文發送過去。
3.RealServer獲取到報文以後解封報文,獲取到原來目標爲VIP的報文,服務器發現這個VIP是位於本地的IP隧道中就會處理這個這個請求,並經過路由表去把響應報文直接回復給客戶端。
特色:
RealServer和調度器必須能夠公網訪問。
RIP必須是公網地址。
調度器只分配和轉發請求給RealServer,響應報文則由RealSever直接響應給客戶端。
RealServer的網關不能指向調度器。
不支持端口映射。
數據鏈路層負載均衡其實也就是網卡的負載均衡,在下面的應用狀況下,就要考慮對網卡進行負載均衡:
某個服務器跑的應用非高峯期間都能達到500M以上,晚高峯通常可以超過1G,主流服務器的網卡都是千兆的,超過1G的流量明顯會致使丟包的問題,此時又不能中止業務對網卡進行更換,因此必須在增長一個網卡來聯合提供服務,因此就必須把多張網卡捆綁作成一個邏輯網卡。
對網卡的高可用性要求,某些業務必需要求網卡層面的高可用性,因此必須捆綁多個網卡。
對於linux系統來講,數據鏈路層的解決方案就是實現多個網卡綁定,即linux bonding,在思科交換機上這稱爲以太網通道(Ether Channel)
linux bonding
第一種模式:mod=0 ,即:(balance-rr) Round-robin policy(平衡掄循環策略)
特色:傳輸數據包順序是依次傳輸(即:第1個包走eth0,下一個包就走eth1….一直循環下去,直到最後一個傳輸完畢),此模式提供負載平衡和容錯能力;可是咱們知道若是一個鏈接或者會話的數據包從不一樣的接口發出的話,中途再通過不一樣的鏈路,在客戶端頗有可能會出現數據包無序到達的問題,而無序到達的數據包須要從新要求被髮送,這樣網絡的吞吐量就會降低
第二種模式:mod=1,即: (active-backup) Active-backup policy(主-備份策略)
特色:只有一個設備處於活動狀態,當一個宕掉另外一個立刻由備份轉換爲主設備。mac地址是外部可見得,從外面看來,bond的MAC地址是惟一的,以免switch(交換機)發生混亂。此模式只提供了容錯能力;因而可知此算法的優勢是能夠提供高網絡鏈接的可用性,可是它的資源利用率較低,只有一個接口處於工做狀態,在有 N 個網絡接口的狀況下,資源利用率爲1/N
第三種模式:mod=2,即:(balance-xor) XOR policy(平衡策略)
特色:基於指定的傳輸HASH策略傳輸數據包。缺省的策略是:(源MAC地址 XOR 目標MAC地址) % slave數量。其餘的傳輸策略能夠經過xmit_hash_policy選項指定,此模式提供負載平衡和容錯能力
第四種模式:mod=3,即:broadcast(廣播策略)
特色:在每一個slave接口上傳輸每一個數據包,此模式提供了容錯能力
第五種模式:mod=4,即:(802.3ad) IEEE 802.3adDynamic link aggregation(IEEE 802.3ad 動態連接聚合)
特色:建立一個聚合組,它們共享一樣的速率和雙工設定。根據802.3ad規範將多個slave工做在同一個激活的聚合體下。
外出流量的slave選舉是基於傳輸hash策略,該策略能夠經過xmit_hash_policy選項從缺省的XOR策略改變到其餘策略。須要注意的是,並非全部的傳輸策略都是802.3ad適應的,尤爲考慮到在802.3ad標準43.2.4章節說起的包亂序問題。不一樣的實現可能會有不一樣的適應性。
必要條件:
條件1:ethtool支持獲取每一個slave的速率和雙工設定
條件2:switch(交換機)支持IEEE 802.3ad Dynamic link aggregation
條件3:大多數switch(交換機)須要通過特定配置才能支持802.3ad模式
第六種模式:mod=5,即:(balance-tlb) Adaptive transmit load balancing(適配器傳輸負載均衡)
特色:不須要任何特別的switch(交換機)支持的通道bonding。在每一個slave上根據當前的負載(根據速度計算)分配外出流量。若是正在接受數據的slave出故障了,另外一個slave接管失敗的slave的MAC地址。
該模式的必要條件:ethtool支持獲取每一個slave的速率
第七種模式:mod=6,即:(balance-alb) Adaptive load balancing(適配器適應性負載均衡)
特色:該模式包含了balance-tlb模式,同時加上針對IPV4流量的接收負載均衡(receive load balance, rlb),並且不須要任何switch(交換機)的支持。接收負載均衡是經過ARP協商實現的。bonding驅動截獲本機發送的ARP應答,並把源硬件地址改寫爲bond中某個slave的惟一硬件地址,從而使得不一樣的對端使用不一樣的硬件地址進行通訊。
一種是經過硬件來進行進行, 常見的硬件有比較昂貴的NetScaler、F五、Radware和Array等商用的負載均衡器, 也有相似於LVS、Nginx、HAproxy的基於Linux的開源的負載均衡策略, 商用負載均衡裏面NetScaler從效果上比F5的效率上更高。對於負載均衡器來講, 不過商用負載均衡因爲能夠創建在四~七層協議之上,所以適用面更廣因此有其不可替代性, 他的優勢就是有專業的維護團隊來對這些服務進行維護、缺點就是花銷太大, 因此對於規模較小的網絡服務來講暫時尚未須要使用。
另外一種負載均衡的方式是經過軟件:比較常見的有LVS、Nginx、HAproxy等, 其中LVS是創建在四層協議上面的,而另外Nginx和HAproxy是創建在七層協議之上的
LVS:使用集羣技術和Linux操做系統實現一個高性能、高可用的服務器, 它具備很好的可伸縮性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。
一、抗負載能力強、是工做在網絡4層之上僅做分發之用,沒有流量的產生;
二、配置性比較低,這是一個缺點也是一個優勢,由於沒有可太多配置的東西, 因此並不須要太多接觸,大大減小了人爲出錯的概率;
三、工做穩定,自身有完整的雙機熱備方案;
四、無流量,保證了均衡器IO的性能不會收到大流量的影響;
五、應用範圍比較廣,能夠對全部應用作負載均衡;
六、LVS須要向IDC多申請一個IP來作Visual IP,所以須要必定的網絡知識,因此對操做人的要求比較高。
一、工做在網絡的7層之上,能夠針對http應用作一些分流的策略,好比針對域名、目錄結構;
二、Nginx對網絡的依賴比較小;
三、Nginx安裝和配置比較簡單,測試起來比較方便;
四、也能夠承擔高的負載壓力且穩定,通常能支撐超過1萬次的併發;
五、Nginx能夠經過端口檢測到服務器內部的故障, 好比根據服務器處理網頁返回的狀態碼、超時等等, 而且會把返回錯誤的請求從新提交到另外一個節點,不過其中缺點就是不支持url來檢測;
六、Nginx對請求的異步處理能夠幫助節點服務器減輕負載;
七、Nginx能支持http和Email,這樣就在適用範圍上面小不少;
八、不支持Session的保持、對Big request header的支持不是很好, 另外默認的只有Round-robin和IP-hash兩種負載均衡算法。
一、HAProxy是工做在網絡7層之上。
二、可以補充Nginx的一些缺點好比Session的保持,Cookie的引導等工做
三、支持url檢測後端的服務器出問題的檢測會有很好的幫助。
四、更多的負載均衡策略好比:動態加權輪循(Dynamic Round Robin), 加權源地址哈希(Weighted Source Hash), 加權URL哈希和加權參數哈希(Weighted Parameter Hash)已經實現
五、單純從效率上來說HAProxy更會比Nginx有更出色的負載均衡速度。
六、HAProxy能夠對Mysql進行負載均衡,對後端的DB節點進行檢測和負載均衡。
第一階段:利用Nginx或者HAProxy進行單點的負載均衡, 這一階段服務器規模剛脫離開單服務器、單數據庫的模式,須要必定的負載均衡, 可是 仍然規模較小沒有專業的維護團隊來進行維護,也沒有須要進行大規模的網站部署。 這樣利用Nginx或者HAproxy就是第一選擇,此時這些東西上手快, 配置容易, 在七層之上利用HTTP協議就能夠。這時是第一選擇
第二階段:隨着網絡服務進一步擴大,這時單點的Nginx已經不能知足, 這時使用LVS或者商用F5就是首要選擇,Nginx此時就做爲LVS或者 F5的節點來使用, 具體LVS或者F5的是選擇是根據公司規模,人才以及資金能力來選擇的,這裏也不作詳談, 可是通常來講這階段相關人才跟不上業務的提 升,因此購買商業負載均衡已經成爲了必經之路。
第三階段:這時網絡服務已經成爲主流產品,此時隨着公司知名度也進一步擴展, 相關人才的能力以及數量也隨之提高,這時不管從開發適合自身產品的定製, 以及下降成原本講開源的LVS,已經成爲首選,這時LVS會成爲主流。 最終造成比較理想的狀態爲:F5/LVS<—>Haproxy<—>Squid/Varnish<—>AppServer
1.主要應用在門戶網站首頁廣告信息的緩存。由於門戶網站訪問量較大,將廣告緩存到redis中,能夠下降數據庫訪問壓力,提升查詢性能。
2.應用在用戶註冊驗證碼緩存。利用redis設置過時時間,當超過指定時間後,redis清理驗證碼,使過時的驗證碼無效。
3.用在購物車模塊,用戶登錄系統後,添加的購物車數據須要保存到redis緩存中。
redis中對一個key進行自增或者自減操做,它是原子性的嗎?
是原子性的。一個操做的不能夠再分,操做要麼執行,要麼不執行。Redis的操做之因此是原子性的,是由於Redis是單線程的。對Redis來講,執行get、set以及eval等API,都是一個一個的任務,這些任務都會由Redis的線程去負責執行,任務要麼執行成功,要麼執行失敗,這就是Redis的命令是原子性的緣由。Redis自己提供的全部API都是原子操做,Redis中的事務實際上是要保證批量操做的原子性。
a、大數據字段最好剝離出單獨的表,以便影響性能
b、使用varchar,代替char,這是由於varchar會動態分配長度,char指定爲20,即時你存儲字符「1」,它依然是20的長度
c、給表創建主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有必定的影響
d、避免表字段運行爲null,若是不知道添加什麼值,建議設置默認值,特別int類型,好比默認值爲0,在索引查詢上,效率立顯。
e、創建索引,彙集索引則意味着數據的物理存儲順序,最好在惟一的,非空的字段上創建,其它索引也不是越多越好,索引在查詢上優點顯著,在頻繁更新數據的字段上創建彙集索引,後果很嚴重,插入更新至關忙。
f、組合索引和單索引的創建,要考慮查詢實際和具體模式
1.一個字段的取值只有幾種的字段不要使用索引。好比性別,只有兩種可能數據。意味着索引的二叉樹級別少,可能是平級。這樣的二叉樹查找無異於全表掃描。
2.頻繁更新的字段不要使用索引
3.where 子句中使用!=或<>操做符,對字段進行 null 值判斷(IS NULL /IS NOT NULL),使用 or 來鏈接條件,使用in 和 not in,對字段進行表達式操做,對字段進行函數操做,/ like ‘%輸入符%’等條件,不要使用索引。不然將致使引擎放棄使用索引而進行全表掃描
4. 不要在 where 子句中的「=」左邊進行函數(DAY(column)=…)、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
5.任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
6.索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引
7.使用varchar,代替char,這是由於varchar會動態分配長度,char指定爲20,即時你存儲字符「1」,它依然是20的長度
8.大數據字段最好剝離出單獨的表,以便影響性能
9.給表創建主鍵
10.常常用到的列就最好建立索引
11.查詢從索引的最左前列開始而且不跳過索引中的列;
12索引列上不操做
13加了範圍會失效
14在JOIN操做中(須要從多個數據表提取數據時),MYSQL只有在主鍵和外鍵的數據類型相同時才能使用索引,不然即便創建了索引也不會使用。使用鏈接(JOIN)來代替子查詢(Sub-Queries)
java中的多線程在大家的這個項目當中有哪些體現?
a,後臺任務:如定時向大量(100W以上)的用戶發送郵件;按期更新配置文件、任務調度(如quartz),一些監控用於按期信息採集
b, 自動做業處理:好比按期備份日誌、按期備份數據庫
c, 異步處理:如發微博、記錄日誌
獲取鎖的時候,使用setnx加鎖,並使用expire命令(this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS); )爲鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值爲一個隨機生成的UUID,經過此在釋放鎖的時候進行判斷。
獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
釋放鎖的時候,經過UUID判斷是否是該鎖,如果該鎖,則執行delete進行鎖釋放。
SETEX:若是 key 已經存在, SETEX 命令將覆寫舊值。
SETNX:若給定的 key 已經存在,則 SETNX 不作任何動做。
RDB:保存存儲文件到磁盤;同步時間爲15分鐘,5分鐘,1分鐘一次,可能存在數據丟失問題。
AOF:保存命令文件到磁盤;安全性高,修改後當即同步或每秒同步一次。
上述兩種方式在咱們的項目中都有使用到,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據後從數據庫中查詢後保存到redis中
採用默認的RDB方式,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據就從數據庫中查詢後再保存到redis中
數據庫事務的隔離級別有四種,隔離級別高的數據庫的可靠性高,但併發量低,而隔離級別低的數據庫可靠性低,但併發量高,系統開銷小。
READ UNCIMMITTED(未提交讀)
READ COMMITTED(提交讀)
REPEATABLE READ(可重複讀)
SERIALIZABLE(可串行化)
mysql默認的事務處理級別是'REPEATABLE-READ',也就是可重複讀。
表結構層面的拆分。經過mycat數據庫中間件完成數據庫分表操做。
業務層面也有拆分,好比商品模塊拆分紅8張表來實現存儲
分庫:經過Mycat結點來管理不一樣服務器上的數據庫,每一個表最多存500萬條記錄
分表:重直切割,水平切割
MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個"EXPLAIN"便可。mysql中的explain語法能夠幫助咱們改寫查詢,優化表的結構和索引的設置,從而最大地提升查詢效率。
用了CAS,全部應用項目中若是須要登陸時在web.xml中配置過濾器作請求轉發到cas端工做原理是在cas登陸後會給瀏覽器發送一個票據(ticket),瀏覽器cookie中會緩存這個ticket,在登陸其餘項目時會拿着瀏覽器的ticket轉發到cas,到cas後根據票據判斷是否登陸
Java 基礎
JDK 和 JRE 有什麼區別?
== 和 equals 的區別是什麼?
兩個對象的 hashCode()相同,則 equals()也必定爲 true,對嗎?
final 在 java 中有什麼做用?
java 中的 Math.round(-1.5) 等於多少?
String 屬於基礎的數據類型嗎?
java 中操做字符串都有哪些類?它們之間有什麼區別?
String str="i"與 String str=new String(「i」)同樣嗎?
如何將字符串反轉?
String 類的經常使用方法都有那些?
抽象類必需要有抽象方法嗎?
普通類和抽象類有哪些區別?
抽象類能使用 final 修飾嗎?
接口和抽象類有什麼區別?
java 中 IO 流分爲幾種?
BIO、NIO、AIO 有什麼區別?
Files的經常使用方法都有哪些?
2、容器
java 容器都有哪些?
Collection 和 Collections 有什麼區別?
List、Set、Map 之間的區別是什麼?
HashMap 和 Hashtable 有什麼區別?
如何決定使用 HashMap 仍是 TreeMap?
說一下 HashMap 的實現原理?
說一下 HashSet 的實現原理?
ArrayList 和 LinkedList 的區別是什麼?
如何實現數組和 List 之間的轉換?
ArrayList 和 Vector 的區別是什麼?
Array 和 ArrayList 有何區別?
在 Queue 中 poll()和 remove()有什麼區別?
哪些集合類是線程安全的?
迭代器 Iterator 是什麼?
Iterator 怎麼使用?有什麼特色?
Iterator 和 ListIterator 有什麼區別?
怎麼確保一個集合不能被修改?
3、多線程
並行和併發有什麼區別?
線程和進程的區別?
守護線程是什麼?
建立線程有哪幾種方式?
說一下 runnable 和 callable 有什麼區別?
線程有哪些狀態?
sleep() 和 wait() 有什麼區別?
notify()和 notifyAll()有什麼區別?
線程的 run()和 start()有什麼區別?
44.建立線程池有哪幾種方式?
45.線程池都有哪些狀態?
線程池中 submit()和 execute()方法有什麼區別?
在 java 程序中怎麼保證多線程的運行安全?
多線程鎖的升級原理是什麼?
什麼是死鎖?
怎麼防止死鎖?
ThreadLocal 是什麼?有哪些使用場景?
說一下 synchronized 底層實現原理?
synchronized 和 volatile 的區別是什麼?
synchronized 和 Lock 有什麼區別?
synchronized 和 ReentrantLock 區別是什麼?
說一下 atomic 的原理?
4、反射
什麼是反射?
什麼是 java 序列化?什麼狀況下須要序列化?
動態代理是什麼?有哪些應用?
怎麼實現動態代理?
5、對象拷貝
爲何要使用克隆?
如何實現對象克隆?
深拷貝和淺拷貝區別是什麼?
6、Java Web
jsp 和 servlet 有什麼區別?
jsp 有哪些內置對象?做用分別是什麼?
說一下 jsp 的 4 種做用域?
session 和 cookie 有什麼區別?
說一下 session 的工做原理?
若是客戶端禁止 cookie 能實現 session 還能用嗎?
spring mvc 和 struts 的區別是什麼?
如何避免 sql 注入?
什麼是 XSS 攻擊,如何避免?
什麼是 CSRF 攻擊,如何避免?
7、異常
throw 和 throws 的區別?
final、finally、finalize 有什麼區別?
try-catch-finally 中哪一個部分能夠省略?
try-catch-finally 中,若是 catch 中 return 了,finally 還會執行嗎?
常見的異常類有哪些?
8、網絡
http 響應碼 301 和 302 表明的是什麼?有什麼區別?
forward 和 redirect 的區別?
簡述 tcp 和 udp的區別?
tcp 爲何要三次握手,兩次不行嗎?爲何?
說一下 tcp 粘包是怎麼產生的?
OSI 的七層模型都有哪些?
get 和 post 請求有哪些區別?
如何實現跨域?
說一下 JSONP 實現原理?
9、設計模式
說一下你熟悉的設計模式?
簡單工廠和抽象工廠有什麼區別?
10、Spring/Spring MVC
爲何要使用 spring?
解釋一下什麼是 aop?
解釋一下什麼是 ioc?
spring 有哪些主要模塊?
spring 經常使用的注入方式有哪些?
spring 中的 bean 是線程安全的嗎?
spring 支持幾種 bean 的做用域?
spring 自動裝配 bean 有哪些方式?
spring 事務實現方式有哪些?
說一下 spring 的事務隔離?
說一下 spring mvc 運行流程?
spring mvc 有哪些組件?
@RequestMapping 的做用是什麼?
@Autowired 的做用是什麼?
11、Spring Boot/Spring Cloud
什麼是 spring boot?
爲何要用 spring boot?
spring boot 核心配置文件是什麼?
spring boot 配置文件有哪幾種類型?它們有什麼區別?
spring boot 有哪些方式能夠實現熱部署?
jpa 和 hibernate 有什麼區別?
什麼是 spring cloud?
spring cloud 斷路器的做用是什麼?
spring cloud 的核心組件有哪些?
12、Hibernate
爲何要使用 hibernate?
什麼是 ORM 框架?
hibernate 中如何在控制檯查看打印的 sql 語句?
hibernate 有幾種查詢方式?
hibernate 實體類能夠被定義爲 final 嗎?
在 hibernate 中使用 Integer 和 int 作映射有什麼區別?
hibernate 是如何工做的?
get()和 load()的區別?
說一下 hibernate 的緩存機制?
hibernate 對象有哪些狀態?
在 hibernate 中 getCurrentSession 和 openSession 的區別是什麼?
hibernate 實體類必需要有無參構造函數嗎?爲何?
十3、Mybatis
mybatis 中 #{}和 ${}的區別是什麼?
mybatis 有幾種分頁方式?
RowBounds 是一次性查詢所有結果嗎?爲何?
mybatis 邏輯分頁和物理分頁的區別是什麼?
mybatis 是否支持延遲加載?延遲加載的原理是什麼?
說一下 mybatis 的一級緩存和二級緩存?
mybatis 和 hibernate 的區別有哪些?
mybatis 有哪些執行器(Executor)?
mybatis 分頁插件的實現原理是什麼?
mybatis 如何編寫一個自定義插件?
十4、RabbitMQ
rabbitmq 的使用場景有哪些?
rabbitmq 有哪些重要的角色?
rabbitmq 有哪些重要的組件?
rabbitmq 中 vhost 的做用是什麼?
rabbitmq 的消息是怎麼發送的?
rabbitmq 怎麼保證消息的穩定性?
141.rabbitmq 怎麼避免消息丟失?
要保證消息持久化成功的條件有哪些?
rabbitmq 持久化有什麼缺點?
rabbitmq 有幾種廣播類型?
rabbitmq 怎麼實現延遲消息隊列?
rabbitmq 集羣有什麼用?
rabbitmq 節點的類型有哪些?
rabbitmq 集羣搭建須要注意哪些問題?
rabbitmq 每一個節點是其餘節點的完整拷貝嗎?爲何?
rabbitmq 集羣中惟一一個磁盤節點崩潰了會發生什麼狀況?
rabbitmq 對集羣節點中止順序有要求嗎?
十5、Kafka
kafka 能夠脫離 zookeeper 單獨使用嗎?爲何?
kafka 有幾種數據保留的策略?
kafka 同時設置了 7 天和 10G 清除數據,到第五天的時候消息達到了 10G,這個時候 kafka 將如何處理?
什麼狀況會致使 kafka 運行變慢?
使用 kafka 集羣須要注意什麼?
十6、Zookeeper
zookeeper 是什麼?
zookeeper 都有哪些功能?
zookeeper 有幾種部署模式?
zookeeper 怎麼保證主從節點的狀態同步?
集羣中爲何要有主節點?
集羣中有 3 臺服務器,其中一個節點宕機,這個時候 zookeeper 還能夠使用嗎?
說一下 zookeeper 的通知機制?
十7、MySql
數據庫的三範式是什麼?
一張自增表裏面總共有 7 條數據,刪除了最後 2 條數據,重啓 mysql 數據庫,又插入了一條數據,此時 id 是幾?
如何獲取當前數據庫版本?
說一下 ACID 是什麼?
char 和 varchar 的區別是什麼?
float 和 double 的區別是什麼?
mysql 的內鏈接、左鏈接、右鏈接有什麼區別?
mysql 索引是怎麼實現的?
怎麼驗證 mysql 的索引是否知足需求?
說一下數據庫的事務隔離?
說一下 mysql 經常使用的引擎?
說一下 mysql 的行鎖和表鎖?
說一下樂觀鎖和悲觀鎖?
mysql 問題排查都有哪些手段?
如何作 mysql 的性能優化?
十8、Redis
redis 是什麼?都有哪些使用場景?
redis 有哪些功能?
redis 和 memecache 有什麼區別?
redis 爲何是單線程的?
什麼是緩存穿透?怎麼解決?
redis 支持的數據類型有哪些?
redis 支持的 java 客戶端都有哪些?
jedis 和 redisson 有哪些區別?
怎麼保證緩存和數據庫數據的一致性?
redis 持久化有幾種方式?
189.redis 怎麼實現分佈式鎖?
redis 分佈式鎖有什麼缺陷?
redis 如何作內存優化?
redis 淘汰策略有哪些?
redis 常見的性能問題有哪些?該如何解決?
十9、JVM
說一下 jvm 的主要組成部分?及其做用? 說一下 jvm 運行時數據區? 說一下堆棧的區別? 隊列和棧是什麼?有什麼區別? 什麼是雙親委派模型? 說一下類加載的執行過程? 怎麼判斷對象是否能夠被回收? java 中都有哪些引用類型? 說一下 jvm 有哪些垃圾回收算法? 說一下 jvm 有哪些垃圾回收器? 詳細介紹一下 CMS 垃圾回收器? 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什麼區別? 簡述分代垃圾回收器是怎麼工做的? 說一下 jvm 調優的工具? 經常使用的 jvm 調優的參數都有哪些?