HTTP協議採用無狀態的短鏈接的通訊方式。一般一次請求就完成一次數據交互,一般也對應一個業務邏輯。 java
當在瀏覽器裏輸入一個URL,首先會請求DNS把域名解析成爲IP地址,根據IP地址找到對應的服務器,向服務器發送請求,服務器返回數據資源給訪問的用戶。數據庫
服務器端的其餘操做:負載均衡平均分配全部用戶的請求。請求數據可能存儲在分佈式緩存、靜態文件、數據庫裏。靜態資源會發起額外的HTTP請求,這些請求可能在CDN上,CDN服務器處理這個請求。設計模式
互聯網應用原則:數組
瀏覽器在創建Socket鏈接以前,必須根據地址欄裏的URL的域名DNS解析出IP,根據IP地址和默認80端口與遠程服務器創建Socket鏈接,瀏覽器根據URL組裝一個GET類型的HTTP請求頭,經過outputStream.write發送到目標服務器,服務器等待inputStream.read返回數據,最後斷開鏈接。瀏覽器
發起一個HTTP請求的過程就是創建一個Socket通訊的過程。緩存
B/S網絡架構中核心是HTTP協議。 HTTP協議中最重要的是HTTP Header。安全
HTTP Header控制着用戶瀏覽器渲染行爲和服務器的執行邏輯。 服務器
瀏覽器緩存機制:網絡
Ctrl+F5刷新頁面必定可以請求沒有緩存的頁面。 Ctrl+F5刷新頁面,瀏覽器直接向目標URL發送請求,不使用瀏覽器緩存。 數據結構
Ctrl+F5刷新頁面,HTTP請求頭增長一些請求頭,Pragma:no-cache
,Cache-Control:no-cache
。
內容分發網絡(Content Delivery Network)。CDN=鏡像+緩存+總體負載均衡。
CDN以緩存網站中的靜態數據爲主。
用戶從主站服務器請求到動態內容後,再從CDN上下載這些靜態數據,從而加速網頁數據內容的下載速度。
步驟:
訪問靜態文件,先向Local DNS服務器發起請求,通過迭代到達域名註冊服務器解析,
公司DNS把請求從新CNAME解析到另外的一個域名,這個域名指向CDN的DNS負載均衡服務器,由這個GTM分配用戶距離最近的CDN節點。
有了DNS的解析結果,用戶就能夠去這個CDN節點訪問這個靜態文件了。
若是在這個CDN節點中,所請求的文件不存在,會再回源站獲取文件,返回給用戶。
負載均衡:
負載均衡對工做任務進行平衡、分攤到多個操做單元上執行。
一般有三種負載均衡架構:鏈路負載均衡、集羣負載均衡、操做系統負載均衡。
鏈路負載均衡:由DNS解析成不一樣的IP。
集羣負載均衡:分爲硬件負載均衡和軟件負載均衡。
硬件負載均衡:價格貴。
軟件負載均衡:使用最廣泛的一種負載方式。缺點是一次訪問要通過屢次代理服務器,會增長網絡延時。
操做系統負載均衡:利用操做系統級別的軟中斷和硬件中斷來達到負載均衡。
CDN動態加速:
原理:在CDN的DNS解析中經過動態的鏈路探測來尋找回源最好的一條路徑,經過DNS的調度將全部請求調度到選定的路徑上回源,從而加速用戶訪問的效率。
Java的I/O操做在包java.io下,大概能夠分紅四組:
基於字節操做的I/O接口:InputStream和OutputStream。
基於字符操做的I/O接口:Writer和Reader。
基於磁盤操做的I/O接口:File。
基於網絡操做的I/O接口:Socket。
前兩組主要是傳輸數據的數據格式,後兩組主要是傳輸數據的方式。(Socket類不在java.io包)
不論是磁盤仍是網絡傳輸,最小的存儲單元都是字節,不是字符。僅是爲了操做方便提供一個直接寫字符、讀字符的I/O接口。
字節與字符的轉換接口:
數據持久化或網絡傳輸都是以字節進行的,因此必需要有從字符到字節或從字節到字符的轉化。
InputStreamReader類是從字節到字符的轉化橋樑
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "GBK");
操做系統爲了保護系統自己的運行安全,將內核程序運行使用的內存空間和用戶程序運行的內存空間進行隔離。
這雖然保證了內核程序運行的安全性,可是也必然存在 數據可能須要從內核空間向用戶空間複製的問題 。
操做系統爲了加速I/O訪問,在內核程序的內存空間使用緩存機制 。
標準訪問文件的方式:
讀取:當應用程序調用read()接口時,操做系統檢查在內核的高速緩存中有沒有須要數據,若是已經緩存了,那麼直接返回,沒有就從磁盤中讀取,並緩存在操做系統的緩存中。
寫入:應用程序調用write()接口將數據從用戶地址空間複製到內核地址空間的緩存中。何時寫入到磁盤由操做系統決定,除非顯示調用sync同步命令。
直接I/O的方式:
所謂直接I/O的方式就是應用程序直接訪問磁盤數據,而不通過操做系統內核數據緩衝區。目的是 減小一次從內核緩衝區到用戶程序緩存的數據複製。 如數據庫管理系統。
缺點:若是訪問的數據不在應用程序緩存中,那麼每次數據都會直接從磁盤進行加載,這種直接加載會 很是緩慢 。
一般直接I/O與異步I/O結合使用,會獲得較好性能。
同步訪問文件的方式:
數據的讀取和寫入都是同步操做,與標準訪問文件的不一樣是: 只有當數據被成功寫到磁盤時才返回給應用程序成功的標誌。
性能比較差,在一些對安全性要求較高的場景中使用。
異步訪問文件的模式:
當訪問數據的線程發出請求以後,線程會接着去處理其餘事情,而不是阻塞等待,當請求的數據返回後繼續處理下面的操做。
能夠明顯地提升應用程序的效率,但不會改變訪問文件的效率。
內存映射的方式:
操做系統將內存中的某一塊區域與磁盤中的文件關聯起來,當要訪問內存中的一段數據時,轉換爲訪問文件的某一段數據。
減小數據從內核空間緩存到用戶空間緩存的數據複製操做,由於 這兩個空間的數據時共享的 。
Java序列化技術:
Java序列化:將一個對象轉化成一串二進制表示的字節數組,經過保存或轉移這些字節數據來達到持久化的目的。
須要持久化,對象必須實現java.io.Serializable接口。
反序列化,則是將這個字節數組再從新構形成對象。
下面是對一些複雜的對象狀況的總結:
當父類繼承Serializable接口時,全部子類都 能夠 被序列化。
子類實現Serializable接口,父類沒有,父類中的屬性 不能 序列化(不報錯,數據會丟失),可是在子類中屬性仍能正確序列化。
若是序列化的屬性是對象,則這個對象也必須實現Serializable接口,不然會報錯。
在反序列化時,若是對象的屬性有修改或刪除,則修改的部分屬性會丟失,但不會報錯。
在反序列化時,若是serialVersionUID被修改,則反序列化時會失敗。
將一份數據從一個地方正確地傳輸到另外一個地方所需的時間稱爲 響應時間 ,影響因素:
網絡帶寬
傳輸距離
TCP擁塞控制
創建通訊鏈路:
客戶端:
建立一個Socket實例
爲這個Socket實例分配沒有被使用的本地端口號
建立一個包含本地地址、遠程地址和端口號的套接字數據結構(這個結構保存在系統中直到這個鏈接關閉)
TCP三次握手,完成後,SOcket實例對象建立完成。
服務端:
建立一個ServerSocket 實例,只要端口號沒有被佔用,就會完成。
同時,爲ServerSocket實例建立一個底層數據結構,一般監聽全部地址。
以後當調用accept()方法時,進入阻塞狀態,等待客戶端的請求。
當一個新的請求到來時,將爲這個鏈接建立一個新的套接字數據結構。
這個新建立的數據結構將會關聯到ServerSocket實例的一個未完成的鏈接數據結構列表中。
注意,這時的服務端的與之對應的Socket實例並無完成建立,而要等到與客戶端的3次握手完成後,這個服務端的Socket實例纔會返回,並將這個Socket實例對應的數據結構從未完成列表中移到已完成列表。
數據傳輸:
數據的讀入和讀取都是經過緩存區完成的。
BIO帶來挑戰:
BIO即阻塞I/O,不論是磁盤I/O仍是網絡I/O,數據在寫入OutputStream或從InputStream讀取時都有可能會阻塞,一旦有阻塞,線程將會失去CPU的使用權,這在 當前的大規模訪問量和有幸能要求的狀況下是不能被接受的 。
網絡I/O的一些解決辦法:
一個客戶端對應一個處理線程,出現阻塞時只是一個線程阻塞而不會影響其餘線程工做。
採用線程池來減小線程的建立和回收的成本。
但一些場景沒法解決:
一些須要大量HTTP長鏈接的狀況,如淘寶的Web旺旺
想給某些客戶端更高的服務優先級時,很難經過設計線程的優先級來完成。
每一個客戶端的請求在服務端可能須要訪問一些競爭資源,這些客戶端在不一樣線程,須要同步。
NIO工做機制:
Selector能夠同時監聽一組通訊信道(Channel)上的I/O狀態,前提是這個Selector已經註冊到這些通訊信道中。
Selector能夠調用select()方法檢查已經註冊的通訊信道上I/O是否已經準備好,若是沒有至少一個信道I/O狀態有變化,那麼select()方法會阻塞等待或在超時時間後返回0;
若是有多個信道有數據,那麼將會把這些數據分配到對應的數據Buffer中。
有一個線程來處理全部鏈接的數據交互,每一個鏈接的數據交互都不是阻塞方式,全部能夠同時處理大量的鏈接請求。
Buffer:
Buffer能夠理解爲一組基本數據類型的元素列表,它經過幾個變量來保存這個數據的當前位置狀態,也就是4個索引。
經過Channel獲取的I/O數據首先要通過操做系統的Socket緩衝區,在將數據複製到Buffer中,這個操做系統緩衝區就是底層的TCP所關聯的RecvQ或SendQ隊列。
從操做系統緩衝區到用戶緩衝區複製數據比較耗性能,Buffer提供另一種 直接操做操做系統緩衝區的方式 , 即ByteBuffer.allocateDirector(size),這個方法返回的DirectByteBuffer就是與底層存儲空間關聯的緩衝區,它經過Native代碼操做費JVM堆的內存空間。
NIO的數據訪問方式:
NIO提供了比傳統的文件訪問方式更好的方法:一個是FileChannel.transferTo、FileChannel.transferFrom;另外一個是FileChannel.map
FileChannel.transferXXX能夠減小數據從內核到用戶空間的複製,數據直接在內核空間中移動。
FileChannel.map將文件按照必定大小塊映射爲內存區域,當程序訪問這個內存區域時將直接操做這個文件數據,這個方式 省去了數據從內核空間向用戶空間複製的損耗。 適合大文件的只讀性操做,如大文件的MD5校驗。
提升I/O性能:
增長緩存,減小磁盤訪問次數。
優化磁盤的管理系統設計最優的磁盤方式策略,以及磁盤的尋址方式。底層操做系統層面
設計合理的磁盤存儲數據塊,以及訪問這些數據庫的策略。應用層面。
應用合理的RAID策略提高磁盤I/O。
減小網絡交互的次數:在網絡交互的兩端設置緩存;合併訪問請求。
減小網絡傳輸數據量的大小:將數據壓縮後再傳輸;設計簡單的協議,儘可能經過讀取協議頭來獲取有用的價值信息。
儘可能減小編碼:儘可能直接以字節形式發送,也就是儘可能提早將字符轉化爲字節,或減小字符到字節的轉化過程。
把一個類的接口變換成客戶端所能接受的另外一種接口,從而使兩個接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做。
Java的I/O類庫中有許多這樣的需求,如將字符串數據轉變成字節數據保存到文件中,將字節數據轉變成流數據等。
以InputStreamReader和OutputStreamWriter類爲例。InputStreamReader和OutputStreamWriter類分別繼承了Reader和Writer接口,可是要建立它們的對象必須在構造函數中傳入一個InputStream和OutputStream的實例。
InputStreamReader和OutputStreamWriter的做用也就是將InputStream和OutputStream適配到Reader和Writer。
InputStream類就是以抽象組件存在的;
而FileInputStream就是具體組件,它實現了抽象組件的全部接口;
FileterInputStream類無疑就是裝飾角色,它實現了InputStream類的全部接口,而且持有InputStream的對象實例的引用;
BufferedInputStream是具體的裝飾器實現者。這個裝飾器類的做用就是使用InputStream讀取的數據保存在內存中,而提升讀取的性能。
裝飾器與適配器模式都有一個別名就是 包裝模式(Wrapper) 。
適配器模式的意義是要將一個接口轉變成另外一個接口,目的是 經過改變接口來達到重複使用的目的 ;
裝飾器模式不是要改變被裝飾對象的接口,而是偏偏要保持原有的接口,可是 加強原有對象的功能或者改變原有對象的處理方法而提高性能 。