面試阿里後的總結

畢業從事java開發工作4年,被別人面試過好多次,也面試過別人,感覺人跟人的差距可以好大,
有的人工作沒幾年,但技術廣度和深度都很夠;有的人工作近10年,好多基礎原理都不明白。


今年一個月內面了3次阿里天貓3個不同部門,全在首輪電面掛了,好打擊,也感覺好失敗,浪費了不少機會


總結了一下,技術廣度是夠了,但技術深度不夠,但感覺還不夠紮實,尤其某些技術細節瞭解得不夠透徹


看的書夠多,但都不夠深入,有不少沒有親自去實踐,說白了就是懶,技術人員需要不斷努力學習


看技術書是比較燒腦的一個過程,技術能力不是你工作多少年決定的,而是你學了多少決定的


推薦一些書給各位


<<深入理解計算機系統>> 這本書很好啊,神器啊,值得深讀
<<深入理解Java虛擬機>> 周志明 
<<數據結構和算法>> java版
<<併發編程藝術>> 阿里技術專家寫的
<< 億級流量網站架構核心技術>> 開濤哥的
<<springboot實戰教程>>   快速上手
<<redis源碼分析>>   
<<高性能MySQL>>
現在雲技術是趨勢,hadoop我覺得還是必須要學的
<<hadoop權威指南>>


下面隨便寫了點被面的知識點,技術要工作之後不斷深究,不能偷懶。






消息隊列
描述:消息隊列中間件是分佈式系統中重要的組件
作用:異步處理,應用解耦,流量削鋒和消息通訊。
例子:註冊-發送郵件
      訂單系統,庫存系統
      搶購-放入消息隊列-異步批量處理
      日誌處理


常用的:rabbitmq,rocketmq,kafaka
非主流的:redis


消息隊列主要四大問題:生產失敗,消息丟失,消息重複消費如何處理,消息順序性


生產者-> 隊列-> 消費者


生產失敗可以重發加個3次確認機制
消息丟失可以同步持久化到硬盤,當性能會降低
消息重複客戶端可以根據id自己做去重處理
比較簡單有效的實現消息順序性的方式就是單線程生產者+單線程消費者+每個消費線程對應一個單獨隊列, 排除消息丟失的情況,可以做到嚴格有序。


消息隊列的投遞方式可以分爲push和pull2種,一種模型的某些場景下的優點,在另一些場景就可能是缺點。無論是push還是pull,都存在各種的利弊。
push的優點就是及時性,缺點就是受限於消費者的消費能力,可能造成消息的堆積,broker會不斷給消費者發送不能處理的消息。
pull的優點的就是主動權掌握在消費方,可以根據自己的消息速度進行消息拉取,缺點就是消費方不知道什麼時候可以獲取的最新的消息,會有消息延遲和忙等。




發佈和訂閱
主動推,和自己拉去,先進後出,先進先出


緩存


服務端緩存,客戶端緩存,廣域網緩存-cdn


服務端緩存:jvm緩存,堆外緩存,分佈式緩存,本地硬盤緩存,靜態化
客戶端緩存:瀏覽器緩存,app客戶端緩存


jvm緩存 


分佈式緩存 redis緩存


redis 3.0支持集羣


高可用
快速選主策略。例如zookepper
數據分主從備份
負載均衡:負載均衡,失敗重試,健康檢查,動態切換
限流降級:降級預警,配置中心,斷融機制,讀寫服務降級
隔離:冷熱數據隔離,讀寫隔離,動靜隔離
超時和重試
預測和預案


緩存雪崩
使用全局互斥鎖,當緩存失效,節點從db獲取數據 load進緩存,再獲取
原有的失效時間基礎上增加一個隨機值,防止同時失效,集體穿透到數據庫
緩存永遠不過期,但要定時刷新
使用斷容器組件hystrix,具有降級策略


key-value存儲系統,數據都是緩存在內存中
Memcached區別:它支持存儲的value類型相對更多
               redis會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件


redis3.0集羣默認是3主3從,槽16384
當查找某個key不在所在節點會返回所在的節點名


提高可用性和實時性,沒法實時強一致性,只保證最終一致性


持久化到硬盤,有同步和異步,看產品要求






線程


兩種實現方式:繼承Thread類、實現Runnable接口


wait():釋放佔有的對象鎖,線程進入等待池,釋放cpu,而其他正在等待的線程即可搶佔此鎖,獲得鎖的線程即可運行程序。
而sleep()不同的是,線程調用此方法後,會休眠一段時間,休眠期間,會暫時釋放cpu,但並不釋放對象鎖。也就是說,在休眠期間,
其他線程依然無法進入此代碼內部。休眠結束,線程重新獲得cpu,執行代碼。wait()和sleep()最大的不同在於wait()會釋放對象鎖,而sleep()不會!


notify(): 該方法會喚醒因爲調用對象的wait()而等待的線程,其實就是對對象鎖的喚醒,從而使得wait()的線程可以有機會獲取對象鎖。調用notify()後
,並不會立即釋放鎖,而是繼續執行當前代碼,直到synchronized中的代碼全部執行完畢,纔會釋放對象鎖。JVM則會在等待的線程中調度一個線程去獲得對象鎖
,執行代碼。需要注意的是,wait()和notify()必須在synchronized代碼塊中調用。


newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
newFixedThreadPool 創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
newScheduledThreadPool 創建一個定長線程池,支持定時及週期性任務執行。
newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行




synchronized 
都是可以重入互斥鎖:可以支持一個線程對鎖的重複獲取
monitorenter和monitorexit
lock
區別:自旋鎖
lock要自己加鎖去鎖,一定要在finally裏面去鎖
Synchronized鎖非公平鎖 lock可以設置成公平鎖但這樣性能較差
lock鎖綁定多個條件,一個ReentrantLock對象可以同時綁定對個對象。


lock原理
lock它通過一個int類型的狀態變量state和一個FIFO隊列




volatile 去掉編譯期間優化重排序,直接從主內存獲取值,而不是線程工作內存








ReentrantReadWriteLock
可重入讀寫鎖(讀寫鎖的一個實現)兩者都有lock,unlock方法。寫寫,寫讀互斥;讀讀不互斥。可以實現併發讀的高效線程安全代碼




CAS交換並且比較,java有原子類AtomicInteger
樂觀鎖 AtomicStampedReference 解決ABA問題


BIO NIO AIO
BIO 一個Socket鏈接一個線程,消耗大,同步堵塞, 類似酒店裏面的包廂專廂服務員 
NIO的最重要的地方是當一個連接創建後,不需要對應一個線程,這個連接會被註冊到多路複用器上面,所以所有的連接只需要一個線程就可以搞定
NIO 一個線程或者多個處理多個Socket,同步非堵塞 ,酒店裏面的大廳 服務員


AIO 異步非堵塞 操作系統主動通知應用程序,類似  酒店訂餐,然後顧客先去玩,菜好了,酒點會打電話通知
當進行讀寫操作時,只須直接調用API的read或write方法即可。這兩種方法均爲異步的,對於讀操作而言,當有流可讀取時,操作系統會將可讀的流傳入read方法的緩衝區,並通知應用程序


同步阻塞IO:在此種方式下,用戶進程在發起一個IO操作以後,必須等待IO操作的完成,只有當真正完成了IO操作以後,用戶進程才能運行。JAVA傳統的IO模型屬於此種方式!
同步非阻塞IO:在此種方式下,用戶進程發起一個IO操作以後邊可返回做其它事情,但是用戶進程需要時不時的詢問IO操作是否就緒,這就要求用戶進程不停的去詢問,從而引入不必要的CPU資源浪費。其中目前JAVA的NIO就屬於同步非阻塞IO。
異步阻塞IO:此種方式下是指應用發起一個IO操作以後,不等待內核IO操作的完成,等內核完成IO操作以後會通知應用程序,這其實就是同步和異步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼爲什麼說是阻塞的呢?
因爲此時是通過select系統調用來完成的,而select函數本身的實現方式是阻塞的,而採用select函數有個好處就是它可以同時監聽多個文件句柄,從而提高系統的併發性!
 異步非阻塞IO:在此種模式下,用戶進程只需要發起一個IO操作然後立即返回,等IO操作真正的完成以後,應用程序會得到IO操作完成的通知,此時用戶進程只需要對數據進行處理就好了,不需要進行實際的IO讀寫操作,因爲真正的IO讀取或者寫入操作已經由內核完成了。


linux提供select/poll,進程通過將一個或多個fd傳遞給select或poll系統調用,阻塞在select;這樣select/poll可以幫我們偵測許多fd是否就緒。但是select/poll是順序掃描fd是否就緒,
而且支持的fd數量有限。linux還提供了一個epoll系統調用,epoll是基於事件驅動方式,而不是順序掃描,當有fd就緒時,立即回調函數rollback;




mysql的sql優化


合理的表結構
大表查詢去掉表關聯
充分利用索引字段
explan 檢查mysql語句




mysql


一主多從
雙主多從,但只從一主插入數據,另一組備份
keepalived+VIP 虛擬ip動態切換




MyISAM 不支持事務,行級鎖,還有外鍵索引
MyISAM Merge引擎:這種類型是MyISAM類型的一種變種。合併表是將幾個相同的MyISAM表合併爲一個虛表。常應用於日誌和數據倉
innerDB 支持事務,行級鎖,外鍵索引
4 memory(heap):這種類型的數據表只存在於內存中。它使用散列索引,所以數據的存取速度非常快。因爲是存在於內存中,所以這種類型常應用於臨時表中。
5 archive:這種類型只支持select 和 insert語句,而且不支持索引。常應用於日誌記錄和聚合分析方面。
速度較快




mysql 半同步複製,和異步複製




。


Mybatis:1:使用連接池,datasource,在驅動並連接的這個過程中優化並解耦  J
DBC第一步其實從效率角度來看是不合適的,因爲無論什麼數據庫都不可能支撐隨機和龐大的連接數,
而且不可避免的存在連接浪費的情況,Mybatis就封裝了這些優化的方法。
2:統一sql存取到XML  如果代碼寫在java塊中,在團隊合作中很可能出現兩個交叉業務的代碼使用類似的sql語句,而開發人員的工作本身沒有交集,
那就代表sql語句肯定是無法複用的。而且對sql的修改,就代表着對java文件的修改,需要重新編譯和打包部署(比如常見的狀態值更改,sql修改隨着業務變化必然存在修改)。 
 mybatis將sql統一存取到xml中,就算存在業務交叉,但因爲統一配置的緣故,sql在xml中一目瞭然,
兩個跨team的程序員可以看到對方的sql,來判斷自己是否需要重用。並且使用xml配置可以減少代碼編譯。  還有就是在java中拼寫長sql太噁心了。
3:參數和結果集映射  sql的方式需要傳入參數,如果存在多條件“或類型”的查詢(列表查詢的查詢條件允許空),那就代表你必須傳參進行sql拼接,就算使用xml的方式也不行。
要麼每個業務獨立配置xml中的sql,要麼還是寫入java代碼中,或者以工具的方式進行自動拼接。  
Mybatis使用映射的方式,方便model管理參數,同時以解析器的方式將參數動態拼接到sql(sqlmaper裏那些標籤),由於是model映射,連查詢結果都可以統一映射,方便取出和運算。
而且mybatis對查詢結果集進行了緩存處理,使得重複查詢進一步進行了優化。4:對多重複sql進行復用封裝  比如模板方法,將常用sql模塊化,直接調用。
比如通用的save和getID之類的,只有表名和字段名有變化。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章