面試:第三章:中級綜合
SSM框架面試問題
講下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對象當中返回。
3、DispatcherServlet根據(jù)獲得的Handler,選擇一個合適的HandlerAdapter。HandlerAdapter的設(shè)計符合面向?qū)ο笾械膯我宦氊熢瓌t,代碼結(jié)構(gòu)清晰,便于維護,最為重要的是,代碼的可復(fù)制性高。HandlerAdapter會被用于處理多種Handler,調(diào)用Handler實際處理請求的方法。
4、提取請求中的模型數(shù)據(jù),開始執(zhí)行Handler(Controller)。在填充Handler的入?yún)⑦^程中,根據(jù)配置,spring將幫助做一些額外的工作
消息轉(zhuǎn)換:將請求的消息,如json、xml等數(shù)據(jù)轉(zhuǎn)換成一個對象,將對象轉(zhuǎn)換為指定的響應(yīng)信息。
數(shù)據(jù)轉(zhuǎn)換:對請求消息進行數(shù)據(jù)轉(zhuǎn)換,如String轉(zhuǎn)換成Integer、Double等。
數(shù)據(jù)格式化:對請求的消息進行數(shù)據(jù)格式化,如將字符串轉(zhuǎn)換為格式化數(shù)字或格式化日期等。
數(shù)據(jù)驗證:驗證數(shù)據(jù)的有效性如長度、格式等,驗證結(jié)果存儲到BindingResult或Error中。
5、Handler執(zhí)行完成后,向DispatcherServlet返回一個ModelAndView對象,ModelAndView對象中應(yīng)該包含視圖名或視圖模型。
6、根據(jù)返回的ModelAndView對象,選擇一個合適的ViewResolver(視圖解析器)返回給DispatcherServlet。
7、ViewResolver結(jié)合Model和View來渲染視圖。
8、將視圖渲染結(jié)果返回給客戶端。
以上8個步驟,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver等對象協(xié)同工作,完成SpringMVC請求—>響應(yīng)的整個工作流程,這些對象完成的工作對于開發(fā)者來說都是不可見的,開發(fā)者并不需要關(guān)心這些對象是如何工作的,開發(fā)者,只需要在Handler(Controller)當中完成對請求的業(yè)務(wù)處理。
圖片怎么上傳
前端實現(xiàn)異步上傳,后端使用springmvc的MultipartFile類型來接收,放到分布式圖片服務(wù)器中,服務(wù)器返回圖片路徑把路徑返回頁面回顯圖片,開發(fā)或者測試環(huán)境可以使用FastDFS
微服務(wù)和SOA有什么區(qū)別?
如果一句話來談SOA和微服務(wù)的區(qū)別,即微服務(wù)不再強調(diào)傳統(tǒng)SOA架構(gòu)里面比較重的ESB企業(yè)服務(wù)總線,同時SOA的思想進入到單個業(yè)務(wù)系統(tǒng)內(nèi)部實現(xiàn)真正的組件化。說的更直白一點就是微服務(wù)被拆分的粒度更小
spring框架AOP執(zhí)行原理簡單說下?還有就是AOP在事務(wù)管理方面是怎么實現(xiàn)的?
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ù)控制。
Spring 分布式事務(wù)如何處理的?
第一種方案:可靠消息最終一致性,需要業(yè)務(wù)系統(tǒng)結(jié)合MQ消息中間件實現(xiàn),在實現(xiàn)過程中需要保證消息的成功發(fā)送及成功消費。即需要通過業(yè)務(wù)系統(tǒng)控制MQ的消息狀態(tài)
第二種方案:TCC補償性,分為三個階段TRYING-CONFIRMING-CANCELING。每個階段做不同的處理。
TRYING階段主要是對業(yè)務(wù)系統(tǒng)進行檢測及資源預(yù)留
CONFIRMING階段是做業(yè)務(wù)提交,通過TRYING階段執(zhí)行成功后,再執(zhí)行該階段。默認如果TRYING階段執(zhí)行成功,CONFIRMING就一定能成功。
CANCELING階段是回對業(yè)務(wù)做回滾,在TRYING階段中,如果存在分支事務(wù)TRYING失敗,則需要調(diào)用CANCELING將已預(yù)留的資源進行釋放。
Springboot用過沒,跟我說說,他的特點?
Springboot是從無數(shù)企業(yè)實戰(zhàn)開發(fā)中總結(jié)出來的一個更加精煉的框架,使得開發(fā)更加簡單,能使用寥寥數(shù)行代碼,完成一系列任務(wù)。
1) Springboot解決那些問題
a) 編碼更簡單
i. Spring框架由于超重量級的XML,annotation配置,使得系統(tǒng)變得很笨重,難以維護
ii. Springboot采用約點大于配置的方法,直接引入依賴,即可實現(xiàn)代碼的開發(fā)
b) 配置更簡單
Xml文件使用javaConfig代替,XML中bean的創(chuàng)建,使用@bean代替后可以直接注入。
配置文件變少很多,就是application.yml
c) 部署更簡單
d) 監(jiān)控更簡單
Spring-boot-start-actuator:
可以查看屬性配置
線程工作狀態(tài)
環(huán)境變量
JVM性能監(jiān)控
支付接口是怎么做的?
微信支付
調(diào)用微信的支付接口,參考微信提供的api
使用了微信的統(tǒng)一下單接口和查詢支付狀態(tài)接口
每個接口需要的參數(shù)放入到map中使用微信提供的sdk轉(zhuǎn)成XML字符串,httpClient遠程提交參數(shù)和接收結(jié)果。
支付寶支付
詳情https://www.alipay.com/
SpringBoot相關(guān)面試題
什么是 Spring Boot?
Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各種啟動器,開發(fā)者能快速上手。
為什么要用 Spring Boot?
Spring Boot 優(yōu)點非常多,如:
獨立運行
簡化配置
自動配置
無代碼生成和XML配置
應(yīng)用監(jiān)控
上手容易
Spring Boot 的核心配置文件有哪幾個?它們的區(qū)別是什么?
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件這個容易理解,主要用于 Spring Boot 項目的自動化配置。
bootstrap 配置文件有以下幾個應(yīng)用場景。
使用 Spring Cloud Config 配置中心時,這時需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來加載外部配置中心的配置信息;
一些固定的不能被覆蓋的屬性;
一些加密/解密的場景
Spring Boot 的配置文件有哪幾種格式?它們有什么區(qū)別?
.properties 和 .yml,它們的區(qū)別主要是書寫格式不同。
Spring Boot 的核心注解是哪個?它主要由哪幾個注解組成的?
啟動類上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要組合包含了以下 3 個注解:
@SpringBootConfiguration:組合了 @Configuration 注解,實現(xiàn)配置文件的功能。
@EnableAutoConfiguration:打開自動配置的功能,也可以關(guān)閉某個自動配置的選項,如關(guān)閉數(shù)據(jù)源自動配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring組件掃描。
開啟 Spring Boot 特性有哪幾種方式?
1)繼承spring-boot-starter-parent項目
2)導(dǎo)入spring-boot-dependencies項目依賴
Spring Boot 需要獨立的容器運行嗎?
可以不需要,內(nèi)置了 Tomcat/ Jetty 等容器.
運行 Spring Boot 有哪幾種方式?
1)打包用命令或者放到容器中運行
2)用 Maven/ Gradle 插件運行
3)直接執(zhí)行 main 方法運行
Spring Boot 自動配置原理是什么?
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據(jù)類路徑下是否有這個類去自動配置。
你如何理解 Spring Boot 中的 Starters?
Starters可以理解為啟動器,它包含了一系列可以集成到應(yīng)用里面的依賴包,你可以一站式集成 Spring 及其他技術(shù),而不需要到處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數(shù)據(jù)庫,只要加入 spring-boot-starter-data-jpa 啟動器依賴就能使用了。
Starters包含了許多項目中需要用到的依賴,它們能快速持續(xù)的運行,都是一系列得到支持的管理傳遞性依賴.
如何在 Spring Boot 啟動的時候運行一些特定的代碼?
可以實現(xiàn)接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現(xiàn)方式一樣,它們都只提供了一個 run 方法.
Spring Boot 有哪幾種讀取配置的方式?
Spring Boot 可以通過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量
電商項目業(yè)務(wù)面試問題
哪些情況用到activeMq?
商品上架后更新ES索引庫、更新靜態(tài)頁、發(fā)送短信
秒殺的時候,只有最后一件物品,該怎么去搶或者分配?
秒殺商品的庫存都會放到redis中,在客戶下單時就減庫存,減完庫存會判斷庫存是否為大于 0,如果小于0,表示庫存不足,剛才減去的數(shù)量再恢復(fù),整個過程使用redis的watch鎖。
你項目對于訂單是怎么處理的,假如一個客戶在下訂單的時候沒有購買怎么辦,對于顧客在購買商品的時候你們怎么處理你們的庫存?
訂單表中設(shè)置了一個過期時間,每天會有定時任務(wù)來掃描訂單表數(shù)據(jù),如果到達預(yù)訂的過期時間沒有付款就會取消此訂單交易。
關(guān)于庫存的設(shè)計是這樣的:
普通商品在發(fā)貨時才去更新庫存,如果庫存不足商家會馬上補貨
秒殺的商品會在客戶下單時就減庫存,如果在規(guī)定時間(半個小時)沒有付款,會取消此訂單把庫存還原
redis存儲格式的選擇
redis支持的數(shù)據(jù)結(jié)構(gòu)總共有5種:hash、value、list、set、zset,其中項目中用到最多是hash
商品表中的數(shù)據(jù)是哪里來的
商品表的數(shù)據(jù)是在商家管理后臺中由商家錄入的。數(shù)據(jù)分別錄入到商品表、商品描述表和商品項表
當初設(shè)計項目時預(yù)計的訪問量計劃是多少
訪問量計劃是3000至5000
簡單介紹一下你的這個項目以及項目中涉及到的技術(shù)框架以及使用場景以及你主要負責項目中的哪一塊?
項目介紹時,先整體介紹是什么項目,項目主要是做啥的,為什么會做這個項目(市場需求)?例如:XXX電商項目,是一個B2B2C綜合電商平臺。由三個系統(tǒng)組成,包含:運營商管理后臺、商家管理后臺、網(wǎng)站前臺。運營商平臺主要負責基礎(chǔ)數(shù)據(jù)維護、商家審核、商品審核等。商家管理后臺主要負責商家入駐、商品錄入/修改、商品上下架等。網(wǎng)站前臺主要負責商品銷售。包含:網(wǎng)站首頁、商品搜索、商品詳情展示、購物車、訂單、支付、用戶中心等模塊。
再介紹自己在項目中做的功能模塊。例如:運營商管理后臺的品牌、規(guī)格數(shù)據(jù)錄入,已經(jīng)商品管理后臺商品錄入功能。同時,實現(xiàn)了網(wǎng)站前臺系統(tǒng)中的商品搜索、購物車等功能模塊。
然后介紹里面使用的技術(shù):例如:dubbo分布式框架、ssm、es、redis、activeMQ、支付寶支付等等。最好是結(jié)合技術(shù)講解項目功能點如何實現(xiàn)。
秒殺系統(tǒng)中如何防止超售?如何避免腳本進行惡意刷單?
防止超售解決方案:將存庫從MySQL前移到Redis中,所有的寫操作放到內(nèi)存中,由于Redis中不存在鎖故不會出現(xiàn)互相等待,并且由于Redis的寫性能和讀性能都遠高于MySQL,這就解決了高并發(fā)下的性能問題。然后通過隊列等異步手段,將變化的數(shù)據(jù)異步寫入到DB中。當達到庫存閥值的時候就不在消費隊列,并關(guān)閉購買功能。
避免腳本惡意刷單:采用IP級別的限流,即針對某一個IP,限制單位時間內(nèi)發(fā)起請求數(shù)量。
單點登錄你們是自己編寫的還是使用通用的CAS?
項目使用通用的CAS框架。
如果一個用戶的token被其他用戶劫持了,怎樣解決這個安全問題。
a、在存儲的時候把token進行對稱加密存儲,用時解開。
b、將請求URL、時間戳、token三者進行合并加鹽簽名,服務(wù)端校驗有效性。
c、HTTPS對URL進行加密
項目部署上線后,運營商管理,商品審核等后臺流量問題?
先詢問流量是指哪方面?流量分為三種,一種是商家流量,另一種是用戶流量,第三種運營商流量。
解決方案:
這三種流量對系統(tǒng)運行造成很大壓力,隨著項目上線時間增長,壓力會越來越大,因此我們要減輕系統(tǒng)訪問壓力 ,就需要做一系列優(yōu)化措施。
具體優(yōu)化如下:
數(shù)據(jù)層面的優(yōu)化:
從數(shù)據(jù)庫層面做優(yōu)化,比如:索引,緩存,集群,讀寫分離,主從復(fù)制,分表,分庫。
從數(shù)據(jù)庫設(shè)計層面的優(yōu)化:比如減少表關(guān)聯(lián),加入冗余字段
從緩存方面優(yōu)化:比如redis實現(xiàn)數(shù)據(jù)緩存,減輕數(shù)據(jù)庫壓力
從搜索上進行優(yōu)化:比如查找索引庫
項目層面的優(yōu)化:
采用面向服務(wù)的分布式架構(gòu):分擔服務(wù)器壓力 ,提高項目并發(fā)量。 比如dubbox+zookeeper分布式架構(gòu)
采用分布式文件系統(tǒng)實現(xiàn)海量文件存儲:如采用fastdfs實現(xiàn)海量圖片存儲,提高文件的訪問速度。
采用mq使用服務(wù)進一步解藕:同步索引庫,同步靜態(tài)資源,短信發(fā)送
服務(wù)器層面的優(yōu)化:
集群思想的使用:tomcat,zookeeper,redis,mysql等
Tomcat異步通信的使用,tomcat連接池配置
秒殺和團購業(yè)務(wù)實現(xiàn)思路
回答:
將商品數(shù)量查詢出存入到redis中,所有用戶下單后,減掉redis中的數(shù)量
如果并發(fā)量很大時,還要考慮高并發(fā)問題,所以可以加入mq消息中間件處理搶單問題,再結(jié)合redis實現(xiàn)庫存減少操作。高并發(fā)方面還可以考慮CDN,Nginx負載均衡等
你們項目中使用的安全框架是什么?
使用springSecurity 或者shiro,校驗用戶登錄和用戶權(quán)限!
項目中使用到的應(yīng)用服務(wù)器是什么?
Tomcat+nginx
講一下每臺服務(wù)器的集群數(shù)量:
項目中一共15臺項目服務(wù),那么為了每一臺高可用一主一備,但首頁項目高并發(fā)設(shè)為四臺服務(wù)器,則一共32臺項目服務(wù)器,再加redis集群用了3臺,為了每一臺高可用一主一備一共6臺,fastdfs一個trackerServer一個storageServer搭建集群一共6臺,solr集群7臺服務(wù)器,nginx為了高可用一主一備一共2臺,mysql數(shù)據(jù)庫集群3臺!activemq消息中間件高可用2臺;
共計:58臺服務(wù)器!
你在項目開發(fā)中碰到過哪些重大且棘手的問題
場景一:需求不明確困境
在項目開發(fā)中,項目采用迭代開發(fā),開發(fā)需求不是很明確,對于項目開發(fā)初期來說非常困難,進度非常慢,有時開發(fā)的出的產(chǎn)品結(jié)果往往不能令老板滿意,或者是甲方滿意,項目還需要不停的迭代,修改。
比如說:
在開發(fā)商城項目的時候,客戶定位是一個綜合性的商務(wù)平臺,可以實現(xiàn)在線第三方商家對接,實現(xiàn)商品的銷售
但是并沒有明確的需求,因此開發(fā)全憑借電商的項目經(jīng)驗來實現(xiàn)里面的相關(guān)的業(yè)務(wù),后期慢慢迭代。
場景二: ES高亮不能顯示的問題
前臺使用angularJS加載搜索結(jié)果,但是發(fā)現(xiàn)高亮不能展示。
問題原因:
angularJS底層使用ajax,異步加載高亮信息返回給頁面后,頁面沒有刷新,就直接顯示返回的數(shù)據(jù)。此時會把所有的數(shù)據(jù)作為普通的文本數(shù)據(jù)進行加載。因此就沒有高亮的效果。
解決方案:
使用angularJS過濾器過濾文本數(shù)據(jù),此時angularJS過濾器把html文本數(shù)據(jù)解析為瀏覽器能識別的html標簽。高亮就能展示了。
場景三:Nginx靜態(tài)頁面服務(wù)跳轉(zhuǎn)到購物車跨域問題
在Nginx中部署了靜態(tài)頁面,添加購物車時必須從靜態(tài)頁面跳轉(zhuǎn)到購物車系統(tǒng),實現(xiàn)購物車添加操作。
由于在靜態(tài)頁面中使用angularJS實現(xiàn)的跳轉(zhuǎn),發(fā)現(xiàn)跳轉(zhuǎn)到購物車系統(tǒng)完全沒有問題,但是并不能跳轉(zhuǎn)回到購物車系統(tǒng)頁面。
問題分析:
從靜態(tài)詳情系統(tǒng)跳轉(zhuǎn)到購物車系統(tǒng),會存在跨域問題,因此不能進行回調(diào)函數(shù)的數(shù)據(jù)傳遞。所以在回調(diào)函數(shù)中的頁面跳轉(zhuǎn)就不能實現(xiàn)。
解決方案:
使用angularJS跨域調(diào)用及springmvc跨域配置,解決問題。
場景四:activeMQ存在運行時間長了以后,收不到消息的現(xiàn)象
時間長了就會出現(xiàn),卡死,新的數(shù)據(jù)不能從隊列接聽到。只能重啟程序。
解決方案:
1)不要頻繁的建立和關(guān)閉連接
JMS使用長連接方式,一個程序,只要和JMS服務(wù)器保持一個連接就可以了,不要頻繁的建立和關(guān)閉連接。頻繁的建立和關(guān)閉連接,對程序的性能影響還是很大的。這一點和jdbc還是不太一樣的。
2)Connection的start()和stop()方法代價很高
JMS的Connection的start()和stop()方法代價很高,不能經(jīng)常調(diào)用。我們試用的時候,寫了個jms的connection pool,每次將connection取出pool時調(diào)用start()方法,歸還時調(diào)用stop()方法,然而后來用jprofiler發(fā)現(xiàn),一般的cpu時間都耗在了這兩個方法上。
3)start()后才能收消息
Connection的start()方法調(diào)用后,才能收到j(luò)ms消息。如果不調(diào)用這個方法,能發(fā)出消息,但是一直收不到消息。不知道其它的jms服務(wù)器也是這樣。
4)顯式關(guān)閉Session
如果忘記了最后關(guān)閉Connection或Session對象,都會導(dǎo)致內(nèi)存泄漏。這個在我測試的時候也發(fā)現(xiàn)了。本來以為關(guān)閉了Connection,由這個Connection生成的Session也會被自動關(guān)閉,結(jié)果并非如此,Session并沒有關(guān)閉,導(dǎo)致內(nèi)存泄漏。所以一定要顯式的關(guān)閉Connection和Session。
5)對Session做對象池
對Session做對象池,而不是Connection。Session也是昂貴的對象,每次使用都新建和關(guān)閉,代價也非常高。而且后來我們發(fā)現(xiàn),原來Connection是線程安全的,而Session不是,所以后來改成了對Session做對象池,而只保留一個Connection。
6) 集群
ActiveMQ有強大而靈活的集群功能,但是使用起來還是會有很多陷阱
場景五:activeMQ存在發(fā)出消息太大,造成消息接受不成功
多個線程從activeMQ中取消息,隨著業(yè)務(wù)的擴大,該機器占用的網(wǎng)絡(luò)帶寬越來越高。
仔細分析發(fā)現(xiàn),mq入隊時并沒有異常高的網(wǎng)絡(luò)流量,僅僅在出隊時會產(chǎn)生很高的網(wǎng)絡(luò)流量。
最終發(fā)現(xiàn)是spring的jmsTemplate與activemq的prefetch機制配合導(dǎo)致的問題。
研究源碼發(fā)現(xiàn)jmsTemplate實現(xiàn)機制是:每次調(diào)用receive()時都會創(chuàng)建一個新的consumer對象,用完即銷毀。
正常情況下僅僅會浪費重復(fù)創(chuàng)建consumer的資源代價,并不至于產(chǎn)生正常情況十倍百倍的網(wǎng)絡(luò)流量。
但是activeMQ有一個提高性能的機制prefetch,此時就會有嚴重的問題。
prefetch機制:
每次consumer連接至MQ時,MQ預(yù)先存放許多message到消費者(前提是MQ中存在大量消息),預(yù)先存
放message的數(shù)量取決于prefetchSize(默認為1000)。此機制的目的很顯然,是想讓客戶端代碼用一個consumer反復(fù)進行
receive操作,這樣能夠大量提高出隊性能。
此機制與jmsTemplate配合時就會產(chǎn)生嚴重的問題,每次jmsTemplate.receive(),都會產(chǎn)生1000個消息的網(wǎng)絡(luò)流量, 但是因為jmsTemplae并不會重用consumer,導(dǎo)致后面999個消息都被廢棄。反復(fù)jmsTemplate.receive()時,表面上看 不出任何問題,其實網(wǎng)絡(luò)帶寬會造成大量的浪費。
解決方案:
1、若堅持使用jmsTemplate,需要設(shè)置prefetch值為1,相當于禁用了activeMQ的prefetch機制,此時感覺最健壯, 就算多線程,反復(fù)調(diào)用jmsTemplate.receive()也不會有任何問題。但是會有資源浪費,因為要反復(fù)創(chuàng)建consumer并頻繁與服務(wù)器進 行數(shù)據(jù)通信,但在性能要求不高的應(yīng)用中也不算什么問題。
2、不使用jmsTemplate,手工創(chuàng)建一個consumer,并單線程反復(fù)使用它來receive(),此時可以充分利用prefetch機制。配合多線程的方式每個線程擁有自己的一個consumer,此時能夠充分發(fā)揮MQ在大吞吐量時的速度優(yōu)勢。
切記避免多線程使用一個consumer造成的消息混亂。大吞吐量的應(yīng)用推薦使用方案2,能夠充分利用prefetch機制提高系MQ的吞吐性能。
商品的價格變化后,如何同步redis中數(shù)以百萬計的購物車數(shù)據(jù)。
購物車只存儲商品id,到購物車結(jié)算頁面將會從新查詢購物車數(shù)據(jù),因此就不會涉及購物車商品價格同步的問題。
系統(tǒng)中的錢是如何保證安全的。
在當前互聯(lián)網(wǎng)系統(tǒng)中錢的安全是頭等大事,如何保證錢的安全可以從以下2個方面來思考:
1)錢計算方面
在系統(tǒng)中必須是浮點數(shù)計算類型存儲錢的額度,否則計算機在計算時可能會損失精度。
2)事務(wù)處理方面
在當前環(huán)境下,高并發(fā)訪問,多線程,多核心處理下,很容易出現(xiàn)數(shù)據(jù)一致性問題,此時必須使用事務(wù)進行控制,訪問交易出現(xiàn)安全性的問題,那么在分布式系統(tǒng)中,存在分布式事務(wù)問題,可以有很多解決方案:
使用 jpa可以解決
使用 tcc 框架可以解決等等。
做交易或是金融系統(tǒng)安全性需要從哪些方面考慮?沒有用什么第三方可以框架
ip黑白名單,訪問日志明細記錄,防止重復(fù)提交,訪問頻率控制,分布式鎖,數(shù)據(jù)前后端校驗,自動對賬任務(wù)處理,互聯(lián)網(wǎng)金融項目一般情況下,不建議自動重試,最好結(jié)合對賬系統(tǒng),人工進行處理,寫好人工處理的接口就好。其他就是控制好數(shù)據(jù)的一致性了,這個最重要,其次還要保證接口的冪等性,不要重復(fù)處理訂單。這些是最基本的安全控制了。像這類網(wǎng)站用戶的輸入數(shù)據(jù)一般都不會太多,一般敏感詞過濾,廣告之類的可以忽略,如果有的話還要控制這些。安全框架選shiro 了,在系統(tǒng)中分配好角色就好了,控制好用戶的資源訪問。其他的用springmvc 就夠了
訂單中的事物是如何保證一致性的。
使用分布式事務(wù)來進行控制,保證數(shù)據(jù)最終結(jié)果的一致性。
當商品庫存數(shù)量不足時,如何保證不會超賣。
當庫存數(shù)量不足時,必須保證庫存不能被減為負數(shù),如果不加以控制,庫存被減為小于等于0的數(shù),那么這就叫做超賣。
那么如何防止超賣的現(xiàn)象發(fā)生呢?
場景一: 如果系統(tǒng)并發(fā)要求不是很高
那么此時庫存就可以存儲在數(shù)據(jù)庫中,數(shù)據(jù)庫中加鎖控制庫存的超賣現(xiàn)象。
場景二:系統(tǒng)的并發(fā)量很大
如果系統(tǒng)并發(fā)量很大,那么就不能再使用數(shù)據(jù)庫來進行減庫存操作了,因為數(shù)據(jù)庫加鎖操作本身是以損失數(shù)據(jù)庫的性能來進行控制數(shù)據(jù)庫數(shù)據(jù)的一致性的。
但是當并發(fā)量很大的時候,將會導(dǎo)致數(shù)據(jù)庫排隊,發(fā)生阻塞。因此必須使用一個高效的nosql數(shù)據(jù)庫服務(wù)器來進行減庫存。
此時可以使用redis服務(wù)器來存儲庫存,redis是一個內(nèi)存版的數(shù)據(jù)庫,查詢效率相當?shù)母?,可以使用watch來監(jiān)控減庫存的操作,一旦發(fā)現(xiàn)庫存被減為0,立馬停止售賣操作。
你們系統(tǒng)的商品模塊和訂單模塊的數(shù)據(jù)庫是怎么設(shè)計的
商品模塊設(shè)計:
商品模塊一共8張表,整個核心就是模板表。采用模板表為核心的設(shè)計方法,來構(gòu)造商品數(shù)據(jù)。
訂單設(shè)計:
訂單涉及的表有:
1) 收貨人地址
2) 訂單信息
3) 訂單明細
系統(tǒng)中商家活動策劃以及上報相關(guān)業(yè)務(wù)流程。
商城系統(tǒng)中有以下活動:
1) 秒殺活動
a) 后臺設(shè)置秒殺商品
b) 設(shè)置秒殺開啟時間,定時任務(wù),開啟秒殺
c) 秒殺減庫存(秒殺時間結(jié)束,庫存賣完,活動結(jié)束)
2) 促銷活動
3) 團購活動
4) 今日推薦
以上活動銷售記錄,統(tǒng)計,使用圖形化報表進行統(tǒng)計,可以查看銷售情況。
涉及到積分積累和兌換商品等業(yè)務(wù)是怎么設(shè)計的
積分累計有2大塊:
積分累計:
根據(jù)用戶購買的商品的價格不同,沒有購買一定價格的商品,獲取一定的積分。
積分商城:
積分商城是用戶可以使用積分商品換取商品的區(qū)域。
介紹下電商項目,你覺得那些是亮點?
這個項目是為xxx開發(fā)的b2b2c類型綜合購物平臺,主要以銷售xxx,電子產(chǎn)品為主要的電子商城網(wǎng)站。
項目的亮點是:
1)項目采用面向服務(wù)分布式架構(gòu)(使用dubbo,zookeeper)
a) 解耦
b) 提高項目并發(fā)能力
c) 分擔服務(wù)器壓力
2)項目中使用activeMQ對項目進一步解耦
a) 提高項目并發(fā)能力
b) 提高任務(wù)處理速度
3) 使用微信支付,支付寶支付(自己總結(jié))
4) 使用阿里大魚發(fā)生短信
5) 使用第三方分布式文件系統(tǒng)存儲海量文件
6) Nginx部署靜態(tài)頁面實現(xiàn)動靜分離
購物車功能做了嗎,實現(xiàn)原理說一下?
加入購物車
加入購物車插入到庫中一條購物記錄,同時插入到緩存中,緩存的key是記錄的id
未登錄狀態(tài)
用戶未登錄時點擊加入購物車,將productId ,skuId,buyNum
轉(zhuǎn)換成json存到cookie中(同一件商品不同的skuId視為兩個商品,相同的skuId和productId視為相同商品數(shù)量累加),用戶登錄成功的時候接收用戶的消息將cookie中的商品信息保存到數(shù)據(jù)庫中,然后清空cookie數(shù)據(jù)(京東)不然會出現(xiàn)登錄成功后刪除購物車商品然后退出,購物車中顯示問題
登錄狀態(tài)
點擊加入購物車將long userId,long productId,long skuId,int count 存到庫中,相同的productId和skuId 數(shù)量累加,不同的skuId新增一條
addToCart(long userId,long skuId,int count); //加入sku到購物車商品
修改商品數(shù)量
未登錄狀態(tài)
用戶未登錄時,點擊加減數(shù)量,根據(jù)productId和skuId從cooike中將商品數(shù)量進行加減,注意校驗cooike中的數(shù)量不能小于0,不能大于庫存數(shù)量
登錄狀態(tài)
用戶登錄狀態(tài)時,點擊加減數(shù)量productId和skuId,userId將用戶購物車中某個sku的數(shù)量增加或減去differ值,注意校驗庫存數(shù)量
updateAmount(long userId,skuId,int differ,List selectedSkuIds);
//將用戶購物車中某個sku的數(shù)量增加或減去differ值。此方法更新商品后,會根據(jù)selectedSkuIds重新計算一遍購物車價格,返回滿足條件的優(yōu)惠券
刪除購物車記錄
未登錄狀態(tài)
用戶未登錄時,根據(jù)productId和skuId刪除cookie中的記錄
deleteCart(long userId,long skuId, List selectedSkuIds);
//將某個sku從用戶購物車移除。此接品,在清除后臺會重復(fù)計算selectedSkuIds價格,并會返回選中的sku列表與未選中的sku列表集合。及相應(yīng)優(yōu)惠券。
登錄狀態(tài)
登錄狀態(tài)下,直接根據(jù)productId和skuId以及userId刪除庫中數(shù)據(jù)
4購物車列表展示
未登錄狀態(tài)
從cookie中取出productId以及skuId列表展示商品信息
登錄狀態(tài)
登錄狀態(tài)下根據(jù)用戶id查詢庫中的記錄數(shù)
getCart(long userId,list selectedSkuIds); //查詢用戶購物車。此接口會重新計算selectedSkuIds,并返回選中與未選中sku列表集合,返回相應(yīng)的滿足條件的優(yōu)惠券信息。
5.訂單提交成功后更新購物車數(shù)量以及修改購物車狀態(tài)
訂單提交成功后接收訂單成功消息,更新購物車狀態(tài)和數(shù)量刪除緩存記錄
6.商品下架后,更新庫存狀態(tài),顯示失效
商品下架后接收消息修改購物車里的商品狀態(tài)為失效
你們的項目上線了嗎?這么大的項目怎么沒上線?
項目上線問題回答:
1) 項目沒有上線
如果你沒有做過電商的項目,可以說項目沒有上線之前,你離職了,這個一個創(chuàng)業(yè)型的公司,或者此項目是給甲方做的項目,你沒有參與上線。以此來回避這個問題.
2) 項目上線
項目已經(jīng)上線了
上線環(huán)境:
a) Centos7
b) Mysql
c) Jdk8
d) Tomcat8
關(guān)于上線,那么面試官一定會問您,上線遇到什么問題沒有?
因此必須把項目中遇到的問題準備2個,以下可以作為參考
問題一:(用戶非正常流程導(dǎo)致的錯誤)
用戶注冊一半就退出來,導(dǎo)致再次注冊不成功或者用證件號登陸觸發(fā)空指針異常。
解決辦法:一旦輸入證件號時,檢查數(shù)據(jù)庫的表是否有相應(yīng)的證件號記錄,有則把相關(guān)記錄全部刪掉,從而讓他成功注冊??罩羔槷惓5慕鉀Q辦法,做非空驗證的判斷。
問題二:(并發(fā)插入,流水號不一致)
出現(xiàn)大量的主鍵唯一約束錯誤,后來想到是產(chǎn)生的預(yù)報名號不同步,導(dǎo)致有可能大并發(fā)量時產(chǎn)生多個相同的流水號,插入就會出現(xiàn)主鍵唯一約束錯誤。
解決辦法:在數(shù)據(jù)庫里寫一個insert的觸發(fā)器。自動替換掉要插入的主鍵為 max(key)+1.
問題三:(并發(fā)刪除,索引失效)
出現(xiàn)某些表的索引失效,后來發(fā)現(xiàn)是插入相同主鍵多次之后導(dǎo)致表失效。
解決辦法:設(shè)定oracle任務(wù),讓數(shù)據(jù)庫每隔12個小時自動重建所有索引。
問題四:(js代碼的不細致)
發(fā)現(xiàn)報考志愿顯示的專業(yè)比原來的少一個。
解決辦法:發(fā)現(xiàn)時jsp頁面的js少循環(huán)一個=號導(dǎo)致的。。。。
問題五:(頁面和后臺代碼太不通用)
用戶需求一旦更改或者程序邏輯有錯誤后,導(dǎo)致要修改很多頁面和后臺代碼,十分不通用,要從業(yè)務(wù)邏輯上設(shè)計的通用點。改一個,就能等同于改全部。用一些設(shè)計模式去解決。
訂單怎么實現(xiàn)的,你們這個功能怎么這么簡單?
訂單實現(xiàn):
從購物車系統(tǒng)跳轉(zhuǎn)到訂單頁面,選擇默認收貨地址
選擇支付方式
購物清單展示
提交訂單
訂單業(yè)務(wù)處理:
一個商家一個訂單,不同的倉庫發(fā)送的貨品也是屬于不同的訂單。因此會產(chǎn)出不同的訂單號。
訂單處理:根據(jù)支付的狀態(tài)進行不同的處理
1) 在線支付
a) 支付未成功—從新發(fā)起支付
b) 支付超時---訂單關(guān)閉
2) 貨到付款
你們這個項目有秒殺嗎,怎么實現(xiàn)的?
所謂“秒殺”,就是網(wǎng)絡(luò)賣家發(fā)布一些超低價格的商品,
所有買家在同一時間網(wǎng)上搶購的一種銷售方式。通俗一點講就是網(wǎng)絡(luò)商家為促銷等目的組織的網(wǎng)上限時搶購活動。由于商品價格低廉,往往一上架就被搶購一空,有時只用一秒鐘。
秒殺商品通常有兩種限制:庫存限制、時間限制。
需求:
(1)商家提交秒殺商品申請,錄入秒殺商品數(shù)據(jù),主要包括:商品標題、原價、秒殺價、商品圖片、介紹等信息
(2)運營商審核秒殺申請
(3)秒殺頻道首頁列出秒殺商品(進行中的)點擊秒殺商品圖片跳轉(zhuǎn)到秒殺商品詳細頁。
(4)商品詳細頁顯示秒殺商品信息,點擊立即搶購實現(xiàn)秒殺下單,下單時扣減庫存。當庫存為0或不在活動期范圍內(nèi)時無法秒殺。
(5)秒殺下單成功,直接跳轉(zhuǎn)到支付頁面(微信掃碼),支付成功,跳轉(zhuǎn)到成功頁,填寫收貨地址、電話、收件人等信息,完成訂單。
(6)當用戶秒殺下單5分鐘內(nèi)未支付,取消預(yù)訂單,調(diào)用微信支付的關(guān)閉訂單接口,恢復(fù)庫存。
數(shù)據(jù)庫表分析
Tb_seckill_goods 秒殺商品表
Tb_seckill_order 秒殺訂單表
秒殺實現(xiàn)思路
秒殺技術(shù)實現(xiàn)核心思想是運用緩存減少數(shù)據(jù)庫瞬間的訪問壓力!讀取商品詳細信息時運用緩存,當用戶點擊搶購時減少redis中的庫存數(shù)量,當庫存數(shù)為0時或活動期結(jié)束時,同步到數(shù)據(jù)庫。 產(chǎn)生的秒殺預(yù)訂單也不會立刻寫到數(shù)據(jù)庫中,而是先寫到緩存,當用戶付款成功后再寫入數(shù)據(jù)庫。
你們這個項目用的什么數(shù)據(jù)庫,數(shù)據(jù)庫有多少張表?
項目使用mysql數(shù)據(jù)庫,總共有103張表,其中商品表共計有8張。
項目部署做過嗎,能不能部署?
做過,可以部署。
項目服務(wù)器:集群部署
數(shù)據(jù)庫服務(wù)器:集群部署
Nginx集群:負載均衡
單點登錄怎么做的,用別人知道原理嗎?
在分布式項目中實現(xiàn)session共享,完成分布式系統(tǒng)單點登錄
3) Cookie中共享ticket
4) Redis存儲session
分布式系統(tǒng)共享用戶身份信息session,必須先獲取ticket票據(jù),然后再根據(jù)票據(jù)信息獲取redis中用戶身份信息。
實現(xiàn)以上2點即可實現(xiàn)session共享。
目前項目中使用的springsecurity + cas 來實現(xiàn)的單點登錄,cas自動產(chǎn)生ticket票據(jù)信息,每次獲取用戶信息,cas將會攜帶ticket信息獲取用戶身份信息。
支付做了嗎,支付寶還是微信,實現(xiàn)說下?
微信支付:
1) 調(diào)用微信支付下單接口
2) 返回支付地址,生成二維碼
3) 掃描二維碼即可完成支付
問題: 微信支付二維碼是我們自己生成的,因此必須時刻監(jiān)控微信支付二維碼的狀態(tài),確保支付成功。
支付寶支付可以參考www.alipay.com
緩存及優(yōu)化方面的面試問題
怎么提高redis緩存利用率?
1、從業(yè)務(wù)場景分析,預(yù)計會高頻率用到的數(shù)據(jù)預(yù)先存放到redis中,
2、可以定時掃描命中率低的數(shù)據(jù),可以直接從redis中清除。
怎么實現(xiàn)數(shù)據(jù)量大、 并發(fā)量高的搜索
創(chuàng)建solr索引庫,數(shù)據(jù)量特別大時采用solr分布式集群
MySQL索引使用限制
不要在列上進行運算。
select * from users where
YEAR(adddate)<2007; 將在每個行上進行運算,這將導(dǎo)致索引失效而進行全表掃描,因此我們可以改成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個字符內(nèi),多數(shù)值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。
索引不會包含NULL列
復(fù)合索引中如果有一列含有NULL值那么這個組合索引都將失效,一般需要給默認值0或者 ' '字符串
最左匹配
不按索引最左列開始查詢(多列索引) 例如index(‘c1’, ‘c2’, ‘c3’) ,where ‘c2’ = ‘a(chǎn)aa’
不使用索引,where ‘c2’ = ‘a(chǎn)aa’ and ‘c3’ = ‘sss’ 不能使用索引。where ‘c1’ = ‘a(chǎn)aa’ and
‘c2’ = ‘bbb’ 可以使用索引
多列范圍查詢
查詢中某個列有范圍查詢,則其右邊的所有列都無法使用查詢(多列查詢)。where c1= ‘xxx’ and c2 like = ‘a(chǎn)a%’ and c3=’sss’ 該查詢只會使用索引中的前兩列,c3將不能使用到索引,因為like是范圍查詢。
檢索排序
一個查詢語句中,既有檢索又有排序并且是不同的字段,且這兩個列上都有單列索引(獨立索引),那么只有其中一個列用到索引,因為查詢優(yōu)化器在做檢索和排序中不能同時使用兩個不同的索引
索引散列度
通過索引掃描的記錄超過了表總行數(shù)的30%(估計值),則查詢優(yōu)化器認為全表掃描的效率更高,所以會變成全表掃描查詢
隱式轉(zhuǎn)換
隱式轉(zhuǎn)換導(dǎo)致的索引失效。比如,表的字段tu_mdn定義為varchar(20),但在查詢時把該字段作為number類型當做where條件,這樣會導(dǎo)致索引失效.
錯誤的例子:select * from test where tu_mdn=13333333333; 正確的例子:select * from
test where tu_mdn='13333333333’;
怎么分詞
使用第三方的分詞器IKAnalyzer,會按照中國人用此習慣自動分詞。
seo怎么優(yōu)化
使用restful,或靜態(tài)頁這樣能更好的被搜索引擎收錄。
怎么加快訪問速度
硬件上加大網(wǎng)絡(luò)帶寬、和服務(wù)器內(nèi)存
代碼的處理:靜態(tài)頁面、緩存、優(yōu)化sql、創(chuàng)建索引等方案
講到redis緩存的時候說不清楚
redis中項目中的應(yīng)用。1.主要應(yīng)用在門戶網(wǎng)站首頁廣告信息的緩存。因為門戶網(wǎng)站訪問量較大,將廣告緩存到redis中,可以降低數(shù)據(jù)庫訪問壓力,提高查詢性能。2.應(yīng)用在用戶注冊驗證碼緩存。利用redis設(shè)置過期時間,當超過指定時間后,redis清理驗證碼,使過期的驗證碼無效。3.用在購物車模塊,用戶登陸系統(tǒng)后,添加的購物車數(shù)據(jù)需要保存到redis緩存中。
技術(shù)角度分析:
內(nèi)存如果滿了,采用LRU算法進行淘汰。
Redis如何實現(xiàn)負載的?采用Hash槽來運算存儲值,使用CRC16算法取模運算,來保證負載問題。
Redis緩存穿透問題?將數(shù)據(jù)查詢出來如果沒有強制設(shè)置空值,并且設(shè)置過期時間,減少頻繁查詢數(shù)據(jù)庫。
能講下redis的具體使用場景嗎?使用redis存儲長期不改變的數(shù)據(jù)完全可以使用也看靜態(tài)化,那么你們當時是為什么會使用redis?
redis在項目中應(yīng)用:1.主要應(yīng)用在門戶網(wǎng)站首頁廣告信息的緩存。因為門戶網(wǎng)站訪問量較大,將廣告緩存到redis中,可以降低數(shù)據(jù)庫訪問壓力,提高查詢性能。2.應(yīng)用在用戶注冊驗證碼緩存。利用redis設(shè)置過期時間,當超過指定時間后,redis清理驗證碼,使過期的驗證碼無效。3.用在購物車模塊,用戶登陸系統(tǒng)后,添加的購物車數(shù)據(jù)需要保存到redis緩存中。
使用redis主要是減少系統(tǒng)數(shù)據(jù)庫訪問壓力。從緩存中查詢數(shù)據(jù),也提高了查詢性能,挺高用戶體驗度。
redis中對一個key進行自增或者自減操作,它是原子性的嗎?
是原子性的。對于Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要么執(zhí)行,要么不執(zhí)行。Redis的操作之所以是原子性的,是因為Redis是單線程的。對Redis來說,執(zhí)行g(shù)et、set以及eval等API,都是一個一個的任務(wù),這些任務(wù)都會由Redis的線程去負責執(zhí)行,任務(wù)要么執(zhí)行成功,要么執(zhí)行失敗,這就是Redis的命令是原子性的原因。Redis本身提供的所有API都是原子操作,Redis中的事務(wù)其實是要保證批量操作的原子性。
你們項目中使用到的數(shù)據(jù)庫是什么?你有涉及到關(guān)于數(shù)據(jù)庫到建庫建表操作嗎?數(shù)據(jù)庫創(chuàng)建表的時候會有哪些考慮呢?
項目中使用的是MySQL數(shù)據(jù)庫,
數(shù)據(jù)庫創(chuàng)建表時要考慮
a、大數(shù)據(jù)字段最好剝離出單獨的表,以便影響性能
b、使用varchar,代替char,這是因為varchar會動態(tài)分配長度,char指定為20,即時你存儲字符“1”,它依然是20的長度
c、給表建立主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有一定的影響
d、避免表字段運行為null,如果不知道添加什么值,建議設(shè)置默認值,特別int類型,比如默認值為0,在索引查詢上,效率立顯。
e、建立索引,聚集索引則意味著數(shù)據(jù)的物理存儲順序,最好在唯一的,非空的字段上建立,其它索引也不是越多越好,索引在查詢上優(yōu)勢顯著,在頻繁更新數(shù)據(jù)的字段上建立聚集索引,后果很嚴重,插入更新相當忙。
f、組合索引和單索引的建立,要考慮查詢實際和具體模式
mysql中哪些情況下可以使用索引,哪些情況不能使用索引?mysql索引失效的情形有哪些?
使用索引:
a、 為了快速查找匹配WHERE條件中涉及到列。
b、 如果表有一個multiple-column索引,任何一個索引的最左前綴可以通過使用優(yōu)化器來查找行
c、 當運行joins時,為了從其他表檢索行。MySql可以更有效的使用索引在多列上如果他們聲明的類型和大小是一樣的話。在這個環(huán)境下,VARCHAR和CHAR是一樣的如果他們聲明的大小是一樣的
d、 為了找到 MIN() or MAX()的值對于一個指定索引的列key_col.
總之,就是經(jīng)常用到的列就最好創(chuàng)建索引。
不能使用引用:
a) 數(shù)據(jù)唯一性差(一個字段的取值只有幾種時)的字段不要使用索引
比如性別,只有兩種可能數(shù)據(jù)。意味著索引的二叉樹級別少,多是平級。這樣的二叉樹查找無異于全表掃描
b) 頻繁更新的字段不要使用索引
比如logincount登錄次數(shù),頻繁變化導(dǎo)致索引也頻繁變化,增大數(shù)據(jù)庫工作量,降低效率
c) 字段不在where語句出現(xiàn)時不要添加索引,如果where后含IS NULL /IS NOT NULL/ like ‘%輸入符%’等條件,不建議使用索引只有在where語句出現(xiàn),mysql才會去使用索引
d) where 子句里對索引列使用不等于(<>),使用索引效果一般
索引失效:
a.如果條件中有or,即使其中有條件帶索引也不會使用(這也是為什么盡量少用or的原因)
注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
b.對于多列索引,不是使用的第一部分,則不會使用索引
c.like查詢是以%開頭
d.如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,否則不使用索引
e.如果mysql估計使用全表掃描要比使用索引快,則不使用索引
8,java中的多線程在你們的這個項目當中有哪些體現(xiàn)?
a,后臺任務(wù):如定時向大量(100W以上)的用戶發(fā)送郵件;定期更新配置文件、任務(wù)調(diào)度(如quartz),一些監(jiān)控用于定期信息采集
b, 自動作業(yè)處理:比如定期備份日志、定期備份數(shù)據(jù)庫
c, 異步處理:如發(fā)微博、記錄日志
Redis分布式鎖理解
實現(xiàn)思想
獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。
獲取鎖的時候還設(shè)置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執(zhí)行delete進行鎖釋放。
Redis怎么設(shè)置過期的?項目過程中,使用了哪一種持久化方式
設(shè)置過期:
this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);
持久化方式:Redis默認的RDB方式
項目添加Redis緩存后,持久化具體怎么實現(xiàn)的。
RDB:保存存儲文件到磁盤;同步時間為15分鐘,5分鐘,1分鐘一次,可能存在數(shù)據(jù)丟失問題。
AOF:保存命令文件到磁盤;安全性高,修改后立即同步或每秒同步一次。
上述兩種方式在我們的項目中都有使用到,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數(shù)據(jù),無數(shù)據(jù)后從數(shù)據(jù)庫中查詢后保存到redis中
采用默認的RDB方式,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數(shù)據(jù),無數(shù)據(jù)就從數(shù)據(jù)庫中查詢后再保存到redis中
項目中有用到過redis,訪問redis是通過什么訪問的?redis能夠存儲的數(shù)據(jù)類型有哪幾種?
Redis通過SpringDataRedis訪問的.
Redis支持五種數(shù)據(jù)類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
怎樣進行程序性能調(diào)優(yōu)
系統(tǒng)性能就是兩個事:
Throughput ,吞吐量。也就是每秒鐘可以處理的請求數(shù),任務(wù)數(shù)。
Latency, 系統(tǒng)延遲。也就是系統(tǒng)在處理一個請求或一個任務(wù)時的延遲。
那么Latency越好,能支持的Throughput就會越高。因為Latency短說明處理速度快,于是就可以處理更多的請求。
提高吞吐量:
分布式集群,模塊解藕,設(shè)計模式
系統(tǒng)延遲:
異步通信
數(shù)據(jù)庫設(shè)計的面試問題
你有了解mysql的隔離級別嗎?mysql默認的隔離級別是什么?
數(shù)據(jù)庫事務(wù)的隔離級別有四種,隔離級別高的數(shù)據(jù)庫的可靠性高,但并發(fā)量低,而隔離級別低的數(shù)據(jù)庫可靠性低,但并發(fā)量高,系統(tǒng)開銷小。
READ UNCIMMITTED(未提交讀)
READ COMMITTED(提交讀)
REPEATABLE READ(可重復(fù)讀)
SERIALIZABLE(可串行化)
mysql默認的事務(wù)處理級別是'REPEATABLE-READ',也就是可重復(fù)讀。
sql語句中關(guān)于查詢語句的優(yōu)化你們是怎么做的?
1、應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
2、對查詢進行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
3、應(yīng)盡量避免在 where 子句中對字段進行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描
4、盡量避免在 where 子句中使用 or 來連接條件,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描
5、in 和 not in 也要慎用,否則會導(dǎo)致全表掃描
6、應(yīng)盡量避免在 where 子句中對字段進行表達式操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描。
7、應(yīng)盡量避免在where子句中對字段進行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描
8、不要在 where 子句中的“=”左邊進行函數(shù)、算術(shù)運算或其他表達式運算,否則系統(tǒng)將可能無法正確使用索引。
9、在使用索引字段作為條件時,如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,否則該索引將不會被使 用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
10、索引并不是越多越好,索引固然可以提高相應(yīng)的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
11、盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節(jié)省存儲空間,其次對于查詢來說,在一個相對較小的字段內(nèi)搜索效率顯然要高些。
12、任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
mysql索引失效的場景有哪些?like做模糊查詢的時候會失效嗎?
1.WHERE字句的查詢條件里有不等于號(WHERE column!=…),MYSQL將無法使用索引
2.類似地,如果WHERE字句的查詢條件里使用了函數(shù)(如:WHERE DAY(column)=…),MYSQL將無法使用索引
3.在JOIN操作中(需要從多個數(shù)據(jù)表提取數(shù)據(jù)時),MYSQL只有在主鍵和外鍵的數(shù)據(jù)類型相同時才能使用索引,否則即使建立了索引也不會使用
4.如果WHERE子句的查詢條件里使用了比較操作符LIKE和REGEXP,MYSQL只有在搜索模板的第一個字符不是通配符的情況下才能使用索引。比如說,如果查詢條件是LIKE 'abc%',MYSQL將使用索引;如果條件是LIKE '%abc',MYSQL將不使用索引。
5.在ORDER BY操作中,MYSQL只有在排序條件不是一個查詢條件表達式的情況下才使用索引。盡管如此,在涉及多個數(shù)據(jù)表的查詢里,即使有索引可用,那些索引在加快ORDER BY操作方面也沒什么作用。
6.如果某個數(shù)據(jù)列里包含著許多重復(fù)的值,就算為它建立了索引也不會有很好的效果。比如說,如果某個數(shù)據(jù)列里包含了凈是些諸如“0/1”或“Y/N”等值,就沒有必要為它創(chuàng)建一個索引。
7.索引有用的情況下就太多了?;局灰⒘怂饕?,除了上面提到的索引不會使用的情況下之外,其他情況只要是使用在WHERE條件里,ORDER BY 字段,聯(lián)表字段,一般都是有效的。 建立索引要的就是有效果。 不然還用它干嗎? 如果不能確定在某個字段上建立的索引是否有效果,只要實際進行測試下比較下執(zhí)行時間就知道。
8.如果條件中有or(并且其中有or的條件是不帶索引的),即使其中有條件帶索引也不會使用(這也是為什么盡量少用or的原因)。注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
9.如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,否則不使用索引
10.如果mysql估計使用全表掃描要比使用索引快,則不使用索引
問題二:Like模糊查詢,建立索引會失效
項目中關(guān)于表結(jié)構(gòu)拆分,你們是業(yè)務(wù)層面的拆分還是表結(jié)構(gòu)層面的拆分?
表結(jié)構(gòu)層面的拆分。通過mycat數(shù)據(jù)庫中間件完成數(shù)據(jù)庫分表操作。
業(yè)務(wù)層面也有拆分,比如商品模塊拆分成8張表來實現(xiàn)存儲
有了解過大數(shù)據(jù)層面的分庫分表嗎?以及mysql的執(zhí)行計劃嗎?
分庫:通過Mycat結(jié)點來管理不同服務(wù)器上的數(shù)據(jù)庫,每個表最多存500萬條記錄
分表:重直切割,水平切割
MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個"EXPLAIN"即可。mysql中的explain語法可以幫助我們改寫查詢,優(yōu)化表的結(jié)構(gòu)和索引的設(shè)置,從而最大地提高查詢效率。
有了解過數(shù)據(jù)庫中的表級鎖和行級鎖嗎?樂觀鎖和悲觀鎖你有哪些了解?
MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖( row-level locking),也支持表級鎖,但默認情況下是采用行級鎖。
MySQL主要的兩種鎖的特性可大致歸納如下:
表級鎖: 開銷小,加鎖快;不會出現(xiàn)死鎖(因為MyISAM會一次性獲得SQL所需的全部鎖);鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
行級鎖: 開銷大,加鎖慢;會出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
樂觀鎖:通過version版本字段來實現(xiàn)
悲觀鎖:通過for update來實現(xiàn)
Mysql優(yōu)化有沒有工具
三個MySQL性能測試工具:The MySQL Benchmark Suite、MySQL super-smack、MyBench。除了第一個為MySQL性能測試工具,其他兩個都為壓力測試工具。
你們項目中使用到的數(shù)據(jù)庫是什么?你有涉及到關(guān)于數(shù)據(jù)庫到建庫建表操作嗎?數(shù)據(jù)庫創(chuàng)建表的時候會有哪些考慮呢?
項目中使用的是MySQL數(shù)據(jù)庫,
數(shù)據(jù)庫創(chuàng)建表時要考慮
a、大數(shù)據(jù)字段最好剝離出單獨的表,以便影響性能
b、使用varchar,代替char,這是因為varchar會動態(tài)分配長度,char指定為20,即時你存儲字符“1”,它依然是20的長度
c、給表建立主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有一定的影響
d、避免表字段運行為null,如果不知道添加什么值,建議設(shè)置默認值,特別int類型,比如默認值為0,在索引查詢上,效率立顯。
e、建立索引,聚集索引則意味著數(shù)據(jù)的物理存儲順序,最好在唯一的,非空的字段上建立,其它索引也不是越多越好,索引在查詢上優(yōu)勢顯著,在頻繁更新數(shù)據(jù)的字段上建立聚集索引,后果很嚴重,插入更新相當忙。
f、組合索引和單索引的建立,要考慮查詢實際和具體模式
怎樣進行數(shù)據(jù)庫優(yōu)化?
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) 是當多個用戶同時使用相同的數(shù)據(jù)源時,它可以利用鎖定數(shù)據(jù)庫的方法來為用戶提供一種安全的訪問方式,這樣可以保證用戶的操作不被其它的用戶所干擾。
e,鎖定表
f,使用外鍵
鎖定表的方法可以維護數(shù)據(jù)的完整性,但是它卻不能保證數(shù)據(jù)的關(guān)聯(lián)性。這個時候我們就可以使用外鍵。
g,使用索引
h,優(yōu)化的查詢語句
怎樣進行數(shù)據(jù)庫性能調(diào)優(yōu)
一應(yīng)用程序優(yōu)化
(1)把數(shù)據(jù)庫當作奢侈的資源看待,在確保功能的同時,盡可能少地動用數(shù)據(jù)庫資源。
(2)不要直接執(zhí)行完整的SQL 語法,盡量通過存儲過程實現(xiàn)數(shù)據(jù)庫操作。
(3)客戶與服務(wù)器連接時,建立連接池,讓連接盡量得以重用,以避免時間與資源的損耗。
(4)非到不得已,不要使用游標結(jié)構(gòu),確實使用時,注意各種游標的特性。
二基本表設(shè)計優(yōu)化
(1)表設(shè)計遵循第三范式。在基于表驅(qū)動的信息管理系統(tǒng)中,基本表的設(shè)計規(guī)范是第三范式。
(2)分割表。分割表可分為水平分割表和垂直分割表兩種:水平分割是按照行將一個表分割為多個表。
(3)引入中間表。
三 數(shù)據(jù)庫索引優(yōu)化
索引是建立在表上的一種數(shù)據(jù)組織,它能提高訪問表中一條或多條記錄的特定查詢效率。
聚集索引
一種索引,該索引中鍵值的邏輯順序決定了表中相應(yīng)行的物理順序。
聚集索引確定表中數(shù)據(jù)的物理順序。
非聚集索引
一種索引,該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同.
分布式開發(fā)面試問題
分布式架構(gòu)session共享問題,如何在集群里邊實現(xiàn)共享。
用了CAS,所有應(yīng)用項目中如果需要登錄時在web.xml中配置過濾器做請求轉(zhuǎn)發(fā)到cas端工作原理是在cas登錄后會給瀏覽器發(fā)送一個票據(jù)(ticket),瀏覽器cookie中會緩存這個ticket,在登錄其他項目時會拿著瀏覽器的ticket轉(zhuǎn)發(fā)到cas,到cas后根據(jù)票據(jù)判斷是否登錄
項目中如何配置集群?
配置了redis集群,使用redis3.0版本官方推薦的配置方式
solr集群使用了solrCloud,使用zookeeper關(guān)聯(lián)solrCloud的配置文件
zookeeper也配置了集群
應(yīng)用層使用Nginx負載均衡
對分布式,dubbo,zookeeper說的不太清楚
分布式是從項目業(yè)務(wù)角度考慮劃分項目整個架構(gòu)??梢詫㈨椖炕诠δ苣K劃分再分別部署。Dubbo是實現(xiàn)分布式項目部署框架。在zookeeper是dubbo分布式框架的注冊中心,管理服務(wù)的注冊和調(diào)用。
從前端到后臺的實現(xiàn)的過程描述的也不清楚
項目前端采用angularjs框架在controller控制器中完成數(shù)據(jù)組裝和數(shù)據(jù)展示,在服務(wù)層(service)代碼完成中后臺請求操作。后端基于前端的接口調(diào)用,完成數(shù)據(jù)的增刪改查操作。前后端數(shù)據(jù)交互通過json格式字符串完成。
Dubbo為什么選擇Zookeeper,而不選擇Redis
引入了ZooKeeper作為存儲媒介,也就把ZooKeeper的特性引進來。
首先是負載均衡,單注冊中心的承載能力是有限的,在流量達到一定程度的時候就需要分流,負載均衡就是為了分流而存在的,一個ZooKeeper群配合相應(yīng)的Web應(yīng)用就可以很容易達到負載均衡;
資源同步,單單有負載均衡還不夠,節(jié)點之間的數(shù)據(jù)和資源需要同步,ZooKeeper集群就天然具備有這樣的功能;
命名服務(wù),將樹狀結(jié)構(gòu)用于維護全局的服務(wù)地址列表,服務(wù)提供者在啟動 的時候,向ZK上的指定節(jié)點/dubbo/${serviceName}/providers目錄下寫入自己的URL地址,這個操作就完成了服務(wù)的發(fā)布。 其他特性還有Mast選舉,分布式鎖等。
項目中Zookeeper服務(wù)器掛了,服務(wù)調(diào)用可以進行嗎
可以的,消費者在啟動時,消費者會從zk拉取注冊的生產(chǎn)者的地址接口等數(shù)據(jù),緩存在本地。
每次調(diào)用時,按照本地存儲的地址進行調(diào)用
如何保證dubbo高可用?
1. zookeeper宕機與dubbo直連
在實際生產(chǎn)中,假如zookeeper注冊中心宕掉,一段時間內(nèi)服務(wù)消費方還是能夠調(diào)用提供方的服務(wù)的,實際上它使用的本地緩存進行通訊,這只是dubbo健壯性的一種。
dubbo的健壯性表現(xiàn):
監(jiān)控中心宕掉不影響使用,只是丟失部分采樣數(shù)據(jù)
數(shù)據(jù)庫宕掉后,注冊中心仍能通過緩存提供服務(wù)列表查詢,但不能注冊新服務(wù)
注冊中心對等集群,任意一臺宕掉后,將自動切換到另一臺
注冊中心全部宕掉后,服務(wù)提供者和服務(wù)消費者仍能通過本地緩存通訊
服務(wù)提供者無狀態(tài),任意一臺宕掉后,不影響使用
服務(wù)提供者全部宕掉后,服務(wù)消費者應(yīng)用將無法使用,并無限次重連等待服務(wù)提供者恢復(fù)
注冊中心的作用在于保存服務(wù)提供者的位置信息,我們可以完全可以繞過注冊中心——采用dubbo直連,即在服務(wù)消費方配置服務(wù)提供方的位置信息。
點對點直連方式,將以服務(wù)接口為單位,忽略注冊中心的提供者列表,A 接口配置點對點,不影響 B 接口從注冊中心獲取列表。
xml配置方式
<dubbo:reference id="userService" interface="com.zang.gmall.service.UserService" url="dubbo://localhost:20880" />
注解上直接添加
@Reference(url = "127.0.0.1:20880")
UserService userService;
2. 集群下dubbo負載均衡配置
在集群負載均衡時,Dubbo提供了4種均衡策略,如:Random LoadBalance(隨機均衡算法)、RoundRobin LoadBalance(權(quán)重輪循均衡算法)、LeastAction LoadBalance(最少活躍調(diào)用數(shù)均衡算法)、ConsistentHash LoadBalance(一致性Hash均衡算法)。缺省時為Random隨機調(diào)用。
@Reference(loadbalance = "roundrobin")
UserService userService;
服務(wù)方方法級別配置(基于xml配置的權(quán)重輪詢均衡算法)
<dubbo:service interface="com.zang.gmall.service.UserService"
<dubbo:method name="getUserAddressList" loadbalance="roundrobin"></dubbo:method>
</dubbo:service>
3. 權(quán)重設(shè)置
當不設(shè)置負載均衡策略,即采用默認的Random LoadBalance(隨機均衡算法)時,默認每個服務(wù)的權(quán)重相同,我們可以通過設(shè)置權(quán)重來分配訪問的隨機性。
權(quán)重默認為100,可以在暴露服務(wù)的同時設(shè)置
4. 服務(wù)降級
當服務(wù)器壓力劇增的情況下,根據(jù)實際業(yè)務(wù)情況及流量,對一些服務(wù)和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務(wù)器資源以保證核心交易正常運作或高效運作。
可以通過服務(wù)降級功能臨時屏蔽某個出錯的非關(guān)鍵服務(wù),并定義降級后的返回策略(不調(diào)用服務(wù)即返回為空 or 調(diào)用失敗返回為空)。
向注冊中心寫入動態(tài)配置覆蓋規(guī)則:
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
其中:
mock=force:return+null 表示消費方對該服務(wù)的方法調(diào)用都直接返回 null 值,不發(fā)起遠程調(diào)用。用來屏蔽不重要服務(wù)不可用時對調(diào)用方的影響。
還可以改為 mock=fail:return+null 表示消費方對該服務(wù)的方法調(diào)用在失敗后,再返回 null 值,不拋異常。用來容忍不重要服務(wù)不穩(wěn)定時對調(diào)用方的影響。
通過操作管理控制臺也可以方便的進行服務(wù)降級
5. 集群容錯
在集群調(diào)用失敗時,Dubbo 提供了多種容錯方案,缺省為 failover 重試。
集群容錯模式主要有以下幾種:
Failover Cluster
失敗自動切換,當出現(xiàn)失敗,重試其它服務(wù)器。通常用于讀操作,但重試會帶來更長延遲。可通過 retries="2" 來設(shè)置重試次數(shù)(不含第一次)。
消費方服務(wù)級注解添加(不能到方法級)
Failfast Cluster
快速失敗,只發(fā)起一次調(diào)用,失敗立即報錯。通常用于非冪等性的寫操作,比如新增記錄。
Failsafe Cluster
失敗安全,出現(xiàn)異常時,直接忽略。通常用于寫入審計日志等操作。
Failback Cluster
失敗自動恢復(fù),后臺記錄失敗請求,定時重發(fā)。通常用于消息通知操作。
Forking Cluster
并行調(diào)用多個服務(wù)器,只要一個成功即返回。通常用于實時性要求較高的讀操作,但需要浪費更多服務(wù)資源??赏ㄟ^ forks="2" 來設(shè)置最大并行數(shù)。
Broadcast Cluster
廣播調(diào)用所有提供者,逐個調(diào)用,任意一臺報錯則報錯。通常用于通知所有提供者更新緩存或日志等本地資源信息。
集群模式配置方法
在服務(wù)提供方和消費方配置集群模式
6. 整合hystrix
Hystrix 旨在通過控制那些訪問遠程系統(tǒng)、服務(wù)和第三方庫的節(jié)點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備擁有回退機制和斷路器功能的線程和信號隔離,請求緩存和請求打包,以及監(jiān)控和配置等功能。
spring boot官方提供了對hystrix的集成,直接在pom.xml里加入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
然后在Application類上增加@EnableHystrix來啟用hystrix starter:
配置服務(wù)提供方:
在Dubbo的Provider上增加@HystrixCommand 配置,這樣子調(diào)用就會經(jīng)過Hystrix代理。
配置服務(wù)消費方:
對于Consumer端,則可以增加一層method調(diào)用,并在method上配置@HystrixCommand 。當調(diào)用出錯時,會走到 fallbackMethod = "reliable" 的調(diào)用里。
@HystrixCommand注解設(shè)置的 reliable 調(diào)用方法的里的參數(shù)要和 method 的參數(shù)保持一致。
ActiveMq消息被重復(fù)消費,丟失,或者不消費怎么辦
重復(fù)消費:Queue支持存在多個消費者,但是對一個消息而言,只會有一個消費者可以消費。
丟消息:用持久化消息,或者非持久化消息及時處理不要堆積,或者啟動事務(wù),啟動事務(wù)后,commit()方法會負責任的等待服務(wù)器的返回,也就不會關(guān)閉連接導(dǎo)致消息丟失了。
不消費:去ActiveMQ.DLQ里找找
怎樣解決activeMQ的消息持久化問題?
A:持久化為文件
這個你裝ActiveMQ時默認就是這種,只要你設(shè)置消息為持久化就可以了。涉及到的配置和代碼有
<persistenceAdapter>
<kahaDB directory="${activemq.base}/data/kahadb"/>
</persistenceAdapter>
producer.Send(request, MsgDeliveryMode.Persistent, level, TimeSpan.MinValue);
B:持久化為MySql
加載驅(qū)動jar,為數(shù)據(jù)中創(chuàng)建三個數(shù)據(jù)庫表,存儲activemq的消息信息
如果activeMQ的消息沒有發(fā)送成功,怎樣確保再次發(fā)送成功。
重新傳遞消息的情況
ActiveMQ在接收消息的Client有以下幾種操作的時候,需要重新傳遞消息:
1:Client用了transactions(事務(wù)),且在session中調(diào)用了rollback()
2:Client用了transactions,且在調(diào)用commit()之前關(guān)閉
3:Client在CLIENT_ACKNOWLEDGE的傳遞模式下,在session中調(diào)用了recover()
確??蛻舳擞袔追N狀態(tài),檢測狀態(tài),只要提交了那就說明客戶端成功!
Zookeeper怎樣進行服務(wù)治理。
接受提供者的接口信息和提供者ip地址進行存儲,然后管理消費者和提供者之間調(diào)用關(guān)系!
如果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ù)
Dubbo有3次重試,假如新消息被重復(fù)消費怎么處理
1、去掉超時重試機制
2、服務(wù)端增加冪等校驗,服務(wù)器加入校驗機制,如果這個消息已被 消費就不再重復(fù)消費
MQ消費者接收不到消息怎么辦。
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重啟時這兩個字段會被重置為默認值。
系統(tǒng)的高并發(fā)問題是怎么解決的。
并發(fā)問題高,這個問題的解決方案是一個系統(tǒng)性的,系統(tǒng)的每一層面都需要做優(yōu)化:
1) 數(shù)據(jù)層
a) 集群
b) 分表分庫
c) 開啟索引
d) 開啟緩存
e) 表設(shè)計優(yōu)化
f) Sql語句優(yōu)化
g) 緩存服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
h) 搜索服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
2) 項目層
a) 采用面向服務(wù)分布式架構(gòu)(分擔服務(wù)器壓力,提高并發(fā)能力)
b) 采用并發(fā)訪問較高的詳情系統(tǒng)采用靜態(tài)頁面
c) 使用頁面緩存
d) 用ActiveMQ使得業(yè)務(wù)進一步進行解耦,提高業(yè)務(wù)處理能力
e) 使用分布式文件系統(tǒng)存儲海量文件
3) 應(yīng)用層
a) Nginx服務(wù)器來做負載均衡
b) Lvs做二層負載
并發(fā)數(shù)多少,項目中怎么解決并發(fā)問題?
面試中項目的并發(fā)數(shù)不宜說的過大,安裝目前谷粒商城項目拆分規(guī)模,這個項目的并發(fā)是在10000+,但是學生面試不能說的這么高。
可以有以下2方面的回答:
1) 項目并發(fā)并不清楚(只是底層程序員)
2) 參與核心業(yè)務(wù)設(shè)計,知道并發(fā)是多少(測試峰值,上線并發(fā))
3000---5000吧
面對項目高并發(fā),項目必須做各種優(yōu)化措施了:
4) 數(shù)據(jù)層
a) 集群
b) 分表分庫
c) 開啟索引
d) 開啟緩存
e) 表設(shè)計優(yōu)化
f) Sql語句優(yōu)化
g) 緩存服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
h) 搜索服務(wù)器(提高查詢效率,減輕數(shù)據(jù)庫壓力)
5) 項目層
a) 采用面向服務(wù)分布式架構(gòu)(分擔服務(wù)器壓力,提高并發(fā)能力)
b) 采用并發(fā)訪問較高的詳情系統(tǒng)采用靜態(tài)頁面
c) 使用頁面緩存
d) 用ActiveMQ使得業(yè)務(wù)進一步進行解耦,提高業(yè)務(wù)處理能力
e) 使用分布式文件系統(tǒng)存儲海量文件
6) 應(yīng)用層
a) Nginx服務(wù)器來做負載均衡
b) Lvs做二層負載
消息發(fā)送失敗怎么處理,發(fā)送數(shù)據(jù),數(shù)據(jù)庫已經(jīng)保存了數(shù)據(jù),但是redis中沒有同步,怎么辦?;蛘哒f如何做到消息同步。
消息發(fā)送失敗,可以進行消息的重新發(fā)送,可以配置消息的重發(fā)次數(shù)。
如果消息重發(fā)完畢后,消息還沒有接受成功,重啟服務(wù)。
Dubbo的通信原理?
Dubbo底層使用hessain2進行二進制序列化進行遠程調(diào)用
Dubbo底層使用netty框架進行異步通信。NIO
其他技術(shù)面試問題
單點登錄的訪問或者跨域問題
首先要理解什么是單點登錄。單點登錄是相互信任的系統(tǒng)模塊登錄一個模塊后,其他模塊不需要重復(fù)登錄即認證通過。項目采用的是CAS單點登錄框架完成的。首先CAS有兩大部分??蛻舳撕头?wù)端。服務(wù)端就是一個web工程部署在tomcat中。在服務(wù)端完成用戶認證操作。每次訪問系統(tǒng)模塊時,需要去CAS完成獲取ticket。當驗證通過后,訪問繼續(xù)操作。對于CAS服務(wù)端來說,我們訪問的應(yīng)用模塊就是CAS客戶端。
跨域問題,首先明白什么是跨域。什么時候涉及跨域問題。當涉及前端異步請求的時候才涉及跨域。那什么是跨域呢?當異步請求時,訪問的請求地址的協(xié)議、ip地址、端口號任意一個與當前站點不同時,就會涉及跨域訪問。解決方案:1、jQuery提供了jsonp實現(xiàn)2、W3C標準提供了CORS(跨域資源共享)解決方案。
shiro安全認證時如何做的
要明白shiro執(zhí)行流程以及shiro的核心組件
認證過程:
在application Code應(yīng)用程序中調(diào)用subject的login方法。將頁面收集的用戶名和密碼傳給安全管理器securityManager,將用戶名傳給realm對象。Realm對象可以理解為是安全數(shù)據(jù)橋,realm中認證方法基于用戶名從數(shù)據(jù)庫中查詢用戶信息。如果用戶存在,將數(shù)據(jù)庫查詢密碼返回給安全管理器securityManager,然后安全管理器判斷密碼是否正確。
ES的用途
ES在系統(tǒng)中主要完成商品搜索功能,提高搜索性能。
分布式鎖的問題
針對分布式鎖的實現(xiàn),目前比較常用的有以下幾種方案:
1.基于數(shù)據(jù)庫實現(xiàn)分布式鎖
2.基于緩存(redis,memcached,tair)實現(xiàn)分布式鎖
3.基于zookeeper實現(xiàn)分布式鎖
ES索引中使用了IK分詞器,你們項目中使用到了分詞器的哪種工作模式?
IK分詞器,基本可分為兩種模式,一種為smart模式,一種為非smart模式。
例如:張三說的確實在理
smart模式的下分詞結(jié)果為:
張三 | 說的 | 確實 | 在理
而非smart模式下的分詞結(jié)果為:
張三 | 三 | 說的 | 的確 | 的 | 確實 | 實在 | 在理
可見非smart模式所做的就是將能夠分出來的詞全部輸出;smart模式下,IK分詞器則會根據(jù)內(nèi)在方法輸出一個認為最合理的分詞結(jié)果,這就涉及到了歧義判斷。
項目中采用的是smart模塊分詞的。
java中關(guān)于多線程的了解你有多少?線程池有涉及嗎?
同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器(PC),線程切換開銷小。線程分為五個階段:創(chuàng)建、就緒、運行、阻塞、終止。
Java線程有五種基本狀態(tài)
新建狀態(tài)(New):當線程對象對創(chuàng)建后,即進入了新建狀態(tài),如:Thread t = new MyThread();
就緒狀態(tài)(Runnable):當調(diào)用線程對象的start()方法(t.start();),線程即進入就緒狀態(tài)。處于就緒狀態(tài)的線程,只是說明此線程已經(jīng)做好了準備,隨時等待CPU調(diào)度執(zhí)行,并不是說執(zhí)行了t.start()此線程立即就會執(zhí)行;
運行狀態(tài)(Running):當CPU開始調(diào)度處于就緒狀態(tài)的線程時,此時線程才得以真正執(zhí)行,即進入到運行狀態(tài)。注:就 緒狀態(tài)是進入到運行狀態(tài)的唯一入口,也就是說,線程要想進入運行狀態(tài)執(zhí)行,首先必須處于就緒狀態(tài)中;
阻塞狀態(tài)(Blocked):處于運行狀態(tài)中的線程由于某種原因,暫時放棄對CPU的使用權(quán),停止執(zhí)行,此時進入阻塞狀態(tài),直到其進入到就緒狀態(tài),才 有機會再次被CPU調(diào)用以進入到運行狀態(tài)。根據(jù)阻塞產(chǎn)生的原因不同,阻塞狀態(tài)又可以分為三種:
1.等待阻塞:運行狀態(tài)中的線程執(zhí)行wait()方法,使本線程進入到等待阻塞狀態(tài);
2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態(tài);
3.其他阻塞 -- 通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請求時,線程會進入到阻塞狀態(tài)。當sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉(zhuǎn)入就緒狀態(tài)。
死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。
Java中線程的創(chuàng)建常見有如三種基本形式
1.繼承Thread類,重寫該類的run()方法。
2.實現(xiàn)Runnable接口,并重寫該接口的run()方法,
該run()方法同樣是線程執(zhí)行體,創(chuàng)建Runnable實現(xiàn)類的實例,并以此實例作為Thread類的target來創(chuàng)建Thread對象,該Thread對象才是真正的線程對象。
3.使用Callable和Future接口創(chuàng)建線程。
具體是創(chuàng)建Callable接口的實現(xiàn)類,并實現(xiàn)clall()方法。并使用FutureTask類來包裝Callable實現(xiàn)類的對象,且以此FutureTask對象作為Thread對象的target來創(chuàng)建線程。
線程池:線程池是一種多線程處理形式,處理過程中將任務(wù)添加到隊列,然后在創(chuàng)建線程后自動啟動這些任務(wù)。線程池線程都是后臺線程。每個線程都使用默認的堆棧大小,以默認的優(yōu)先級運行,并處于多線程單元中。如果某個線程在托管代碼中空閑(如正在等待某個事件),則線程池將插入另一個輔助線程來使所有處理器保持繁忙。如果所有線程池線程都始終保持繁忙,但隊列中包含掛起的工作,則線程池將在一段時間后創(chuàng)建另一個輔助線程但線程的數(shù)目永遠不會超過最大值。超過最大值的線程可以排隊,但他們要等到其他線程完成后才啟動。
如何實現(xiàn)線程的同步?
為何要使用同步?
java允許多線程并發(fā)控制,當多個線程同時操作一個可共享的資源變量時(如數(shù)據(jù)的增刪改查),將會導(dǎo)致數(shù)據(jù)不準確,相互之間產(chǎn)生沖突,因此加入同步鎖以避免在該線程沒有完成操作之前,被其他線程的調(diào)用,從而保證了該變量的唯一性和準確性。
線程同步(5種同步方式)
1.同步方法 2.同步代碼塊 3.使用特殊域變量(volatile)實現(xiàn)線程同步 4.使用重入鎖實現(xiàn)線程同步 5.使用局部變量實現(xiàn)線程同步
遍歷hashmap有幾種方式?
Map的四種遍歷方式
(1) for each map.entrySet()
(2) 顯示調(diào)用map.entrySet()的集合迭代器
(3) for each map.keySet(),再調(diào)用get獲取
(4) for each map.entrySet(),用臨時變量保存map.entrySet()
簡單介紹一下Es全文檢索在整個系統(tǒng)中的應(yīng)用,在更新索引庫的同時會產(chǎn)生索引碎片,這個碎片是如何處理的?
根據(jù)商品的名稱,分類,品牌等屬性來創(chuàng)建索引進行商品搜索。
更新索引庫時會先刪除索引,然后再重建。而對于刪除聚集索引,則會導(dǎo)致對應(yīng)的非聚集索引重建兩次(刪除時重建,建立時再重建).直接刪除碎片。
java并發(fā)包下有哪些并發(fā)組件?
分為兩層組成
外層框架主要有Lock(ReentrantLock、ReadWriteLock等)、同步器(semaphores等)、阻塞隊列(BlockingQueue等)、Executor(線程池)、并發(fā)容器(ConcurrentHashMap等)、還有Fork/Join框架;
內(nèi)層有AQS(AbstractQueuedSynchronizer類,鎖功能都由他實現(xiàn))、非阻塞數(shù)據(jù)結(jié)構(gòu)、原子變量類(AtomicInteger等無鎖線程安全類)三種。
講一下jvm調(diào)優(yōu)。
a,堆大小設(shè)置
b,回收器選擇
c,輔助信息
JVM提供了大量命令行參數(shù),打印信息,供調(diào)試使用;
講一下jvm的組成。
JVM 由類加載器子系統(tǒng)、運行時數(shù)據(jù)區(qū)、執(zhí)行引擎以及本地方法接口組成
講一下ThreadLocal類。
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,其實意思差不多??赡芎芏嗯笥讯贾繲hreadLocal為變量在每個線程中都創(chuàng)建了一個副本,那么每個線程可以訪問自己內(nèi)部的副本變量;
ThreadLocal在每個線程中對該變量會創(chuàng)建一個副本,即每個線程內(nèi)部都會有一個該變量,且在線程內(nèi)部任何地方都可以使用,線程之間互不影響,這樣一來就不存在線程安全問題,也不會嚴重影響程序執(zhí)行性能。
但是要注意,雖然ThreadLocal能夠解決上面說的問題,但是由于在每個線程中都創(chuàng)建了副本,所以要考慮它對資源的消耗,比如內(nèi)存的占用會比不使用ThreadLocal要大;
怎么確保session共享?
在分布式項目中實現(xiàn)session共享必須做以下準備工作:
1) Cookie中共享ticket
2) Redis存儲session
分布式系統(tǒng)共享用戶身份信息session,必須先獲取ticket票據(jù),然后再根據(jù)票據(jù)信息獲取redis中用戶身份信息。
實現(xiàn)以上2點即可實現(xiàn)session共享。
目前項目中使用的springsecurity + cas 來實現(xiàn)的單點登錄,cas自動產(chǎn)生ticket票據(jù)信息,每次獲取用戶信息,cas將會攜帶ticket信息獲取用戶身份信息。
項目中哪塊涉及了線程問題,怎么處理的?
項目的高并發(fā)訪問就是一個多線程問題。
項目中普通的業(yè)務(wù)開發(fā)基本沒有涉及多線程問題,不過你可以談?wù)勀闶褂玫目蚣苤惺褂玫亩嗑€程技術(shù):
因為我們項目使用的框架進行開發(fā)的,因此多線程處理多讓框架非我們處理結(jié)束了。
1) 高并發(fā)就是多線程,這里的多線程讓servlet服務(wù)器給處理了談?wù)凾omcat多線程配置;
a) 配置線程池,擴大并發(fā)能力
b) 開啟NIO能力等等
2) 框架多線程:mybatis 框架底層使用的連接池