微服務
- 對服務進行集中管理調控。高併發互聯網設計原則 —— 高負載
、高存儲
、高容錯
也稱 AKF拆分原則
X軸
:服務水平擴展
服務具備可複製性 ,水平分割
,解決一些併發問題
(水平拓展,比性能的垂直提高成本低-摩爾定律)
Y軸
:服務間各司其職
弱耦合,垂直分割
,物理節點物盡其用
(泳道設計)
Z軸
:對x,y
打包,進行物理隔離。
X中有Y,Y中有X
x和y互相轉換
y中有x:對y軸作垂直拆分,層與層間獨立,爲了保證每一層的可用性,每一層作水平分割java
高併發的場景問題 —— 優化思路
如何讓服務支持x軸的水平擴展,利用分佈式的思惟解決高併發;如何作y中的垂直拆分,是應用之間儘量隔離,弱化服務件耦合度;結合兩個維度來解決高併發的場景問題。(Socket + IO)程序員
網絡編程:經過編碼的方式,讓不一樣計算機之間相互通訊(數據的傳遞)。web
兩個核心問題:
尋址問題:ip地址+port端口號
協議問題:數據傳輸格式面試
OSI 七層模型(標準,瞭解就好)
編程
OSI 五層模型(七層的轉變)tomcat
協議
http協議:應用層協議,超文本傳輸協議,不一樣計算機間傳輸文本的協議(字符串),底層tcp協議
tcp/ip協議:傳輸層協議安全
tcp協議:傳輸安全,效率低
udp協議:傳輸不安全,效率高服務器
BIO 同步阻塞IO
傳統IO 或者 Blocking IO
特色:面向流Input | Output
【每一個線程只能處理一個channel(同步的,該線程和該channel綁定)。
線程發起IO請求,無論內核是否準備好IO操做,從發起請求起,線程一直阻塞,直到操做完成。】websocket
NIO 同步非阻塞IO
New IO 或者Non Blocking IO
特色:面向緩衝區Buffer(基於通道)
【每一個線程能夠處理多個channel(異步)。
線程發起IO請求,當即返回;內核在作好IO操做的準備以後,經過調用註冊的回調函數通知線程作IO操做,線程開始阻塞,直到操做完成 。】網絡
AIO(Async Non Blocking IO) 異步非阻塞
【線程發起IO請求,當即返回;內存作好IO操做的準備以後,作IO操做,直到操做完成或者失敗,經過調用註冊的回調函數通知線程作IO操做完成或者失敗 。】
BIO
方向—— 輸入、輸出流(InputStream | OutputStream)
類型—— 字節、字符流(Reader | Writer)
功能—— 節點、過濾流(BufferedInputStream | BufferedOutputStream )
BIO網絡編程
服務端:ServerSocket 【接收和響應,請求轉發
- ServerSocket
、 請求響應
- Socket
】
①初始化服務器ServerSocket,綁定監聽端口
②等待客戶端鏈接serverSocket.accept();
③處理請求/響應sockect.getInputStream(); / socket.getOutputStream();
④關閉資源
客戶端:Socket 【發送和接收,發送請求|接收響應:Socket
】
①初始化客戶端Socket,綁定服務器IP/端口
②發起請求/獲取響應socket.getOutputStream(); / socket.getInputStream();
③關閉資源
public class BIOBootstrapServer { public static void main(String[] args) throws IOException { server(); } public static void server() throws IOException { //建立服務轉發ServerSocket ServerSocket ss = new ServerSocket(); ss.bind(new InetSocketAddress(9999)); //server能夠省略好hostname ExecutorService threadPool= Executors.newFixedThreadPool(10); while(true) { //等待請求到來,轉發產生Socket(系統內部資源) final Socket socket = ss.accept(); //沒有請求就等待,阻塞 //final 匿名內部類使用局部變量要final修飾 threadPool.submit(new Runnable() { public void run() { try { //利用IO,讀取用戶請求 InputStream req = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(req); BufferedReader br = new BufferedReader(isr); String line = null; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { sb.append(line); } System.out.println("服務器收到:" + sb.toString()); //給出用戶響應 OutputStream res = socket.getOutputStream(); PrintWriter pw = new PrintWriter(res); pw.println(new Date().toLocaleString()); pw.flush(); socket.shutdownOutput(); //告知客戶端寫結束 //關閉系統資源 socket.close(); } catch (Exception e) { e.printStackTrace(); } } }); } } }
public class BIOBootstrapClient { public static void main(String[] args) throws IOException { send("這是一條來自client 的 message!"); } public static void send(String msg) throws IOException { //建立Socket對象 Socket s = new Socket(); s.connect(new InetSocketAddress("127.0.0.1",9999)); //因此幾乎給ip和端口的,底層走的就是socket //發送請求 OutputStream req = s.getOutputStream(); PrintWriter pw=new PrintWriter(req); pw.println(msg); pw.flush(); s.shutdownOutput();//告知服務端寫結束 //接收響應 InputStream res = s.getInputStream(); InputStreamReader isr = new InputStreamReader(res); BufferedReader br = new BufferedReader(isr); String line=null; StringBuilder sb=new StringBuilder(); while((line=br.readLine())!=null){ sb.append(line); } System.out.println("客戶端收到:"+sb.toString()); //關閉資源 s.close(); } }
思考下,BIO模型的缺點?
accept轉發產生socket資源,一次請求轉發等待請求響應的過程有阻塞。main線程做accept請求轉發、子線程做socket讀寫IO處理。
套接字
完成的。套接字,是支持TCP/IP的網絡通訊的基本操做單元,能夠看作是不一樣主機之間的進程進行雙向通訊的端點,簡單的說就是通訊的兩方的一種約定,用套接字中的相關函數來完成通訊過程。
簡單的舉例說明下:Socket = Ip address + TCP/UDP + port。
每一個socket表明一個系統的隨機端口,用來在服務和客戶端之間創建鏈接。
BIO編程詬病 :多線程模型解決服務端併發,可是沒法判斷當前處理的IO狀態是否就緒,此時就會致使線程在作無畏等待,致使系統資源利用率不高。 先開線程 -> 在線程等待IO就緒->處理IO->線程資源釋放
//可讀的FileChannel FileChannel fr=new FileInputStream("xxx路徑").getChannel(); //可寫的FileChannel FileChannel fw=new FileOutputStream("xxx路徑").getChannel();
文件操做
//讀文件件 fr.read(緩衝區) //寫文件 fw.write(緩衝區)
flip:pos賦值給limit,post歸0
clear:恢復變量爲初始狀態
public class FileCopyDemo { public static void main(String[] args) throws IOException { //建立讀通道 磁盤讀入數據 到 ByteBuffer FileInputStream in = new FileInputStream("C:\\Users\\Administrator\\Desktop\\123.txt"); FileChannel fcr = in.getChannel(); //fileChannelRead //建立寫通道 將 ByteBuffer 數據寫入磁盤 FileOutputStream out = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\321.txt"); FileChannel fcw= out.getChannel(); //fileChannelWrite //建立ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(new byte[1024]);//.allocate()也能夠 while (true){ buffer.clear(); int n = fcr.read(buffer); if(n==-1) break; buffer.flip(); fcw.write(buffer); } //關閉資源 fcr.close(); fcw.close(); } }
public class NIOBootstrapServer_Fake { public static void main(String[] args) throws IOException { server(); } public static void server() throws IOException { //建立服務轉發ServerSocket ServerSocketChannel ss = ServerSocketChannel.open(); ss.bind(new InetSocketAddress(9999)); ExecutorService threadPool= Executors.newFixedThreadPool(10); while(true) { //等待請求到來,轉發產生Socket(系統內部資源) final SocketChannel socket = ss.accept();// 阻塞 threadPool.submit(new Runnable() { public void run() { try{ //讀取客戶端響應 ByteBuffer buffer=ByteBuffer.allocate(1024); ByteArrayOutputStream baos=new ByteArrayOutputStream();//相似stringbuilder,用來暫存用 while (true){ buffer.clear(); int n = socket.read(buffer); if(n==-1) break; buffer.flip(); baos.write(buffer.array(),0,n); } System.out.println("服務器收到:"+new String(baos.toByteArray())); //給出客戶端響應 ByteBuffer respBuffer = ByteBuffer.wrap((new Date().toLocaleString()).getBytes()); socket.write(respBuffer); socket.shutdownOutput();//告知客戶端寫結束 //關閉系統資源 socket.close(); }catch (Exception e){ } } }); } } }
NIO核心思想,將網絡編程中全部操做(轉發,讀請求,寫響應)封裝成事件Event,以後用事件形式通知程序進行計算,事件發生則通知程序,這樣處理的IO都是就緒的IO,保證計算資源的充分利用。這時候,引入通道選擇器
的概念。 咱們須要把通道註冊到通道選擇器的註冊列表中,由通道選擇器維護註冊列表;一旦咱們所關注的事件發生了,他會把關注的事件封裝到事件處理列表當中;爲了防止處理空或無效IO,每一個事件處理結束後,要從列表中移除;移除不表明取消註冊。只有兩種可能才取消註冊,一種是通道關閉,一種是主動註銷。