面試:第二章:各種框架和中間件以及緩存數(shù)據(jù)庫
講講SpringMVC的工作原理和常用注解
1、用戶向服務(wù)器發(fā)送請求,請求被SpringMVC的前端控制器DispatcherServlet截獲。
2、DispatcherServlet對請求的URL(統(tǒng)一資源定位符)進行解析,得到URI(請求資源標識符),然后根據(jù)該URI,
通過配置或注解調(diào)用HandlerMapping找到Handler配置的所有相關(guān)的對象,包括Handler對象以及Handler對象對應(yīng)的攔截器,
這些對象都會被封裝到一個HandlerExecutionChain對象當(dāng)中返回DispatcherServlet。
3、前端控制器根據(jù)獲得的Handler,請求HandlerAdapter處理多種Handler,調(diào)用Handler實際處理請求的方法。
4、提取請求中的模型數(shù)據(jù),開始執(zhí)行Handler(Controller)
5、Handler執(zhí)行完成后,向DispatcherServlet返回一個ModelAndView對象。
6、根據(jù)返回的ModelAndView對象,請求ViewResolver(視圖解析器)將邏輯視圖解析成真正的視圖并返回view給前端控制器。
7、渲染視圖將model數(shù)據(jù)轉(zhuǎn)換為response響應(yīng)
8、把響應(yīng)結(jié)果給返回給客戶端。
url和uri的區(qū)別?
URI包括URL和URN兩個類別,個人的身份證號就是URN,個人的家庭地址就是URL,URN可以唯一標識一個人,
而URL可以告訴郵遞員怎么把貨送到你手里。
組件型注解:
@Component 在類定義之前添加@Component注解,他會被spring容器識別,并轉(zhuǎn)為bean。
@Repository 對Dao實現(xiàn)類進行注解 (特殊的@Component)
@Service 用于對業(yè)務(wù)邏輯層進行注解, (特殊的@Component)
@Controller 用于控制層注解 , (特殊的@Component)
請求和參數(shù)型注解:
@RequestMapping:用于處理請求地址映射,可以作用于類和方法上。
@RequestParam:用于獲取傳入?yún)?shù)的值
@PathViriable:用于定義路徑參數(shù)值
@ResponseBody:作用于方法上,可以將整個返回結(jié)果以某種格式返回,如json或xml格式。
@CookieValue:用于獲取請求的Cookie值
講講Spring的IOC(DI)和AOP動態(tài)代理
傳統(tǒng)的程序開發(fā)(不用IOC):舉個簡單的例子,我們是如何找女朋友的?常見的情況是,我們到處去看哪里有
長得漂亮身材又好的mm,然后打聽她們的興趣愛好、qq號、電話號、ip號、iq號………,想辦法認識她們,投其
所好送其所要,然后嘿嘿……這個過程是復(fù)雜深奧的,我們必須自己設(shè)計和面對每個環(huán)節(jié)。
有IOC:
IoC是如何做的呢?有點像通過婚介找女朋友,在我和女朋友之間引入了一個第三者:婚姻介紹所。婚
介管理了很多男男女女的資料,我可以向婚介提出一個列表,告訴它我想找個什么樣的女朋友,比如長得像李
嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術(shù)像齊達內(nèi)之類的,然后婚介就會按照我們的要求,
提供一個mm,我們只需要去和她談戀愛、結(jié)婚就行了。
總結(jié)控制反轉(zhuǎn):所有的類都會在spring容器中登記,告訴spring你是個什么東西,你需要什么東西,然后
spring會在系統(tǒng)運行到適當(dāng)?shù)臅r候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的
創(chuàng)建、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象,而是spring。對于某個
具體的對象而言,以前是它控制其他對象,現(xiàn)在是所有對象都被spring控制,所以這叫控制反轉(zhuǎn)。
理解DI的關(guān)鍵是:“誰依賴誰,為什么需要依賴,誰注入誰,注入了什么”
●誰依賴于誰:當(dāng)然是應(yīng)用程序依賴于IoC容器;
●為什么需要依賴:應(yīng)用程序需要IoC容器來提供對象需要的外部資源;
●誰注入誰:很明顯是IoC容器注入應(yīng)用程序某個對象,應(yīng)用程序依賴的對象;
●注入了什么:就是注入某個對象所需要的外部資源(包括對象、資源、常量數(shù)據(jù))。
IoC和DI是什么關(guān)系呢?
DI(依賴注入)其實就是IOC的另外一種說法,其實它們是同一個概念的不同角度描述
AOP的各種實現(xiàn)
AOP就是面向切面編程,我們可以從以下幾個層面來實現(xiàn)AOP
在編譯期修改源代碼
在運行期字節(jié)碼加載前修改字節(jié)碼
在運行期字節(jié)碼加載后動態(tài)創(chuàng)建代理類的字節(jié)碼
AOP各種實現(xiàn)機制的比較
以下是各種實現(xiàn)機制的比較:
AOP里的公民
Joinpoint:攔截點,如某個業(yè)務(wù)方法
Pointcut:Joinpoint的表達式,表示攔截哪些方法。一個Pointcut對應(yīng)多個Joinpoint
Advice:要切入的邏輯
Before Advice:在方法前切入
After Advice:在方法后切入,拋出異常則不會切入
After Returning Advice:在方法返回后切入,拋出異常則不會切入
After Throwing Advice:在方法拋出異常時切入
Around Advice:在方法執(zhí)行前后切入,可以中斷或忽略原有流程的執(zhí)行
Spring AOP使用的動態(tài)代理,所謂的動態(tài)代理就是說AOP框架不會去修改字節(jié)碼,而是在內(nèi)存中臨時為方法生成
一個AOP對象,這個AOP對象包含了目標對象的全部方法,并且在特定的切點做了增強處理,并回調(diào)原對象的方法。
Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理。JDK動態(tài)代理通過反射來接收被代理
的類,并且要求被代理的類必須實現(xiàn)一個接口。JDK動態(tài)代理的核心是InvocationHandler接口和Proxy類。如果
目標類沒有實現(xiàn)接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標類。CGLIB(Code Generation
Library),是一個代碼生成的類庫,可以在運行時動態(tài)的生成某個類的子類,注意,CGLIB是通過繼承的方式做
的動態(tài)代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態(tài)代理的。
AOP在事務(wù)管理方面,Spring使用AOP來完成聲明式的事務(wù)管理有annotation和xml兩種形式。開發(fā)中,方便代碼
編寫,很多時候都是在spring配置文件中配置事務(wù)管理器并開啟事務(wù)控制注解。在業(yè)務(wù)類或業(yè)務(wù)類方法中添加
@Transactional實現(xiàn)事務(wù)控制。
講講MyBatis框架
(1)mybatis是一個基于java的持久層框架,它內(nèi)部封裝了jdbc,不需要花費精力去處理加載驅(qū)動、創(chuàng)建連接等的過程,
消除了JDBC大量冗余的代碼。
(2)mybatis通過xml或注解的方式將要執(zhí)行的各種statement配置起來,并通過java對象和statement中
sql的動態(tài)參數(shù)進行映射生成最終執(zhí)行的sql語句,最后由mybatis框架執(zhí)行sql并將結(jié)果映射為java對象并返回。
(3)MyBatis 支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)
置參數(shù)以及獲取結(jié)果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJO映射成數(shù)據(jù)庫中的記錄。
(4)提供了很多第三方插件(分頁插件 / 逆向工程);
(5)能夠與Spring很好的集成;
(6)MyBatis相當(dāng)靈活,SQL寫在XML里,從程序代碼中徹底分離,解除sql與程序代碼的耦合,便于統(tǒng)一管理,支持編寫動態(tài)SQL語句。
(7) 提供映射標簽,支持對象與數(shù)據(jù)庫的ORM字段關(guān)系映射。
(8)SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性差,不能隨意更換數(shù)據(jù)庫。
講講SpringBoot的特點
Springboot用來簡化spring應(yīng)用的初始搭建以及開發(fā)過程 使用特定的方式來進行配置
(properties或yml文件)
可以創(chuàng)建獨立的spring引用程序 main方法運行
Springboot嵌入的Tomcat 無需部署war文件
簡化maven配置
講講線程的創(chuàng)建及實現(xiàn)線程幾種方式之間的區(qū)別
1:繼承Therad類,2:實現(xiàn)Runnable接口 3:實現(xiàn)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();
實現(xiàn)Runnable接口,并實現(xiàn)里面的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();
實現(xiàn)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(){//任務(wù)});
es.submit(new Runnable(){//任務(wù)});
...
es.shutdown();
實現(xiàn)Runnable和實現(xiàn)Callable的區(qū)別?
實現(xiàn)Callable接口,任務(wù)可以有返回值,Runnable沒有。
實現(xiàn)Callable接口,可以指定泛型,Runnable沒有。
實現(xiàn)Callable接口,可以在call方法中聲明異常,Runnable沒有。
Runnable和Thread二者的區(qū)別?
實現(xiàn)Runnable接口的方式,更適合處理有共享資源的情況。
實現(xiàn)Runnable接口的方式,避免了單繼承的局限性。
Java自定義類加載器與雙親委派模型
啟動類加載器(Bootstrap)C++
擴展類加載器(Extension)Java
應(yīng)用程序類加載器(AppClassLoader)Java
雙親委派模型工作原理:如果一個類加載器收到類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請
求委派給父類加載器完成。每個類加載器都是如此,只有當(dāng)父加載器在自己的搜索范圍內(nèi)找不到指定的類時(即
ClassNotFoundException),子加載器才會嘗試自己去加載。
講講jvm的組成與調(diào)優(yōu),內(nèi)存模型,GC,tomcat調(diào)優(yōu)
tomcat調(diào)優(yōu):
增加JVM堆內(nèi)存大小
修復(fù)JRE內(nèi)存泄漏
線程池設(shè)置
壓縮
數(shù)據(jù)庫性能調(diào)優(yōu)
Tomcat本地庫
JVM調(diào)優(yōu):
-Xms – 指定初始化時化的堆內(nèi)存,默認為物理內(nèi)存的1/64
-Xmx – 指定最大的內(nèi)存,默認為物理內(nèi)存的1/4
-XX:+PrintGCDetails:輸出詳細的GC處理日志
在重啟你的Tomcat服務(wù)器之后,這些配置的更改才會有效。
講講高可用的數(shù)據(jù)與服務(wù)怎么實現(xiàn),負載均衡策略以及區(qū)別,分布式(及事物),集群,高并發(fā)以及遇到的問題和解決方案
分布式 :
分布式架構(gòu):把系統(tǒng)按照模塊拆分成多個子系統(tǒng),多個子系統(tǒng)分布在不同的網(wǎng)絡(luò)計算機上相互協(xié)作完成業(yè)務(wù)流
程,系統(tǒng)之間需要進行通信。
優(yōu)點:
把模塊拆分,使用接口通信,降低模塊之間的耦合度。
把項目拆分成若干個子項目,不同的團隊負責(zé)不同的子項目。
增加功能時只需要再增加一個子項目,調(diào)用其他系統(tǒng)的接口就可以。
可以靈活的進行分布式部署。
缺點:
1、系統(tǒng)之間交互需要使用遠程通信,接口開發(fā)增加工作量。
2、各個模塊有一些通用的業(yè)務(wù)邏輯無法共用。
基于soa的架構(gòu)
SOA:面向服務(wù)的架構(gòu)。也就是把工程拆分成服務(wù)層、表現(xiàn)層兩個工程。服務(wù)層中包含業(yè)務(wù)邏輯,只需要對外提
供服務(wù)即可。表現(xiàn)層只需要處理和頁面的交互,業(yè)務(wù)邏輯都是調(diào)用服務(wù)層的服務(wù)來實現(xiàn)。
分布式架構(gòu)和soa架構(gòu)有什么區(qū)別?
SOA,主要還是從服務(wù)的角度,將工程拆分成服務(wù)層、表現(xiàn)層兩個工程。
分布式,主要還是從部署的角度,將應(yīng)用按照訪問壓力進行歸類,主要目標是充分利用服務(wù)器的資源,避免資源分配不均
集群:
一個集群系統(tǒng)是一群松散結(jié)合的服務(wù)器組,形成一個虛擬的服務(wù)器,為客戶端用戶提供統(tǒng)一的服務(wù)。對于這個
客戶端來說,通常在訪問集群系統(tǒng)時不會意識到它的服務(wù)是由具體的哪一臺服務(wù)器提供。集群的目的,是為實
現(xiàn)負載均衡、容錯和災(zāi)難恢復(fù)。以達到系統(tǒng)可用性和可伸縮性的要求。集群系統(tǒng)一般應(yīng)具高可用性、可伸縮
性、負載均衡、故障恢復(fù)和可維護性等特殊性能。一般同一個工程會部署到多臺服務(wù)器上。
常見的tomcat集群,Redis集群,Zookeeper集群,數(shù)據(jù)庫集群
分布式與集群的區(qū)別:
分布式是指將不同的業(yè)務(wù)分布在不同的地方。 而集群指的是將幾臺服務(wù)器集中在一起,實現(xiàn)同一業(yè)務(wù)。一句
話:分布式是并聯(lián)工作的,集群是串聯(lián)工作的。
分布式中的每一個節(jié)點,都可以做集群。 而集群并不一定就是分布式的。
舉例:就比如新浪網(wǎng),訪問的人多了,他可以做一個群集,前面放一個響應(yīng)服務(wù)器,后面幾臺服務(wù)器完成同一
業(yè)務(wù),如果有業(yè)務(wù)訪問的時候,響應(yīng)服務(wù)器看哪臺服務(wù)器的負載不是很重,就將給哪一臺去完成。
而分布式,從窄意上理解,也跟集群差不多, 但是它的組織比較松散,不像集群,有一個組織性,一臺服務(wù)器垮了,
其它的服務(wù)器可以頂上來。分布式的每一個節(jié)點,都完成不同的業(yè)務(wù),一個節(jié)點垮了,哪這個業(yè)務(wù)就不可訪問了。
分布式是以縮短單個任務(wù)的執(zhí)行時間來提升效率的,而集群則是通過提高單位時間內(nèi)執(zhí)行的任務(wù)數(shù)來提升效率。
舉例:如果一個任務(wù)由10個子任務(wù)組成,每個子任務(wù)單獨執(zhí)行需1小時,則在一臺服務(wù)器上執(zhí)行該任務(wù)需10小
時。采用分布式方案,提供10臺服務(wù)器,每臺服務(wù)器只負責(zé)處理一個子任務(wù),不考慮子任務(wù)間的依賴關(guān)系,執(zhí)
行完,這個任務(wù)只需一個小時。(這種工作模式的一個典型代表就是Hadoop的Map/Reduce分布式計算模型)
而采用集群方案,同樣提供10臺服務(wù)器,每臺服務(wù)器都能獨立處理這個任務(wù)。假設(shè)有10個任務(wù)同時到達,10個
服務(wù)器將同時工作,1小時后,10個任務(wù)同時完成,這樣,整身來看,還是1小時內(nèi)完成一個任務(wù)!
高并發(fā):
處理高并發(fā)常見的方法有哪些?
1)數(shù)據(jù)層
數(shù)據(jù)庫集群和庫表散列
分表分庫
開啟索引
開啟緩存
表設(shè)計優(yōu)化
Sql語句優(yōu)化
緩存服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
搜索服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
圖片服務(wù)器分離
2)項目層
采用面向服務(wù)分布式架構(gòu)(分擔(dān)服務(wù)器壓力,提高并發(fā)能力)
采用并發(fā)訪問較高的詳情系統(tǒng)采用靜態(tài)頁面,HTML靜態(tài)化 freemaker
使用頁面緩存
用ActiveMQ使得業(yè)務(wù)進一步進行解耦,提高業(yè)務(wù)處理能力
使用分布式文件系統(tǒng)存儲海量文件
3)應(yīng)用層
Nginx服務(wù)器來做負載均衡
Lvs做二層負載
鏡像
高可用:
目的:保證服務(wù)器硬件故障服務(wù)依然可用,數(shù)據(jù)依然保存并能夠被訪問。
高可用的服務(wù)
①分級管理:核心應(yīng)用和服務(wù)具有更高的優(yōu)先級,比如用戶及時付款比能否評價商品更重要;
②超時設(shè)置:設(shè)置服務(wù)調(diào)用的超時時間,一旦超時,通信框架拋出異常,應(yīng)用程序則根據(jù)服務(wù)調(diào)度策略選擇重試or請求轉(zhuǎn)移到其他服務(wù)器上
③異步調(diào)用:通過消息隊列等異步方式完成,避免一個服務(wù)失敗導(dǎo)致整個應(yīng)用請求失敗的情況。
不是所有服務(wù)都可以異步調(diào)用,對于獲取用戶信息這類調(diào)用,采用異步方式會延長響應(yīng)時間,得不償失。對于
那些必須確認服務(wù)調(diào)用成功后才能繼續(xù)進行下一步的操作的應(yīng)用也不適合異步調(diào)用。
④服務(wù)降級:網(wǎng)站訪問高峰期間,為了保證核心應(yīng)用的正常運行,需要對服務(wù)降級。
降級有兩種手段:
一是拒絕服務(wù),拒絕較低優(yōu)先級的應(yīng)用的調(diào)用,減少服務(wù)調(diào)用并發(fā)數(shù),確保核心應(yīng)用的正常運行;
二是關(guān)閉功能,關(guān)閉部分不重要的服務(wù),或者服務(wù)內(nèi)部關(guān)閉部分不重要的功能,以節(jié)約系統(tǒng)開銷,為核心應(yīng)用服務(wù)讓出資源;
⑤冪等性設(shè)計:保證服務(wù)重復(fù)調(diào)用和調(diào)用一次產(chǎn)生的結(jié)果相同;
高可用的數(shù)據(jù)
保證數(shù)據(jù)高可用的主要手段有兩種:一是數(shù)據(jù)備份,二是失效轉(zhuǎn)移機制;
①數(shù)據(jù)備份:又分為冷備份和熱備份,冷備份是定期復(fù)制,不能保證數(shù)據(jù)可用性。熱備份又分為異步熱備
和同步熱備,異步熱備是指多份數(shù)據(jù)副本的寫入操作異步完成,而同步方式則是指多份數(shù)據(jù)副本的寫入操作同時完成。
②失效轉(zhuǎn)移:若數(shù)據(jù)服務(wù)器集群中任何一臺服務(wù)器宕機,那么應(yīng)用程序針對這臺服務(wù)器的所有讀寫操作都
要重新路由到其他服務(wù)器,保證數(shù)據(jù)訪問不會失敗。
網(wǎng)站運行監(jiān)控
”不允許沒有監(jiān)控的系統(tǒng)上線“
(1)監(jiān)控數(shù)據(jù)采集
①用戶行為日志收集:服務(wù)器端的日志收集和客戶端的日志收集;目前許多網(wǎng)站逐步開發(fā)基于實時計算框架Storm的日志統(tǒng)計與分析工具;
②服務(wù)器性能監(jiān)控:收集服務(wù)器性能指標,如系統(tǒng)Load、內(nèi)存占用、磁盤IO等,及時判斷,防患于未然;
③運行數(shù)據(jù)報告:采集并報告,匯總后統(tǒng)一顯示,應(yīng)用程序需要在代碼中處理運行數(shù)據(jù)采集的邏輯;
(2)監(jiān)控管理
①系統(tǒng)報警:配置報警閥值和值守人員聯(lián)系方式,系統(tǒng)發(fā)生報警時,即使工程師在千里之外,也可以被及時通知;
②失效轉(zhuǎn)移:監(jiān)控系統(tǒng)在發(fā)現(xiàn)故障時,主動通知應(yīng)用進行失效轉(zhuǎn)移;
③自動優(yōu)雅降級:為了應(yīng)付網(wǎng)站訪問高峰,主動關(guān)閉部分功能,釋放部分系統(tǒng)資源,保證核心應(yīng)用服務(wù)的正
常運行;—>網(wǎng)站柔性架構(gòu)的理想狀態(tài)
負載均衡:
什么是負載均衡?
當(dāng)一臺服務(wù)器的性能達到極限時,我們可以使用服務(wù)器集群來提高網(wǎng)站的整體性能。那么,在服務(wù)器集群
中,需要有一臺服務(wù)器充當(dāng)調(diào)度者的角色,用戶的所有請求都會首先由它接收,調(diào)度者再根據(jù)每臺服務(wù)器的負
載情況將請求分配給某一臺后端服務(wù)器去處理。
(1)HTTP重定向負載均衡。
原理:當(dāng)用戶向服務(wù)器發(fā)起請求時,請求首先被集群調(diào)度者截獲;調(diào)度者根據(jù)某種分配策略,選擇一臺服務(wù)
器,并將選中的服務(wù)器的IP地址封裝在HTTP響應(yīng)消息頭部的Location字段中,并將響應(yīng)消息的狀態(tài)碼設(shè)為
302,最后將這個響應(yīng)消息返回給瀏覽器。當(dāng)瀏覽器收到響應(yīng)消息后,解析Location字段,并向該URL發(fā)起請
求,然后指定的服務(wù)器處理該用戶的請求,最后將結(jié)果返回給用戶。
優(yōu)點:比較簡單
缺點:調(diào)度服務(wù)器只在客戶端第一次向網(wǎng)站發(fā)起請求的時候起作用。當(dāng)調(diào)度服務(wù)器向瀏覽器返回響應(yīng)信息后,
客戶端此后的操作都基于新的URL進行的(也就是后端服務(wù)器),此后瀏覽器就不會與調(diào)度服務(wù)器產(chǎn)生關(guān)系,瀏
覽器需要每次請求兩次服務(wù)器才能拿完成一次訪問,性能較差。而且調(diào)度服務(wù)器在調(diào)度時,無法知道當(dāng)前用戶
將會對服務(wù)器造成多大的壓力,只不過是把請求次數(shù)平均分配給每臺服務(wù)器罷了,瀏覽器會與后端服務(wù)器直接交互。
(2)DNS域名解析負載均衡
原理:為了方便用戶記憶,我們使用域名來訪問網(wǎng)站。通過域名訪問網(wǎng)站之前,首先需要將域名解析成IP地
址,這個工作是由DNS域名服務(wù)器完成的。我們提交的請求不會直接發(fā)送給想要訪問的網(wǎng)站,而是首先發(fā)給域名
服務(wù)器,它會幫我們把域名解析成IP地址并返回給我們。我們收到IP之后才會向該IP發(fā)起請求。一個域名指向
多個IP地址,每次進行域名解析時,DNS只要選一個IP返回給用戶,就能夠?qū)崿F(xiàn)服務(wù)器集群的負載均衡。
調(diào)度策略:一般DNS提供商會提供一些調(diào)度策略供我們選擇,如隨機分配、輪詢、根據(jù)請求者的地域分配離他最近的服務(wù)器。
隨機分配策略:
當(dāng)調(diào)度服務(wù)器收到用戶請求后,可以隨機決定使用哪臺后端服務(wù)器,然后將該服務(wù)器的IP封裝在HTTP響應(yīng)消息
的Location屬性中,返回給瀏覽器即可。
輪詢策略(RR) :
調(diào)度服務(wù)器需要維護一個值,用于記錄上次分配的后端服務(wù)器的IP。那么當(dāng)新的請求到來時,調(diào)度者將請求依
次分配給下一臺服務(wù)器。
優(yōu)點:配置簡單,將負載均衡工作交給DNS,省略掉了網(wǎng)絡(luò)管理的麻煩;
缺點:集群調(diào)度權(quán)交給了DNS服務(wù)器,從而我們沒辦法隨心所欲地控制調(diào)度者,沒辦法定制調(diào)度策略,沒辦法了
解每臺服務(wù)器的負載情況,只不過把所有請求平均分配給后端服務(wù)器罷了。某一臺后端服務(wù)器發(fā)生故障時,即
使我們立即將該服務(wù)器從域名解析中去除,但由于DNS服務(wù)器會有緩存,該IP仍然會在DNS中保留一段時間,那
么就會導(dǎo)致一部分用戶無法正常訪問網(wǎng)站。不過動態(tài)DNS能夠讓我們通過程序動態(tài)修改DNS服務(wù)器中的域名解
析。從而當(dāng)我們的監(jiān)控程序發(fā)現(xiàn)某臺服務(wù)器掛了之后,能立即通知DNS將其刪掉。
(3)反向代理負載均衡。
原理:反向代理服務(wù)器是一個位于實際服務(wù)器之前的服務(wù)器,所有向我們網(wǎng)站發(fā)來的請求都首先要經(jīng)過反向代
理服務(wù)器,服務(wù)器根據(jù)用戶的請求要么直接將結(jié)果返回給用戶,要么將請求交給后端服務(wù)器處理,再返回給用
戶。反向代理服務(wù)器就可以充當(dāng)服務(wù)器集群的調(diào)度者,它可以根據(jù)當(dāng)前后端服務(wù)器的負載情況,將請求轉(zhuǎn)發(fā)給
一臺合適的服務(wù)器,并將處理結(jié)果返回給用戶。
優(yōu)點:
1.部署簡單
2.隱藏后端服務(wù)器:與HTTP重定向相比,反向代理能夠隱藏后端服務(wù)器,所有瀏覽器都不會與后端服務(wù)器直接
交互,從而能夠確保調(diào)度者的控制權(quán),提升集群的整體性能。
3.故障轉(zhuǎn)移 :與DNS負載均衡相比,反向代理能夠更快速地移除故障結(jié)點。當(dāng)監(jiān)控程序發(fā)現(xiàn)某一后端服務(wù)器出
現(xiàn)故障時,能夠及時通知反向代理服務(wù)器,并立即將其刪除。
4.合理分配任務(wù) :HTTP重定向和DNS負載均衡都無法實現(xiàn)真正意義上的負載均衡,也就是調(diào)度服務(wù)器無法根據(jù)
后端服務(wù)器的實際負載情況分配任務(wù)。但反向代理服務(wù)器支持手動設(shè)定每臺后端服務(wù)器的權(quán)重。我們可以根據(jù)
服務(wù)器的配置設(shè)置不同的權(quán)重,權(quán)重的不同會導(dǎo)致被調(diào)度者選中的概率的不同。
缺點:
1.調(diào)度者壓力過大 :由于所有的請求都先由反向代理服務(wù)器處理,那么當(dāng)請求量超過調(diào)度服務(wù)器的最大負載
時,調(diào)度服務(wù)器的吞吐率降低會直接降低集群的整體性能。
2.制約擴展 :當(dāng)后端服務(wù)器也無法滿足巨大的吞吐量時,就需要增加后端服務(wù)器的數(shù)量,可沒辦法無限量地增
加,因為會受到調(diào)度服務(wù)器的最大吞吐量的制約。
3.粘滯會話:反向代理服務(wù)器會引起一個問題。若某臺后端服務(wù)器處理了用戶的請求,并保存了該用戶的
session或存儲了緩存,那么當(dāng)該用戶再次發(fā)送請求時,無法保證該請求仍然由保存了其Session或緩存的服
務(wù)器處理,若由其他服務(wù)器處理,先前的Session或緩存就找不到了。
解決辦法1: 可以修改反向代理服務(wù)器的任務(wù)分配策略,以用戶IP作為標識較為合適。相同的用戶IP會交由同
一臺后端服務(wù)器處理,從而就避免了粘滯會話的問題。
解決辦法2: 可以在Cookie中標注請求的服務(wù)器ID,當(dāng)再次提交請求時,調(diào)度者將該請求分配給Cookie中標
注的服務(wù)器處理即可。
(4)IP負載均衡。
1.通過NAT實現(xiàn)負載均衡:響應(yīng)報文一般比較大,每一次都需要NAT轉(zhuǎn)換的話,大流量的時候,會導(dǎo)致調(diào)度器成為一個瓶頸。
2.通過直接路由實現(xiàn)負載均衡
3.VS/TUN 實現(xiàn)虛擬服務(wù)器
優(yōu)點:IP負載均衡在內(nèi)核進程完成數(shù)據(jù)分發(fā),較反向代理均衡有更好的處理性能。
缺點:負載均衡的網(wǎng)卡帶寬成為系統(tǒng)的瓶頸,場景:某個服務(wù)器跑的應(yīng)用非高峰期間都能達到500M以
上,晚高峰一般能夠超過1G,主流服務(wù)器的網(wǎng)卡都是千兆的,超過1G的流量明顯會導(dǎo)致丟包的問題,此時又不
能停止業(yè)務(wù)對網(wǎng)卡進行更換。
(5)數(shù)據(jù)鏈路層負載均衡。
對于linux系統(tǒng)來說,數(shù)據(jù)鏈路層的解決方案就是實現(xiàn)多個網(wǎng)卡綁定聯(lián)合提供服務(wù),把多張網(wǎng)卡捆綁做成一個
邏輯網(wǎng)卡。避免負載均衡服務(wù)器網(wǎng)卡帶寬成為瓶頸,是目前大型網(wǎng)站所使用的最廣的一種負載均衡手段。
linux bonding的七種模式,mod=0~6:平衡掄循環(huán)策略,主-備份策略,平衡策略,廣播策略,動態(tài)鏈接聚
合,適配器傳輸負載均衡,適配器適應(yīng)性負載均衡
講講你是怎么優(yōu)化數(shù)據(jù)庫(sql,表的設(shè)計)以及索引的使用有哪些限制條件(索引失效)
a,選取最適用的字段:在創(chuàng)建表的時候,為了獲得更好的性能,我們可以將表中字段的寬度設(shè)得盡可能小。另外一
個提高效率的方法是在可能的情況下,應(yīng)該盡量把字段設(shè)置為NOTNULL,
b,使用連接(JOIN)來代替子查詢(Sub-Queries)
c,使用聯(lián)合(UNION)來代替手動創(chuàng)建的臨時表
d,事物:
a)要么語句塊中每條語句都操作成功,要么都失敗。換句話說,就是可以保持數(shù)據(jù)庫中數(shù)據(jù)的一致性和完整
性。事物以BEGIN關(guān)鍵字開始,COMMIT關(guān)鍵字結(jié)束。在這之間的一條SQL操作失敗,那么,ROLLBACK命令就可以
把數(shù)據(jù)庫恢復(fù)到BEGIN開始之前的狀態(tài)。
b) 是當(dāng)多個用戶同時使用相同的數(shù)據(jù)源時,它可以利用鎖定數(shù)據(jù)庫的方法來為用戶提供一種安全的訪問方
式,這樣可以保證用戶的操作不被其它的用戶所干擾。
e,減少表關(guān)聯(lián),加入冗余字段
f,使用外鍵:鎖定表的方法可以維護數(shù)據(jù)的完整性,但是它卻不能保證數(shù)據(jù)的關(guān)聯(lián)性。這個時候我們就可以使用外鍵。
g,使用索引
h,優(yōu)化的查詢語句
i,集群
j,讀寫分離
k,主從復(fù)制
l,分表
m,分庫
o,適當(dāng)?shù)臅r候可以使用存儲過程
限制:盡量用全職索引,最左前綴:查詢從索引的最左前列開始并且不跳過索引中的列;索引列上不操作,范圍之
后全失效; 不等空值還有OR,索引影響要注意;like以通配符%開頭索引失效會變成全表掃描的操作,字符串不
加單引號索引失效
講講Redis緩存,它的數(shù)據(jù)類型,和其他緩存之間的區(qū)別,及持久化,緩存穿透與雪崩它的解決方案
redis是內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),一個key-value類型的非關(guān)系型數(shù)據(jù)庫,可持久化的數(shù)據(jù)庫,相對于關(guān)
系型數(shù)據(jù)庫(數(shù)據(jù)主要存在硬盤中),性能高,因此我們一般用redis來做緩存使用;并且redis支持豐富的數(shù)
據(jù)類型,比較容易解決各種問題,因此redis可以用來作為注冊中心,?數(shù)據(jù)庫、緩存和消息中間件。Redis的
Value支持5種數(shù)據(jù)類型,string、hash、list、set、zset(sorted set);
String類型:一個key對應(yīng)一個value
Hash類型:它的key是string類型,value又是一個map(key-value),適合存儲對象。
List類型:按照插入順序的字符串鏈表(雙向鏈表),主要命令是LPUSH和RPUSH,能夠支持反向查找和遍歷
Set類型:用哈希表類型的字符串序列,沒有順序,集合成員是唯一的,沒有重復(fù)數(shù)據(jù),底層主要是由一個
value永遠為null的hashmap來實現(xiàn)的。
zset類型:和set類型基本一致,不過它會給每個元素關(guān)聯(lián)一個double類型的分數(shù)(score),這樣就可以為
成員排序,并且插入是有序的。
Memcache和redis的區(qū)別:
數(shù)據(jù)支持的類型:redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還支持list、set、zset、hash等數(shù)據(jù)結(jié)構(gòu)
的存儲;memcache只支持簡單的k/v類型的數(shù)據(jù),key和value都是string類型
可靠性:memcache不支持數(shù)據(jù)持久化,斷電或重啟后數(shù)據(jù)消失,但其穩(wěn)定性是有保證的;redis支持數(shù)據(jù)持久
化和數(shù)據(jù)恢復(fù),允許單點故障,但是同時也會付出性能的代價
性能上:對于存儲大數(shù)據(jù),memcache的性能要高于redis
應(yīng)用場景:
Memcache:適合多讀少寫,大數(shù)據(jù)量的情況(一些官網(wǎng)的文章信息等)
Redis:適用于對讀寫效率要求高、數(shù)據(jù)處理業(yè)務(wù)復(fù)雜、安全性要求較高的系統(tǒng)
案例:分布式系統(tǒng),存在session之間的共享問題,因此在做單點登錄的時候,我們利用redis來模擬了
session的共享,來存儲用戶的信息,實現(xiàn)不同系統(tǒng)的session共享;
redis的持久化方式有兩種:
RDB(半持久化方式):按照配置不定期的通過異步的方式、快照的形式直接把內(nèi)存中的數(shù)據(jù)持久化到磁盤的一
個dump.rdb文件(二進制的臨時文件)中,redis默認的持久化方式,它在配置文件(redis.conf)中。
優(yōu)點:只包含一個文件,將一個單獨的文件轉(zhuǎn)移到其他存儲媒介上,對于文件備份、災(zāi)難恢復(fù)而言,比較實用。
缺點:系統(tǒng)一旦在持久化策略之前出現(xiàn)宕機現(xiàn)象,此前沒有來得及持久化的數(shù)據(jù)將會產(chǎn)生丟失
AOF(全持久化的方式):把每一次數(shù)據(jù)變化都通過write()函數(shù)將你所執(zhí)行的命令追加到一個appendonly.aof文件里面,
Redis默認是不支持這種全持久化方式的,需要在配置文件(redis.conf)中將
appendonly no改成appendonly yes
優(yōu)點:數(shù)據(jù)安全性高,對日志文件的寫入操作采用的是append模式,因此在寫入過程中即使出現(xiàn)宕機問題,也
不會破壞日志文件中已經(jīng)存在的內(nèi)容;
缺點:對于數(shù)量相同的數(shù)據(jù)集來說,aof文件通常要比rdb文件大,因此rdb在恢復(fù)大數(shù)據(jù)集時的速度大于AOF;
AOF持久化配置:
在Redis的配置文件中存在三種同步方式,它們分別是:
appendfsync always #每次有數(shù)據(jù)修改發(fā)生時都會都調(diào)用fsync刷新到aof文件,非常慢,但是安全;
appendfsync everysec #每秒鐘都調(diào)用fsync刷新到aof文件中,很快,但是可能丟失一秒內(nèi)的數(shù)據(jù),推薦使用,兼顧了速度和安全;
appendfsync no #不會自動同步到磁盤上,需要依靠OS(操作系統(tǒng))進行刷新,效率快,但是安全性就比較差;
二種持久化方式區(qū)別:
AOF在運行效率上往往慢于RDB,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效;
如果緩存數(shù)據(jù)安全性要求比較高的話,用aof這種持久化方式(比如項目中的購物車);
如果對于大數(shù)據(jù)集要求效率高的話,就可以使用默認的。而且這兩種持久化方式可以同時使用。
redis-cluster集群,這種方式采用的是無中心結(jié)構(gòu),每個節(jié)點保存數(shù)據(jù)和整個集群的狀態(tài),每個節(jié)點都和其
他所有節(jié)點連接。如果使用的話就用redis-cluster集群。集群這塊是公司運維搭建的,具體怎么搭建不是太了解。
我們項目中redis集群主要搭建了6臺,3主(為了保證redis的投票機制)3從(高可用),每個主服務(wù)器都有
一個從服務(wù)器,作為備份機。所有的節(jié)點都通過PING-PONG機制彼此互相連接;客戶端與redis集群連接,只
需要連接集群中的任何一個節(jié)點即可;Redis-cluster中內(nèi)置了16384個哈希槽,Redis-cluster把所有的物
理節(jié)點映射到【0-16383】slot上,負責(zé)維護。
Redis是有事務(wù)的,redis中的事務(wù)是一組命令的集合,這組命令要么都執(zhí)行,要不都不執(zhí)行,保證一個事務(wù)中
的命令依次執(zhí)行而不被其他命令插入。redis的事務(wù)是不支持回滾操作的。redis事務(wù)的實現(xiàn),需要用到
MULTI(事務(wù)的開始)和EXEC(事務(wù)的結(jié)束)命令 ;
緩存穿透:緩存查詢一般都是通過key去查找value,如果不存在對應(yīng)的value,就要去數(shù)據(jù)庫中查找。如果這
個key對應(yīng)的value在數(shù)據(jù)庫中也不存在,并且對該key并發(fā)請求很大,就會對數(shù)據(jù)庫產(chǎn)生很大的壓力,這就叫緩存穿透
解決方案:
1.對所有可能查詢的參數(shù)以hash形式存儲,在控制層先進行校驗,不符合則丟棄。
2.將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中,一個一定不存在的數(shù)據(jù)會被這個bitmap攔截掉,從
而避免了對底層存儲系統(tǒng)的查詢壓力。
3.如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個空結(jié)果進行緩存,但
它的過期時間會很短,最長不超過五分鐘。
緩存雪崩:當(dāng)緩存服務(wù)器重啟或者大量緩存集中在一段時間內(nèi)失效,發(fā)生大量的緩存穿透,這樣在失效的瞬間
對數(shù)據(jù)庫的訪問壓力就比較大,所有的查詢都落在數(shù)據(jù)庫上,造成了緩存雪崩。 這個沒有完美解決辦法,但可
以分析用戶行為,盡量讓失效時間點均勻分布。大多數(shù)系統(tǒng)設(shè)計者考慮用加鎖或者隊列的方式保證緩存的單線
程(進程)寫,從而避免失效時大量的并發(fā)請求落到底層存儲系統(tǒng)上。
解決方案:
1.在緩存失效后,通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢
數(shù)據(jù)和寫緩存,其他線程等待。
2.可以通過緩存reload機制,預(yù)先去更新緩存,再即將發(fā)生大并發(fā)訪問前手動觸發(fā)加載緩存
3.不同的key,設(shè)置不同的過期時間,讓緩存失效的時間點盡量均勻
4.做二級緩存,或者雙緩存策略。A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間
設(shè)置為短期,A2設(shè)置為長期。
redis的安全機制(你們公司redis的安全這方面怎么考慮的?)
漏洞介紹:redis默認情況下,會綁定在bind 0.0.0.0:6379,這樣就會將redis的服務(wù)暴露到公網(wǎng)上,如果
在沒有開啟認證的情況下,可以導(dǎo)致任意用戶在訪問目標服務(wù)器的情況下,未授權(quán)就可訪問redis以及讀取
redis的數(shù)據(jù),攻擊者就可以在未授權(quán)訪問redis的情況下可以利用redis的相關(guān)方法,成功在redis服務(wù)器上
寫入公鑰,進而可以直接使用私鑰進行直接登錄目標主機;
解決方案:
1.禁止一些高危命令。修改redis.conf文件,用來禁止遠程修改DB文件地址
2.以低權(quán)限運行redis服務(wù)。為redis服務(wù)創(chuàng)建單獨的用戶和根目錄,并且配置禁止登錄;
3.為redis添加密碼驗證。修改redis.conf文件,添加requirepass mypassword;
4.禁止外網(wǎng)訪問redis。修改redis.conf文件,添加或修改 bind 127.0.0.1,使得redis服務(wù)只在當(dāng)前主機使用;
5.做log監(jiān)控,及時發(fā)現(xiàn)攻擊;
redis的哨兵機制(redis2.6以后出現(xiàn)的)
哨兵機制:
監(jiān)控:監(jiān)控主數(shù)據(jù)庫和從數(shù)據(jù)庫是否正常運行;
提醒:當(dāng)被監(jiān)控的某個redis出現(xiàn)問題的時候,哨兵可以通過API向管理員或者其他應(yīng)用程序發(fā)送通知;
自動故障遷移:主數(shù)據(jù)庫出現(xiàn)故障時,可以自動將從數(shù)據(jù)庫轉(zhuǎn)化為主數(shù)據(jù)庫,實現(xiàn)自動切換;
如果master主服務(wù)器設(shè)置了密碼,記得在哨兵的配置文件(sentinel.conf)里面配置訪問密碼
redis中對于生存時間的應(yīng)用
Redis中可以使用expire命令設(shè)置一個鍵的生存時間,到時間后redis會自動刪除;
應(yīng)用場景:
設(shè)置限制的優(yōu)惠活動的信息;
一些及時需要更新的數(shù)據(jù),積分排行榜;
手機驗證碼的時間;
限制網(wǎng)站訪客訪問頻率;
講講ActiveMQ和其他消息中間件之間的區(qū)別
activemq的原理
原理:生產(chǎn)者生產(chǎn)消息, 把消息發(fā)送給activemq。 Activemq 接收到消息, 然后查看有多少個消費者,
然后把消息轉(zhuǎn)發(fā)給消費者, 此過程中生產(chǎn)者無需參與。 消費者接收到消息后做相應(yīng)的處理和生產(chǎn)者沒有任何關(guān)系
對比RabbitMQ
RabbitMQ的協(xié)議是AMQP,而ActiveMQ使用的是JMS協(xié)議。顧名思義JMS是針對Java體系的傳輸協(xié)議,隊列兩
端必須有JVM,所以如果開發(fā)環(huán)境都是java的話推薦使用ActiveMQ,可以用Java的一些對象進行傳遞比如
Map、Blob(二進制大數(shù)據(jù))、Stream等。而AMQP通用行較強,非java環(huán)境經(jīng)常使用,傳輸內(nèi)容就是標準字
符串。RabbitMQ安裝比較麻煩。ActiveMQ解壓即可用不用任何安裝。
對比KafKa
Kafka性能超過ActiveMQ等傳統(tǒng)MQ工具,集群擴展性好。
弊端是:
1、在傳輸過程中可能會出現(xiàn)消息重復(fù)的情況,
2、不保證發(fā)送順序
3、一些傳統(tǒng)MQ的功能沒有,比如消息的事務(wù)功能。所以通常用Kafka處理大數(shù)據(jù)日志。
對比Redis
其實Redis本身利用List可以實現(xiàn)消息隊列的功能,但是功能很少,而且隊列體積較大時性能會急劇下降。對
于數(shù)據(jù)量不大、業(yè)務(wù)簡單的場景可以使用。
如何解決消息重復(fù)問題
所謂消息重復(fù),就是消費者接收到了重復(fù)的消息,一般來說我們對于這個問題的處理要把握下面幾點,
①.消息不丟失(上面已經(jīng)處理了)
②.消息不重復(fù)執(zhí)行
一般來說我們可以在業(yè)務(wù)段加一張表,用來存放消息是否執(zhí)行成功,每次業(yè)務(wù)事物commit之后,告知服務(wù)端,已經(jīng)
處理過該消息,這樣即使你消息重發(fā)了,也不會導(dǎo)致重復(fù)處理
大致流程如下:業(yè)務(wù)端的表記錄已經(jīng)處理消息的id,每次一個消息進來之前先判斷該消息是否執(zhí)行過,如果執(zhí)行
過就放棄,如果沒有執(zhí)行就開始執(zhí)行消息,消息執(zhí)行完成之后存入這個消息的id
講講分布式事務(wù)的異步通信問題解決方案
問題介紹:一個消息發(fā)送過去了,不管結(jié)果如何發(fā)送端都不會原地等待接收端。直到接收端再推送回來回執(zhí)消息,
發(fā)送端才直到結(jié)果。但是也有可能發(fā)送端消息發(fā)送后,石沉大海,杳無音信。這時候就需要一種機制能夠?qū)@種不
確定性進行補充。
解決方案:
你給有很多筆友,平時寫信一去一回,但是有時候會遇到遲遲沒有回信的情況。那么針對這種偶爾出現(xiàn)的情況,你
可以選擇兩種策略。一種方案是你發(fā)信的時候用定個鬧鐘,設(shè)定1天以后去問一下對方收沒收到信。另一種方案就
是每天夜里定個時間查看一下所有發(fā)過信但是已經(jīng)一天沒收到回復(fù)的信。然后挨個打個電話問一下。
第一種策略就是實現(xiàn)起來就是延遲隊列,第二種策略就是定時輪詢掃描。
二者的區(qū)別是延遲隊列更加精準,但是如果周期太長,任務(wù)留在延遲隊列中時間的就會非常長,會把隊列變得冗
長。比如用戶幾天后待辦提醒,生日提醒。
那么如果遇到這種長周期的事件,而且并不需要精確到分秒級的事件,可以利用定時掃描來實現(xiàn),尤其是比較消耗
性能的大范圍掃描,可以安排到夜間執(zhí)行。
講講怎么解單點登錄的訪問,分布式session跨域問題
單點登錄是相互信任的系統(tǒng)模塊登錄一個模塊后,其他模塊不需要重復(fù)登錄即認證通過。
采用CAS單點登錄框架,首先CAS有兩大部分:客戶端和服務(wù)端。
服務(wù)端就是一個web工程部署在tomcat中。在服務(wù)端完成用戶認證操作。每次訪問系統(tǒng)模塊時,需要去CAS完成獲
取ticket。當(dāng)驗證通過后,訪問繼續(xù)操作。對于CAS服務(wù)端來說,我們訪問的應(yīng)用模塊就是CAS客戶端。
什么是跨域?
當(dāng)異步請求時,訪問的請求地址的協(xié)議、ip地址、端口號任意一個與當(dāng)前站點不同時,就會涉及跨域訪問。
什么時候涉及跨域問題?當(dāng)涉及前端異步請求的時候才涉及跨域。
解決方案:
1、jQuery提供了jsonp實現(xiàn)
2、W3C標準提供了CORS(跨域資源共享)解決方案。
用了CAS,所有應(yīng)用項目中如果需要登錄時在web.xml中配置過濾器做請求轉(zhuǎn)發(fā)到cas端工作原理是在cas登錄后會
給瀏覽器發(fā)送一個票據(jù)(ticket),瀏覽器cookie中會緩存這個ticket,在登錄其他項目時會拿著瀏覽器的
ticket轉(zhuǎn)發(fā)到cas,到cas后根據(jù)票據(jù)判斷是否登錄
講講linux命令awk、cat、sort、cut、grep、uniq、wc、top、find、sed等作用
awk:相較于sed 常常作用于一整個行的處理,awk 則比較傾向于一行當(dāng)中分成數(shù)個『字段』來處理。 因此,awk
相當(dāng)?shù)倪m合處理小型的數(shù)據(jù)數(shù)據(jù)處理
cat:主要用來查看文件內(nèi)容,創(chuàng)建文件,文件合并,追加文件內(nèi)容等功能。
sort:功能:排序文本,默認對整列有效
cut:cut命令可以從一個文本文件或者文本流中提取文本列
grep:是一種強大的文本搜索工具,它能使用正則表達式搜索文本,并把匹配的行打印出來
uniq:功能:去除重復(fù)行,只會統(tǒng)計相鄰的
wc:功能: 統(tǒng)計文件行數(shù)、字節(jié)、字符數(shù)
top:用來監(jiān)控Linux的系統(tǒng)狀況,比如cpu、內(nèi)存的使用
find:功能: 搜索文件目錄層次結(jié)構(gòu)
sed:sed 是一種在線編輯器,它一次處理一行內(nèi)容
講講什么是死鎖,怎么解決死鎖,表級鎖和行級鎖,悲觀鎖與樂觀鎖以及線程同步鎖區(qū)別
死鎖:打個比方,你去面試,面試官問你,你告訴我什么是死鎖我就讓你進公司。你回答說你讓我進公司我就告訴你什么是死鎖
互斥條件:資源不能被共享,只能由一個進程使用。
請求與保持條件:進程已獲得了一些資源,但因請求其它資源被阻塞時,對已獲得的資源保持不放。
不可搶占條件:有些系統(tǒng)資源是不可搶占的,當(dāng)某個進程已獲得這種資源后,系統(tǒng)不能強行收回,只能由進程
使用完時自己釋放。
循環(huán)等待條件:若干個進程形成環(huán)形鏈,每個都占用對方申請的下一個資源。
(1) 死鎖預(yù)防:破壞導(dǎo)致死鎖必要條件中的任意一個就可以預(yù)防死鎖。例如,要求用戶申請資源時一次性申請
所需要的全部資源,這就破壞了保持和等待條件;將資源分層,得到上一層資源后,才能夠申請下一層資源,
它破壞了環(huán)路等待條件。預(yù)防通常會降低系統(tǒng)的效率。
(2) 死鎖避免:避免是指進程在每次申請資源時判斷這些操作是否安全,例如,使用銀行家算法。死鎖避免算
法的執(zhí)行會增加系統(tǒng)的開銷。
(3) 死鎖檢測:死鎖預(yù)防和避免都是事前措施,而死鎖的檢測則是判斷系統(tǒng)是否處于死鎖狀態(tài),如果是,則執(zhí)
行死鎖解除策略。
(4) 死鎖解除:這是與死鎖檢測結(jié)合使用的,它使用的方式就是剝奪。即將某進程所擁有的資源強行收回,分
配給其他的進程。
表級鎖: 開銷小,加鎖快;不會出現(xiàn)死鎖(因為MyISAM會一次性獲得SQL所需的全部鎖);鎖定粒度大,發(fā)生鎖沖
突的概率最高,并發(fā)度最低。
行級鎖: 開銷大,加鎖慢;會出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
悲觀鎖:總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時候都認為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣
別人想拿這個數(shù)據(jù)就會阻塞直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖
等,讀鎖,寫鎖等,都是在做操作之前先上鎖。再比如Java里面的同步原語synchronized關(guān)鍵字的實現(xiàn)也是悲觀
鎖。通過for update來實現(xiàn)
樂觀鎖:顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會
判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以
提高吞吐量,像數(shù)據(jù)庫提供的類似于write_condition機制,其實都是提供的樂觀鎖。在Java中
java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現(xiàn)方式CAS實現(xiàn)的。通過version版本字段來實現(xiàn)
同步鎖:
場景:在開發(fā)中,遇到耗時的操作,我們需要把耗時的邏輯放入子線程中執(zhí)行,防止卡頓。二個線程分別執(zhí)行兩個
任務(wù),同時執(zhí)行完成,同時解析文件,獲取數(shù)據(jù)后,同時插入數(shù)據(jù)庫,由于插入的表比較多,這樣容易出現(xiàn)插入錯
亂的bug
采用synchronized:
聲明該方法為同步方法,如果一個方法正在執(zhí)行,別的方法調(diào)用,則處于等待狀態(tài)。當(dāng)這個方法執(zhí)行完成后,可以
調(diào)用解鎖方法,wait():釋放占有的對象鎖,線程進入等待池。
區(qū)別:
synchronized是在JVM層面實現(xiàn)的,因此系統(tǒng)可以監(jiān)控鎖的釋放與否,而ReentrantLock使用代碼實現(xiàn)的,系統(tǒng)
無法自動釋放鎖,需要在代碼中finally子句中顯式釋放鎖lock.unlock();
在并發(fā)量比較小的情況下,使用synchronized是個不錯的選擇,但是在并發(fā)量比較高的情況下,其性能下降
很嚴重,此時ReentrantLock是個不錯的方案。
講講怎么加快訪問速度,怎樣進行程序性能調(diào)優(yōu)
加快訪問:
硬件上加大網(wǎng)絡(luò)帶寬、和服務(wù)器內(nèi)存
代碼的處理:靜態(tài)頁面、緩存、優(yōu)化sql、創(chuàng)建索引等方案
系統(tǒng)性能就是兩個事:
Throughput ,吞吐量。也就是每秒鐘可以處理的請求數(shù),任務(wù)數(shù)。
Latency, 系統(tǒng)延遲。也就是系統(tǒng)在處理一個請求或一個任務(wù)時的延遲。
那么Latency越好,能支持的Throughput就會越高。因為Latency短說明處理速度快,于是就可以處理更多的請求。
提高吞吐量:分布式集群,模塊解藕,設(shè)計模式
系統(tǒng)延遲:異步通信
講講緩存的設(shè)計和優(yōu)化,緩存和數(shù)據(jù)庫一致性同步解決方案
1.降低后端負載:對于高消耗的SQL:join結(jié)果集、分組統(tǒng)計結(jié)果;對這些結(jié)果進行緩存。
2.加速請求響應(yīng)
3.大量寫合并為批量寫:如計數(shù)器先redis累加再批量寫入DB
4.超時剔除:例如expire
5.主動更新:開發(fā)控制生命周期(最終一致性,時間間隔比較短)
6.緩存空對象
7.布隆過濾器攔截
8.命令本身的效率:例如sql優(yōu)化,命令優(yōu)化
9.網(wǎng)絡(luò)次數(shù):減少通信次數(shù)
10.降低接入成本:長連/連接池,NIO等。
11.IO訪問合并
目的:要減少緩存重建次數(shù)、數(shù)據(jù)盡可能一致、減少潛在危險。
解決方案:
1.互斥鎖setex,setnx:
如果 set(nx 和 ex) 結(jié)果為 true,說明此時沒有其他線程重建緩存,那么當(dāng)前線程執(zhí)行緩存構(gòu)建邏輯。
如果 setnx(nx 和 ex) 結(jié)果為 false,說明此時已經(jīng)有其他線程正在執(zhí)行構(gòu)建緩存的工作,那么當(dāng)前線程將休
息指定時間 ( 例如這里是 50 毫秒,取決于構(gòu)建緩存的速度 ) 后,重新執(zhí)行函數(shù),直到獲取到數(shù)據(jù)。
2永遠不過期:
熱點key,無非是并發(fā)特別大一級重建緩存時間比較長,如果直接設(shè)置過期時間,那么時間到的時候,巨大的訪
問量會壓迫到數(shù)據(jù)庫上,所以要給熱點key的val增加一個邏輯過期時間字段,并發(fā)訪問的時候,判斷這個邏輯
字段的時間值是否大于當(dāng)前時間,大于了說明要對緩存進行更新了,那么這個時候,依然讓所有線程訪問老的
緩存,因為緩存并沒有設(shè)置過期,但是另開一個線程對緩存進行重構(gòu)。等重構(gòu)成功,即執(zhí)行了redis set操作
之后,所有的線程就可以訪問到重構(gòu)后的緩存中的新的內(nèi)容了
從緩存層面來看,確實沒有設(shè)置過期時間,所以不會出現(xiàn)熱點 key 過期后產(chǎn)生的問題,也就是“物理”不過期。
從功能層面來看,為每個 value 設(shè)置一個邏輯過期時間,當(dāng)發(fā)現(xiàn)超過邏輯過期時間后,會使用單獨的線程去構(gòu)建緩存。
一致性問題:
1.先刪除緩存,然后在更新數(shù)據(jù)庫,如果刪除緩存失敗,那就不要更新數(shù)據(jù)庫,如果說刪除緩存成功,而更新
數(shù)據(jù)庫失敗,那查詢的時候只是從數(shù)據(jù)庫里查了舊的數(shù)據(jù)而已,這樣就能保持數(shù)據(jù)庫與緩存的一致性。
2.先去緩存里看下有沒有數(shù)據(jù),如果沒有,可以先去隊列里看是否有相同數(shù)據(jù)在做更新,發(fā)現(xiàn)隊列里有一個請
求了,那么就不要放新的操作進去了,用一個while(true)循環(huán)去查詢緩存,循環(huán)個200MS左右再次發(fā)送到
隊列里去,然后同步等待緩存更新完成。
講講消息隊列和消息被重復(fù)消費怎么處理,消費者接收不到消息怎么辦
什么是消息隊列?
就是消息的傳輸過程中保存消息的容器。
消息隊列都解決了什么問題?
異步,并行,解耦,排隊
消息模式?
訂閱,點對點
一、重復(fù)消費:Queue支持存在多個消費者,但是對一個消息而言,只會有一個消費者可以消費。
二、丟消息:
1.用持久化消息
2.非持久化消息及時處理不要堆積
3.啟動事務(wù),啟動事務(wù)后,commit()方法會負責(zé)等待服務(wù)器的返回,也就不會關(guān)閉連接導(dǎo)致消息丟失。
三、消息重發(fā):
消息被重新傳遞給客戶端:
1、使用事務(wù)會話,并調(diào)用滾退()。
2、在調(diào)用commit()之前關(guān)閉事務(wù)會話。
3、會話使用CLIENT_ACKNOWLEDGE簽收模式,并Session .recover()重發(fā)被調(diào)用。
4、客戶端連接超時(也許正在執(zhí)行的代碼要比配置的超時周期更長)。
四、不消費:去ActiveMQ.DLQ里找找
什么是ActiveMQ.DLQ?
1.一旦消息的重發(fā)嘗試超過了為重發(fā)策略配置的最大重發(fā)次數(shù),一個“Poison ACK”被發(fā)送回the broker,讓
他知道消息被認為是毒丸。the broker然后接收消息并將其發(fā)送到死信隊列,以便以后可以進行分析。
2.在activemq中死信隊列叫做ActiveMQ.DLQ。所有無法傳遞的消息將被發(fā)送到這個隊列,這很難管理。
3.因此,您可以在Activemq.xml配置文件的目標策略映射中設(shè)置個體死信策略,它允許您為隊列或主題指定
特定的死信隊列前綴。
Mq消費者接受不到消息存在2中情況:
1. 處理失敗 指的是MessageListener的onMessage方法里拋出RuntimeException。
2. Message頭里有兩個相關(guān)字段:Redelivered默認為false,redeliveryCounter默認為0。
3. 消息先由broker發(fā)送給consumer,consumer調(diào)用listener,如果處理失敗,本地
redeliveryCounter++,給broker一個特定應(yīng)答,broker端的message里redeliveryCounter++,延遲一點
時間繼續(xù)調(diào)用,默認1s。超過6次,則給broker另一個特定應(yīng)答,broker就直接發(fā)送消息到DLQ。
4. 如果失敗2次,consumer重啟,則broker再推過來的消息里,redeliveryCounter=2,本地只能再重試4次
即會進入DLQ。
5. 重試的特定應(yīng)答發(fā)送到broker,broker即會在內(nèi)存將消息的redelivered設(shè)置為
true,redeliveryCounter++,但是這兩個字段都沒有持久化,即沒有修改存儲中的消息記錄。所以broker重
啟時這兩個字段會被重置為默認值。
講講SOA與分布式的區(qū)別,zookeeper或者activeMQ服務(wù)掛了怎么辦
SOA和分布式的區(qū)別?
SOA,將工程拆分成服務(wù)層、表現(xiàn)層兩個工程,服務(wù)層中包含業(yè)務(wù)邏輯,只需要對外提供服務(wù)即可。表現(xiàn)層只需要
處理和頁面的交互,業(yè)務(wù)邏輯都是調(diào)用服務(wù)層的服務(wù)來實現(xiàn)。
分布式,主要還是從部署的角度,將應(yīng)用按照訪問壓力進行歸類,主要目標是充分利用服務(wù)器的資源,避免資源分配不均
如果activeMQ的服務(wù)掛了,怎么辦?
1、在通常的情況下,非持久化消息是存儲在內(nèi)存中的,持久化消息是存儲在文件中的,它們的最大限制在配置文
件的<systemUsage>節(jié)點中配置。但是,在非持久化消息堆積到一定程度,內(nèi)存告急的時候,ActiveMQ會將內(nèi)存
中的非持久化消息寫入臨時文件中,以騰出內(nèi)存。雖然都保存到了文件里,但它和持久化消息的區(qū)別是,重啟后持
久化消息會從文件中恢復(fù),非持久化的臨時文件會直接刪除。
2、考慮高可用,實現(xiàn)activemq集群。
如果zookeeper服務(wù)掛了怎么辦?
注冊中心對等集群,任意一臺宕掉后,會自動切換到另一臺
注冊中心全部宕掉,服務(wù)提供者和消費者仍可以通過本地緩存通訊
服務(wù)提供者無狀態(tài),任一臺宕機后,不影響使用
服務(wù)提供者全部宕機,服務(wù)消費者會無法使用,并無限次重連等待服務(wù)者恢復(fù)
講講JUC的輔助類
ReentrantReadWriteLock:讀寫鎖
CountDownLatch:減少計數(shù)
CyclicBarrier:循環(huán)柵欄
Semaphore:信號燈