50%運維都迷糊的Socket基礎知識!
一起來看看一個熱愛探索的運維小白如何一步步掌握Socket相關的知識。
分享嘉賓
趙舜東 DevOps學院創始人
花名:“趙班長”,曾在武警某部負責指揮自動化的架構和運維工作,2008年退役後一直從事網際網路運維工作,歷任運維工程師、運維經理、運維架構師、運維總監。UnixHot運維社群創始人、中國SaltStack使用者組發起人、《SaltStack入門與實踐》作者、《運維知識體系》和《快取知識體系》作者、Exin DevOps Master授權講師、GOPS金牌講師。
什麼是Socket?
大家都用電腦上網,當我們訪問運維社群的時候,我們的電腦和運維社群的伺服器就會建立一條Socket,我們稱之為網路套接字。那麼既然是網路通訊,肯定是成對的。至少有一個客戶端和服務端,我們稱之為套接字對。
一個套接字對(socket pair)是一個定義該網路連線的兩個端點的五元組,包括:
源IP地址
源埠
目的IP地址
目的埠
型別:TCP or UDP
那麼針對於HTTP請求來說,我們知道底層是建立了一條TCP的Socket,那麼TCP的套接字對就是一個四元組,因為協議已經確定了:
1.源IP地址、2.源埠、3.目的IP地址、4.目的埠。
客戶端的隨機埠
為了更直觀的認識這個TCP Socket,我們做一個小實驗,我這裡準備了兩臺伺服器:
角色 | IP地址 | 埠 |
客戶端 | 192.168.56.11 | 隨機 |
服務端 | 192.168.56.12 | 9999 |
當客戶端192.168.56.11訪問192.168.56.12的9999埠的時候,那麼會選擇一個隨機埠來進行通訊,那麼這個隨機埠,到底是從什麼範圍隨機出來了呢,埠總有一個範圍不可能無窮多的。
那麼對於TCP套接字來說客戶端的一個IP地址,到底能有多少個埠呢?由於TCP協議頭部使用16位來儲存埠號,所以埠的個數最多為65536個,2^16=65536。
沒錯,是65536個。但是為什麼我們經常看到網上說可用埠最大65535個呢,也就是2^16-1個。因為埠號是從0開始算的,0-65535那就是65536個。而0埠是保留埠,無論是TCP還是UDP都是不用使用的,當然這個是標準,那到底能不能監聽埠0呢,下面我用一個python指令碼,監聽本地的埠0來試試。
[root@test ~]# catbind_port_zero.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''本指令碼監聽本地的127.0.0.1的埠0,
探索埠0的奧秘'''
import socket
def bind_port_zero():
ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ss.bind(('127.0.0.0', 0))
addr, port = ss.getsockname()
ss.close()
print(addr, port)
bind_port_zero()
執行指令碼,看看到底能不能正常監聽:
[root@test ~]# pythonbind_port_zero.py
('127.0.0.0', 53692)
[root@test ~]# pythonbind_port_zero.py
('127.0.0.0', 59444)
可以發現,可以正常監聽,但是呢並沒有監聽到埠0。實驗證明在Linux下如果在bind的時候指定埠0,那麼由系統隨機選擇一個可用埠來bind。
好的,我們現在知道了埠的範圍0-65535,那麼作為客戶端訪問其它服務端的時候,能用多少呢?並不是這個範圍都可以用的。那麼在Linux下我們可以這麼獲取本地的隨機埠範圍:
[root@test ~]# cat/proc/sys/net/ipv4/ip_local_port_range
32768 61000
不要驚訝答案確實是32768到61000,現在你應該明白,別人說的發10萬併發進行壓力測試代表什麼意思了吧。至少預設情況下是無法實現的,讀完這句話,是否有啟發呢?並不是不能實現哦。
瓶頸真的只有隨機埠範圍嗎?
剛才我們也看了,我們訪問其它伺服器,作為客戶端,我們要使用一個隨機埠,32768-61000,貌似也不少,當然你還可以修改它,擴大隨機埠範圍。例如我們使用Nginx做反向代理負載均衡的時候,使用者端和Nginx建立Socket進行通訊,Nginx還需要和後端真實伺服器也建立Socket進行通訊,在高併發的場景下,這個隨機埠肯定是一個瓶頸。但是真的只有隨機埠範圍是瓶頸嗎?下面我們使用ab命令來對百度進行一次壓力測試。
ab是Apache的效能測試工具,可以模擬併發進行Web效能測試。在CenotOS下,你可以這樣來安裝:
[root@test ~]# yuminstall -y httpd-devel
按照我們們之前的認識,隨機埠61000-32768=28232,那麼我實驗的機器是一臺剛安裝的系統,沒有什麼網路傳輸,即便有,我們建立2萬個套接字對應該是沒問題吧。事實真的如此嗎?我們用實驗來證明:
我們模擬傳送2萬個請求,2000的併發來測試百度:
[root@test ~]#ab -n 10000 -c 2000
This isApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996Adam Twiss, Zeus Technology Ltd,
Licensed to TheApache Software Foundation,
Benchmarking (be patient)
socket: Toomany open files (24)
這不可能,為什麼報錯了?不要擔心,報錯我們很容易看懂了socket: Too many open files (24)
,不能開啟太多的檔案。我們使用ulimit來看看系統資源限制。
[root@test ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 31219
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
(省略部分輸出)
沒錯,預設情況下,當前使用者能夠開啟的檔案數量最大是1024,但是這個和我們使用ab測試有什麼關係呢?ab測試建立的不是socket嗎?如果你不理解,那就要回歸本質,想想我們剛剛學習Linux的時候,經常聽到的一句Linux的思想“一切皆檔案”!誰說socket不是一個檔案呢?
我相信你知道怎麼做了,你可以使用ulimit –n來修改當前使用者、當前session的限制,也可以修改配置檔案/etc/security/limits.conf來徹底解決這個問題,這也是進行系統效能調優的必備基礎。
建立一條TCP Socket
好的,剛才只是一個小插曲,我們繼續探索TCP Socket,光說不練是個棒槌。我們來建立一個套接字對看看:
服務端:
首先,我們在192.168.56.12上使用nc命令,來監聽9999埠。
[root@192.168.56.12 ~]#nc -l -4 -p 9999 -k
[root@192.168.56.12 ~]#netstat -ntlp | grep 9999
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 26789/n
客戶端:
在客戶端,同樣使用nc命令來連線到服務端的9999埠。
[root@192.168.56.11 ~]#nc 192.168.56.12 9999
好的,現在你可以在客戶端上輸入任何的語言和服務端愉快的聊天了?不過這不是重點。
檢視Socket
我們先來看看客戶端的TCPSocket。
[root@192.168.56.11 ~]#netstat -na | grep 9999
tcp 0 0 192.168.56.11:11525 192.168.56.12:9999 ESTABLISHED
服務端的TCP Socket
[root@192.168.56.12 ~]#netstat -na | grep 9999
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN
tcp 0 0 192.168.56.12:9999 192.168.56.11:11525 ESTABLISHED
我相信你已經真正理解了Socket,剩下的就是無盡的想象,還記得TIME_WAIT嗎?如果有大量的TIME_WAIT存在,那麼這個套接字對是不釋放的,不釋放也就代表著佔用一個,資源嘛,佔用一個就少一個。怎麼最佳化呢?且聽下回分解!
不過,如果你真的理解了Socket的概念,你已經有了一個終極解決方案。既然一個TCP Socket是一個四元組,那如果我這臺機器有多個IP地址呢?哈哈,這是一句畫龍點睛之語,你懂的!
使用偽終端傳送資料
最後,留一個小彩蛋,除了使用nc進行資料傳送之外,其實Linux還提供了一種稱之為偽裝置的方式,讓我們來體驗下/dev下面的tcp偽裝置。/dev下面提供了很多的偽裝置,比如tcp就可以用來直接進行遠端埠的訪問。
[root@192.168.56.11 ~]# echo"886" > /dev/tcp/192.168.56.12/9999
趕緊看看服務端有沒有收到886。
原文連結:https://mp.weixin.qq.com/s/vaURXrvafNBzBxmEiuaGOQ
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556419/viewspace-2218933/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Heartbeat基礎知識-運維小結運維
- Keepalived基礎知識-運維小結運維
- 全面的MySQL基礎運維知識點(一)MySql運維
- 全面的MySQL基礎運維知識點(三)MySql運維
- 全面的MySQL基礎運維知識點(二)MySql運維
- python基礎知識小結-運維筆記Python運維筆記
- 智慧運維基礎-運維知識庫之ETL運維
- Redis日常運維-基礎認識Redis運維
- Linux下Apache(HTTP)基礎知識梳理-運維筆記LinuxApacheHTTP運維筆記
- java培訓基礎知識都學哪些Java
- 新媒體運營都需要做哪些工作?新媒體運營基礎知識
- 0基礎入門Linux 運維,應該先掌握哪些知識?Linux運維
- Linux運維就業前景如何?linux基礎知識學習Linux運維就業
- Linux運維都需要做什麼?0基礎Linux運維學習Linux運維
- Python基礎知識思維導圖Python
- 軟體測試都需要學哪些基礎知識
- IT知識課堂:50道網路基礎知識普及
- 遊戲基礎知識——“運輸單位”的設計遊戲
- 基礎知識
- LUA的基礎知識
- C++基礎知識篇:C++ 運算子C++
- HPC高效能運算知識: 基礎科普
- cd命令有哪些相關知識?學linux運維命令基礎入門Linux運維
- 思維導圖來學習Javascript基礎知識JavaScript
- AI 基礎知識AI
- Webpack 基礎知識Web
- Dart基礎知識Dart
- RabbitMQ基礎知識MQ
- webpack基礎知識Web
- javascript基礎知識JavaScript
- ThinkPHP基礎知識PHP
- Laravel基礎知識Laravel
- Redis基礎知識Redis
- Docker基礎知識Docker
- 程式基礎知識
- Envoy基礎知識
- DockerFile基礎知識Docker
- Nginx基礎知識Nginx