一、用戶向服務器發送請求,請求被SpringMVC的前端控制器DispatcherServlet截獲。html
二、DispatcherServlet對請求的URL(統一資源定位符)進行解析,獲得URI(請求資源標識符),而後根據該URI,調用HandlerMapping得到該Handler配置的全部相關的對象,包括Handler對象以及Handler對象對應的攔截器,這些對象都會被封裝到一個HandlerExecutionChain對象當中返回。前端
三、DispatcherServlet根據得到的Handler,選擇一個合適的HandlerAdapter。HandlerAdapter的設計符合面向對象中的單一職責原則,代碼結構清晰,便於維護,最爲重要的是,代碼的可複製性高。HandlerAdapter會被用於處理多種Handler,調用Handler實際處理請求的方法。java
四、提取請求中的模型數據,開始執行Handler(Controller)。在填充Handler的入參過程當中,根據配置,spring將幫助作一些額外的工做mysql
消息轉換:將請求的消息,如json、xml等數據轉換成一個對象,將對象轉換爲指定的響應信息。nginx
數據轉換:對請求消息進行數據轉換,如String轉換成Integer、Double等。 程序員
數據格式化:對請求的消息進行數據格式化,如將字符串轉換爲格式化數字或格式化日期等。angularjs
數據驗證:驗證數據的有效性如長度、格式等,驗證結果存儲到BindingResult或Error中。web
五、Handler執行完成後,向DispatcherServlet返回一個ModelAndView對象,ModelAndView對象中應該包含視圖名或視圖模型。面試
六、根據返回的ModelAndView對象,選擇一個合適的ViewResolver(視圖解析器)返回給DispatcherServlet。ajax
七、ViewResolver結合Model和View來渲染視圖。
八、將視圖渲染結果返回給客戶端。
以上8個步驟,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver等對象協同工做,完成SpringMVC請求—>響應的整個工做流程,這些對象完成的工做對於開發者來講都是不可見的,開發者並不須要關心這些對象是如何工做的,開發者,只須要在Handler(Controller)當中完成對請求的業務處理。
前端實現異步上傳,後端使用springmvc的MultipartFile類型來接收,放到分佈式圖片服務器中,服務器返回圖片路徑把路徑返回頁面回顯圖片,開發或者測試環境能夠使用FastDFS
若是一句話來談SOA和微服務的區別,即微服務再也不強調傳統SOA架構裏面比較重的ESB企業服務總線,同時SOA的思想進入到單個業務系統內部實現真正的組件化。說的更直白一點就是微服務被拆分的粒度更小
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實現事務控制。
第一種方案:可靠消息最終一致性,須要業務系統結合MQ消息中間件實現,在實現過程當中須要保證消息的成功發送及成功消費。即須要經過業務系統控制MQ的消息狀態
第二種方案:TCC補償性,分爲三個階段TRYING-CONFIRMING-CANCELING。每一個階段作不一樣的處理。
TRYING階段主要是對業務系統進行檢測及資源預留
CONFIRMING階段是作業務提交,經過TRYING階段執行成功後,再執行該階段。默認若是TRYING階段執行成功,CONFIRMING就必定能成功。
CANCELING階段是回對業務作回滾,在TRYING階段中,若是存在分支事務TRYING失敗,則須要調用CANCELING將已預留的資源進行釋放。
Springboot是從無數企業實戰開發中總結出來的一個更加精煉的框架,使得開發更加簡單,能使用寥寥數行代碼,完成一系列任務。
1) Springboot解決那些問題
a) 編碼更簡單
i. Spring框架因爲超重量級的XML,annotation配置,使得系統變得很笨重,難以維護
ii. Springboot採用約點大於配置的方法,直接引入依賴,便可實現代碼的開發
b) 配置更簡單
Xml文件使用javaConfig代替,XML中bean的建立,使用@bean代替後能夠直接注入。
配置文件變少不少,就是application.yml
c) 部署更簡單
d) 監控更簡單
Spring-boot-start-actuator:
能夠查看屬性配置
線程工做狀態
環境變量
JVM性能監控
微信支付
調用微信的支付接口,參考微信提供的api
使用了微信的統一下單接口和查詢支付狀態接口
每一個接口須要的參數放入到map中使用微信提供的sdk轉成XML字符串,httpClient遠程提交參數和接收結果。
支付寶支付
Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各類啓動器,開發者能快速上手。
Spring Boot 優勢很是多,如:
獨立運行
簡化配置
自動配置
無代碼生成和XML配置
應用監控
上手容易
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。
bootstrap 配置文件有如下幾個應用場景。
.properties 和 .yml,它們的區別主要是書寫格式不一樣。
啓動類上面的註解是@SpringBootApplication,它也是 Spring Boot 的核心註解,主要組合包含了如下 3 個註解:
@SpringBootConfiguration:組合了 @Configuration 註解,實現配置文件的功能。
@EnableAutoConfiguration:打開自動配置的功能,也能夠關閉某個自動配置的選項,如關閉數據源自動配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring組件掃描。
1)繼承spring-boot-starter-parent項目
2)導入spring-boot-dependencies項目依賴
能夠不須要,內置了 Tomcat/ Jetty 等容器.
1)打包用命令或者放到容器中運行
2)用 Maven/ Gradle 插件運行
3)直接執行 main 方法運行
註解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。
Starters能夠理解爲啓動器,它包含了一系列能夠集成到應用裏面的依賴包,你能夠一站式集成 Spring 及其餘技術,而不須要處處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數據庫,只要加入 spring-boot-starter-data-jpa 啓動器依賴就能使用了。
Starters包含了許多項目中須要用到的依賴,它們能快速持續的運行,都是一系列獲得支持的管理傳遞性依賴.
能夠實現接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現方式同樣,它們都只提供了一個 run 方法.
Spring Boot 能夠經過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量
商品上架後更新ES索引庫、更新靜態頁、發送短信
秒殺商品的庫存都會放到redis中,在客戶下單時就減庫存,減完庫存會判斷庫存是否爲大於 0,若是小於0,表示庫存不足,剛纔減去的數量再恢復,整個過程使用redis的watch鎖。
訂單表中設置了一個過時時間,天天會有定時任務來掃描訂單表數據,若是到達預訂的過時時間沒有付款就會取消此訂單交易。
關於庫存的設計是這樣的:
普通商品在發貨時纔去更新庫存,若是庫存不足商家會立刻補貨
秒殺的商品會在客戶下單時就減庫存,若是在規定時間(半個小時)沒有付款,會取消此訂單把庫存還原
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框架。
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入隊時並無異常高的網絡流量,僅僅在出隊時會產生很高的網絡流量。
研究源碼發現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的吞吐性能。
購物車只存儲商品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部署靜態頁面實現動靜分離
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中清除。
建立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,會按照中國人用此習慣自動分詞。
使用restful,或靜態頁這樣能更好的被搜索引擎收錄。
硬件上加大網絡帶寬、和服務器內存
代碼的處理:靜態頁面、緩存、優化sql、建立索引等方案
內存若是滿了,採用LRU算法進行淘汰。
Redis如何實現負載的?採用Hash槽來運算存儲值,使用CRC16算法取模運算,來保證負載問題。
Redis緩存穿透問題?將數據查詢出來若是沒有強制設置空值,而且設置過時時間,減小頻繁查詢數據庫。
redis在項目中應用:1.主要應用在門戶網站首頁廣告信息的緩存。由於門戶網站訪問量較大,將廣告緩存到redis中,能夠下降數據庫訪問壓力,提升查詢性能。2.應用在用戶註冊驗證碼緩存。利用redis設置過時時間,當超過指定時間後,redis清理驗證碼,使過時的驗證碼無效。3.用在購物車模塊,用戶登錄系統後,添加的購物車數據須要保存到redis緩存中。
使用redis主要是減小系統數據庫訪問壓力。從緩存中查詢數據,也提升了查詢性能,挺高用戶體驗度。
是原子性的。對於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、組合索引和單索引的創建,要考慮查詢實際和具體模式
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, 異步處理:如發微博、記錄日誌
實現思想
獲取鎖的時候,使用setnx加鎖,並使用expire命令爲鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值爲一個隨機生成的UUID,經過此在釋放鎖的時候進行判斷。
獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
釋放鎖的時候,經過UUID判斷是否是該鎖,如果該鎖,則執行delete進行鎖釋放。
設置過時:
this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);
持久化方式:Redis默認的RDB方式
RDB:保存存儲文件到磁盤;同步時間爲15分鐘,5分鐘,1分鐘一次,可能存在數據丟失問題。
AOF:保存命令文件到磁盤;安全性高,修改後當即同步或每秒同步一次。
上述兩種方式在咱們的項目中都有使用到,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據後從數據庫中查詢後保存到redis中
採用默認的RDB方式,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據就從數據庫中查詢後再保存到redis中
Redis經過SpringDataRedis訪問的.
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
系統性能就是兩個事:
Throughput ,吞吐量。也就是每秒鐘能夠處理的請求數,任務數。
Latency, 系統延遲。也就是系統在處理一個請求或一個任務時的延遲。
那麼Latency越好,能支持的Throughput就會越高。由於Latency短說明處理速度快,因而就能夠處理更多的請求。
提升吞吐量:
分佈式集羣,模塊解藕,設計模式
系統延遲:
異步通訊
數據庫事務的隔離級別有四種,隔離級別高的數據庫的可靠性高,但併發量低,而隔離級別低的數據庫可靠性低,但併發量高,系統開銷小。
mysql默認的事務處理級別是'REPEATABLE-READ',也就是可重複讀。
一、應儘可能避免在 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 ,用具體的字段列表代替「*」,不要返回用不到的任何字段。
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張表來實現存儲
分庫:經過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性能測試工具: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、組合索引和單索引的創建,要考慮查詢實際和具體模式
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)引入中間表。
索引是創建在表上的一種數據組織,它能提升訪問表中一條或多條記錄的特定查詢效率。
彙集索引
一種索引,該索引中鍵值的邏輯順序決定了表中相應行的物理順序。
彙集索引肯定表中數據的物理順序。
非彙集索引
一種索引,該索引中索引的邏輯順序與磁盤上行的物理存儲順序不一樣.
用了CAS,全部應用項目中若是須要登陸時在web.xml中配置過濾器作請求轉發到cas端工做原理是在cas登陸後會給瀏覽器發送一個票據(ticket),瀏覽器cookie中會緩存這個ticket,在登陸其餘項目時會拿着瀏覽器的ticket轉發到cas,到cas後根據票據判斷是否登陸
配置了redis集羣,使用redis3.0版本官方推薦的配置方式
solr集羣使用了solrCloud,使用zookeeper關聯solrCloud的配置文件
zookeeper也配置了集羣
應用層使用Nginx負載均衡
分佈式是從項目業務角度考慮劃分項目整個架構。能夠將項目基於功能模塊劃分再分別部署。Dubbo是實現分佈式項目部署框架。在zookeeper是dubbo分佈式框架的註冊中心,管理服務的註冊和調用。
項目前端採用angularjs框架在controller控制器中完成數據組裝和數據展現,在服務層(service)代碼完成中後臺請求操做。後端基於前端的接口調用,完成數據的增刪改查操做。先後端數據交互經過json格式字符串完成。
引入了ZooKeeper做爲存儲媒介,也就把ZooKeeper的特性引進來。
首先是負載均衡,單註冊中心的承載能力是有限的,在流量達到必定程度的時候就須要分流,負載均衡就是爲了分流而存在的,一個ZooKeeper羣配合相應的Web應用就能夠很容易達到負載均衡;
資源同步,單單有負載均衡還不夠,節點之間的數據和資源須要同步,ZooKeeper集羣就自然具有有這樣的功能;
命名服務,將樹狀結構用於維護全局的服務地址列表,服務提供者在啓動 的時候,向ZK上的指定節點/dubbo/${serviceName}/providers目錄下寫入本身的URL地址,這個操做就完成了服務的發佈。 其餘特性還有Mast選舉,分佈式鎖等。
能夠的,消費者在啓動時,消費者會從zk拉取註冊的生產者的地址接口等數據,緩存在本地。
每次調用時,按照本地存儲的地址進行調用
在實際生產中,假如zookeeper註冊中心宕掉,一段時間內服務消費方仍是可以調用提供方的服務的,實際上它使用的本地緩存進行通信,這只是dubbo健壯性的一種。
dubbo的健壯性表現:
註冊中心的做用在於保存服務提供者的位置信息,咱們能夠徹底能夠繞過註冊中心——採用dubbo直連,即在服務消費方配置服務提供方的位置信息。
點對點直連方式,將以服務接口爲單位,忽略註冊中心的提供者列表,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;
在集羣負載均衡時,Dubbo提供了4種均衡策略,如:Random LoadBalance(隨機均衡算法)、RoundRobin LoadBalance(權重輪循均衡算法)、LeastAction LoadBalance(最少活躍調用數均衡算法)、ConsistentHash LoadBalance(一致性Hash均衡算法)。缺省時爲Random隨機調用。
@Reference(loadbalance = "roundrobin") UserService userService;
服務方方法級別配置(基於xml配置的權重輪詢均衡算法)
<dubbo:service interface="com.zang.gmall.service.UserService" <dubbo:method name="getUserAddressList" loadbalance="roundrobin"></dubbo:method> </dubbo:service>
當不設置負載均衡策略,即採用默認的Random LoadBalance(隨機均衡算法)時,默認每一個服務的權重相同,咱們能夠經過設置權重來分配訪問的隨機性。
權重默認爲100,能夠在暴露服務的同時設置
當服務器壓力劇增的狀況下,根據實際業務狀況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運做或高效運做。
能夠經過服務降級功能臨時屏蔽某個出錯的非關鍵服務,並定義降級後的返回策略(不調用服務即返回爲空 or 調用失敗返回爲空)。
向註冊中心寫入動態配置覆蓋規則:
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"));
其中:
經過操做管理控制檯也能夠方便的進行服務降級
在集羣調用失敗時,Dubbo 提供了多種容錯方案,缺省爲 failover 重試。
Failover Cluster
失敗自動切換,當出現失敗,重試其它服務器。一般用於讀操做,但重試會帶來更長延遲。可經過 retries="2" 來設置重試次數(不含第一次)。
消費方服務級註解添加(不能到方法級)
Failfast Cluster
快速失敗,只發起一次調用,失敗當即報錯。一般用於非冪等性的寫操做,好比新增記錄。
Failsafe Cluster
失敗安全,出現異常時,直接忽略。一般用於寫入審計日誌等操做。
Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。一般用於消息通知操做。
Forking Cluster
並行調用多個服務器,只要一個成功即返回。一般用於實時性要求較高的讀操做,但須要浪費更多服務資源。可經過 forks="2" 來設置最大並行數。
Broadcast Cluster
廣播調用全部提供者,逐個調用,任意一臺報錯則報錯。一般用於通知全部提供者更新緩存或日誌等本地資源信息。
集羣模式配置方法
在服務提供方和消費方配置集羣模式
Hystrix 旨在經過控制那些訪問遠程系統、服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。Hystrix具有擁有回退機制和斷路器功能的線程和信號隔離,請求緩存和請求打包,以及監控和配置等功能。
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:
配置服務提供方:
在Dubbo的Provider上增長@HystrixCommand 配置,這樣子調用就會通過Hystrix代理。
配置服務消費方:
對於Consumer端,則能夠增長一層method調用,並在method上配置@HystrixCommand 。當調用出錯時,會走到 fallbackMethod = "reliable" 的調用裏。
重複消費:Queue支持存在多個消費者,可是對一個消息而言,只會有一個消費者能夠消費。
丟消息:用持久化消息,或者非持久化消息及時處理不要堆積,或者啓動事務,啓動事務後,commit()方法會負責任的等待服務器的返回,也就不會關閉鏈接致使消息丟失了。
不消費:去ActiveMQ.DLQ裏找找
A:持久化爲文件
這個你裝ActiveMQ時默認就是這種,只要你設置消息爲持久化就能夠了。涉及到的配置和代碼有
<persistenceAdapter>
<kahaDB directory="${activemq.base}/data/kahadb"/>
</persistenceAdapter>
producer.Send(request, MsgDeliveryMode.Persistent, level, TimeSpan.MinValue);
B:持久化爲MySql
加載驅動jar,爲數據中建立三個數據庫表,存儲activemq的消息信息
從新傳遞消息的狀況
ActiveMQ在接收消息的Client有如下幾種操做的時候,須要從新傳遞消息:
1:Client用了transactions(事務),且在session中調用了rollback()
2:Client用了transactions,且在調用commit()以前關閉
3:Client在CLIENT_ACKNOWLEDGE的傳遞模式下,在session中調用了recover()
確保客戶端有幾種狀態,檢測狀態,只要提交了那就說明客戶端成功!
接受提供者的接口信息和提供者ip地址進行存儲,而後管理消費者和提供者之間調用關係!
一、在一般的狀況下,非持久化消息是存儲在內存中的,持久化消息是存儲在文件中的,它們的最大限制在配置文件的<systemUsage>節點中配置。可是,在非持久化消息堆積到必定程度,內存告急的時候,ActiveMQ會將內存中的非持久化消息寫入臨時文件中,以騰出內存。雖然都保存到了文件裏,但它和持久化消息的區別是,重啓後持久化消息會從文件中恢復,非持久化的臨時文件會直接刪除。
二、考慮高可用,實現activemq集羣。
註冊中心對等集羣,任意一臺宕掉後,會自動切換到另外一臺
註冊中心所有宕掉,服務提供者和消費者仍能夠經過本地緩存通信
服務提供者無狀態,任一臺宕機後,不影響使用
服務提供者所有宕機,服務消費者會沒法使用,並沒有限次重連等待服務者恢復
一、去掉超時重試機制
二、服務端增長冪等校驗,服務器加入校驗機制,若是這個消息已被 消費就再也不重複消費
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作二層負載
消息發送失敗,能夠進行消息的從新發送,能夠配置消息的重發次數。
若是消息重發完畢後,消息尚未接受成功,重啓服務。
Dubbo底層使用hessain2進行二進制序列化進行遠程調用
Dubbo底層使用netty框架進行異步通訊。NIO
首先要理解什麼是單點登陸。單點登陸是相互信任的系統模塊登陸一個模塊後,其餘模塊不須要重複登陸即認證經過。項目採用的是CAS單點登陸框架完成的。首先CAS有兩大部分。客戶端和服務端。服務端就是一個web工程部署在tomcat中。在服務端完成用戶認證操做。每次訪問系統模塊時,須要去CAS完成獲取ticket。當驗證經過後,訪問繼續操做。對於CAS服務端來講,咱們訪問的應用模塊就是CAS客戶端。
跨域問題,首先明白什麼是跨域。何時涉及跨域問題。當涉及前端異步請求的時候才涉及跨域。那什麼是跨域呢?當異步請求時,訪問的請求地址的協議、ip地址、端口號任意一個與當前站點不一樣時,就會涉及跨域訪問。解決方案:一、jQuery提供了jsonp實現二、W3C標準提供了CORS(跨域資源共享)解決方案。
要明白shiro執行流程以及shiro的核心組件
認證過程:
在application Code應用程序中調用subject的login方法。將頁面收集的用戶名和密碼傳給安全管理器securityManager,將用戶名傳給realm對象。Realm對象能夠理解爲是安全數據橋,realm中認證方法基於用戶名從數據庫中查詢用戶信息。若是用戶存在,將數據庫查詢密碼返回給安全管理器securityManager,而後安全管理器判斷密碼是否正確。
ES在系統中主要完成商品搜索功能,提升搜索性能。
針對分佈式鎖的實現,目前比較經常使用的有如下幾種方案:
1.基於數據庫實現分佈式鎖
2.基於緩存(redis,memcached,tair)實現分佈式鎖
3.基於zookeeper實現分佈式鎖
IK分詞器,基本可分爲兩種模式,一種爲smart模式,一種爲非smart模式。
例如:張三說的確實在理
smart模式的下分詞結果爲:
張三 | 說的 | 確實 | 在理
而非smart模式下的分詞結果爲:
張三 | 三 | 說的 | 的確 | 的 | 確實 | 實在 | 在理
可見非smart模式所作的就是將可以分出來的詞所有輸出;smart模式下,IK分詞器則會根據內在方法輸出一個認爲最合理的分詞結果,這就涉及到了歧義判斷。
項目中採用的是smart模塊分詞的。
同一類線程共享代碼和數據空間,每一個線程有獨立的運行棧和程序計數器(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.使用局部變量實現線程同步
Map的四種遍歷方式
(1) for each map.entrySet()
(2) 顯示調用map.entrySet()的集合迭代器
(3) for each map.keySet(),再調用get獲取
(4) for each map.entrySet(),用臨時變量保存map.entrySet()
根據商品的名稱,分類,品牌等屬性來建立索引進行商品搜索。
更新索引庫時會先刪除索引,而後再重建。而對於刪除彙集索引,則會致使對應的非彙集索引重建兩次(刪除時重建,創建時再重建).直接刪除碎片。
分爲兩層組成
外層框架主要有Lock(ReentrantLock、ReadWriteLock等)、同步器(semaphores等)、阻塞隊列(BlockingQueue等)、Executor(線程池)、併發容器(ConcurrentHashMap等)、還有Fork/Join框架;
內層有AQS(AbstractQueuedSynchronizer類,鎖功能都由他實現)、非阻塞數據結構、原子變量類(AtomicInteger等無鎖線程安全類)三種。
a,堆大小設置
b,回收器選擇
c,輔助信息
JVM提供了大量命令行參數,打印信息,供調試使用;
JVM 由類加載器子系統、運行時數據區、執行引擎以及本地方法接口組成
ThreadLocal,不少地方叫作線程本地變量,也有些地方叫作線程本地存儲,其實意思差很少。可能不少朋友都知道ThreadLocal爲變量在每一個線程中都建立了一個副本,那麼每一個線程能夠訪問本身內部的副本變量;
ThreadLocal在每一個線程中對該變量會建立一個副本,即每一個線程內部都會有一個該變量,且在線程內部任何地方均可以使用,線程之間互不影響,這樣一來就不存在線程安全問題,也不會嚴重影響程序執行性能。
可是要注意,雖然ThreadLocal可以解決上面說的問題,可是因爲在每一個線程中都建立了副本,因此要考慮它對資源的消耗,好比內存的佔用會比不使用ThreadLocal要大;
在分佈式項目中實現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 框架底層使用的鏈接池