今天繼續分享 Python 相關的面試題,你準備好了嘛!
網路程式設計篇
1. 簡述 OSI 七層協議
是網路傳輸協議,人為的把網路傳輸的不同階段劃分成不同的層次。
七層劃分為:應用層、表示層、會話層、傳輸層、網路層、資料鏈路層、物理層。
五層劃分為:應用層、傳輸層、網路層、資料鏈路層、物理層。
物理層:網線,電纜等物理裝置 資料鏈路層:Mac 地址 網路層:IP 地址 傳輸層:TCP,UDP 協議 應用層:FTP 協議,Email,WWW 等
2. 三次握手、四次揮手的流程
都發生在傳輸層
三次握手:
TCP 協議是主機對主機層的傳輸控制協議,提供可靠的連線服務,採用三次握手確認建立一個連線。
TCP 標誌位(位碼),有6種標示:SYN(synchronous建立聯機) ACK(acknowledgement 確認) PSH(push傳送) FIN(finish結束) RST(reset重置) URG(urgent緊急)
Sequence number(順序號碼) Acknowledge number(確認號碼)
第一次握手:主機 A 傳送位碼為 syn=1,隨機產生 seq number=1234567 的資料包到伺服器,並進入 SYN_SEND 狀態,主機 B 由 SYN=1 知道,A 要求建立聯機;
第二次握手:主機 B 收到請求後要確認聯機資訊,向 A 傳送 ack number=(主機 A 的 seq+1),syn=1,ack=1,隨機產生 seq=7654321 的包,並進入 SYN_RECV 狀態;
第三次握手:主機 A 收到後檢查 ack number 是否正確,即第一次傳送的 seq number+1,以及位碼 ack 是否為 1,若正確,主機 A 會再傳送 ack number=(主機 B 的 seq+1),ack=1,主機 B 收到後確認 seq 值與 ack=1 則連線建立成功,兩個主機均進入 ESTABLISHED 狀態。
以上完成三次握手,主機 A 與主機 B 開始傳送資料。
四次揮手:
因為 TCP 連線是全雙工的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成它的資料傳送任務後就能傳送一個 FIN 來終止這個方向的連線。收到一個 FIN 只意味著這一方向上沒有資料流動,一個 TCP 連線在收到一個 FIN 後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
- 伺服器 A 傳送一個 FIN,用來關閉 A 到伺服器 B 的資料傳送。
- 伺服器 B 收到這個 FIN,它發回一個 ACK,確認序號為收到的序號加1。和 SYN 一樣,一個 FIN 將佔用一個序號。
- 伺服器 B 關閉與伺服器 A 的連線,傳送一個 FIN 給伺服器 A。
- 伺服器 A 發回 ACK 報文確認,並將確認序號設定為收到序號加1。
3. 什麼是C/S和B/S架構
B/S 又稱為瀏覽器/伺服器模式。比如各種網站,jupyter notebook 等。
優點:零安裝,維護簡單,共享性好。
缺點:安全性較差,個性化不足。
C/S 又稱為客戶端/伺服器模式。比如微信客戶端,Oracle 客戶端等。
優點:安全性好,資料傳輸較快,穩定。
缺點:對 PC 機作業系統等有要求,當客戶端較多時,伺服器端負載較大。
4. TCP和UDP的區別
TCP 和 UDP 都是 OSI 模型中運輸層的協議。TCP 提供可靠的通訊傳輸,而 UDP 則常被用於廣播和細節控制交給應用的通訊傳輸。
UDP 不提供複雜的控制機制,利用 IP 提供面向無連線的通訊服務。
TCP 充分實現了資料傳輸時各種控制功能,可以進行丟包的重發控制,還可以對次序亂掉的分包進行順序控制。
TCP 應用:FTP 傳輸,點對點簡訊等。
UDP 應用:媒體流等。
5. 區域網和廣域網
廣域網(WAN,Wide Area Network)也稱遠端網(long haul network )。通常跨接很大的物理範圍,所覆蓋的範圍從幾十公里到幾千公里,它能連線多個城市或國家,或橫跨幾個洲並能提供遠距離通訊,形成國際性的遠端網路。
區域網(Local Area Network,LAN)是指在某一區域內由多臺計算機互聯成的計算機組。一般是方圓幾千米以內。區域網可以實現檔案管理、應用軟體共享、印表機共享、工作組內的日程安排、電子郵件和傳真通訊服務等功能。區域網是封閉型的,可以由辦公室內的兩臺計算機組成,也可以由一個公司內的上千臺計算機組成。
6. arp 協議
ARP(Address Resolution Protocol)即地址解析協議, 用於實現從 IP 地址到 MAC 地址的對映,即詢問目標 IP 對應的 MAC 地址。
7. 什麼是 socket?簡述基於 TCP 協議的套接字通訊流程。
socket 是對 TCP/IP 協議的封裝,它的出現只是使得程式設計師更方便地使用 TCP/IP 協議棧而已。socket 本身並不是協議,它是應用層與 TCP/IP 協議族通訊的中間軟體抽象層,是一組呼叫介面(TCP/IP網路的API函式)。
“TCP/IP 只是一個協議棧,就像作業系統的執行機制一樣,必須要具體實現,同時還要提供對外的操作介面。 這個就像作業系統會提供標準的程式設計介面,比如win32程式設計介面一樣。TCP/IP 也要提供可供程式設計師做網路開發所用的介面,這就是 Socket 程式設計介面。”
Server:
import socket
import threading
def tcplink(sock, addr):
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 監聽埠:
s.bind(('127.0.0.1', 9999))
s.listen(5)
print('Waiting for connection...')
while True:
# 接受一個新連線:
sock, addr = s.accept()
# 建立新執行緒來處理TCP連線:
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
複製程式碼
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連線:
s.connect(('127.0.0.1', 9999))
# 接收歡迎訊息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
# 傳送資料:
s.send(data)
print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()
複製程式碼
例子來源於廖雪峰的官網
8. 簡述 程式、執行緒、協程的區別以及應用場景
程式是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程式是系統進行資源分配和排程的一個獨立單位。每個程式都有自己的獨立記憶體空間,不同程式通過程式間通訊來通訊。
執行緒是程式的一個實體,是CPU排程和分派的基本單位,它是比程式更小的能獨立執行的基本單位。執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一組暫存器和棧),但是它可與同屬一個程式的其他的執行緒共享程式所擁有的全部資源。
協程是一種使用者態的輕量級執行緒,協程的排程完全由使用者控制。協程擁有自己的暫存器上下文和棧。
多程式:密集 CPU 任務,需要充分使用多核 CPU 資源(伺服器,大量的平行計算)的時候,用多程式。
缺陷:多個程式之間通訊成本高,切換開銷大。
多執行緒:密集 I/O 任務(網路 I/O,磁碟 I/O,資料庫 I/O)使用多執行緒合適。
缺陷:同一個時間切片只能執行一個執行緒,不能做到高並行,但是可以做到高併發。
協程:又稱微執行緒,在單執行緒上執行多個任務,用函式切換,開銷極小。不通過作業系統排程,沒有程式、執行緒的切換開銷。
缺陷:單執行緒執行,處理密集 CPU 和本地磁碟 IO 的時候,效能較低。處理網路 I/O 效能還是比較高。
多執行緒請求返回是無序的,哪個執行緒有資料返回就處理哪個執行緒,而協程返回的資料是有序的。
9. 如何使用執行緒池和程式池
池的功能是限制啟動的程式數或執行緒數。當併發的任務數遠遠超過了計算機的承受能力時,即無法一次性開啟過多的程式數或執行緒數時,就應該用池的概念將開啟的程式數或執行緒數限制在計算機可承受的範圍內。
多程式
from multiprocessing import Pool
import os
import time
import random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
def test_pool():
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
if __name__ == '__main__':
test_pool()
複製程式碼
output
Parent process 32432.
Waiting for all subprocesses done...
Run task 0 (15588)...
Run task 1 (32372)...
Run task 2 (12440)...
Run task 3 (18956)...
Task 2 runs 0.72 seconds.
Run task 4 (12440)...
Task 3 runs 0.82 seconds.
Task 1 runs 1.21 seconds.
Task 0 runs 3.00 seconds.
Task 4 runs 2.95 seconds.
All subprocesses done.
複製程式碼
apply_async(func[, args[, kwds]]) :使用非阻塞方式呼叫 func(並行執行,堵塞方式必須等待上一個程式退出才能執行下一個程式),args 為傳遞給 func 的引數列表,kwds 為傳遞給 func 的關鍵字引數列表; close():關閉 Pool,使其不再接受新的任務; terminate():不管任務是否完成,立即終止; join():主程式阻塞,等待子程式的退出, 必須在 close 或 terminate 之後使用;
也可以使用 concurrent.futures 模組提供的功能來實現
def test_future_process():
print('Parent process %s.' % os.getpid())
p = ProcessPoolExecutor(4)
for i in range(5):
p.submit(long_time_task, i)
p.shutdown(wait=True)
print('Finish')
if __name__ == '__main__':
# test_pool()
test_future_process()
複製程式碼
output
Parent process 29368.
Run task 0 (32148)...
Run task 1 (31552)...
Run task 2 (24012)...
Run task 3 (29408)...
Task 2 runs 0.52 seconds.
Run task 4 (24012)...
Task 3 runs 0.86 seconds.
Task 1 runs 1.81 seconds.
Task 0 runs 1.83 seconds.
Task 4 runs 1.69 seconds.
Finish
複製程式碼
多執行緒
def sayhello(a):
print("hello: " + a)
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (a, (end - start)))
def test_future_thread():
seed = ["a", "b", "c", "d"]
start = time.time()
with ThreadPoolExecutor(3) as executor:
for i in seed:
executor.submit(sayhello, i)
end = time.time()
print("Thread Run Time: " + str(end - start))
複製程式碼
output
hello: a
hello: b
hello: c
Task a runs 0.40 seconds.
hello: d
Task b runs 0.56 seconds.
Task d runs 1.70 seconds.
Task c runs 2.92 seconds.
Thread Run Time: 2.9195945262908936
複製程式碼
可以看出,由於是建立了限制為3的執行緒池,所以只有三個任務在同時執行。
10. 程式之間如何進行通訊
def write(q):
print("write(%s), 父程式為(%s)" % (os.getpid(), os.getppid()))
for i in "Python":
print("Put %s to Queue" % i)
q.put(i)
def read(q):
print("read(%s), 父程式為(%s)" % (os.getpid(), os.getppid()))
for i in range(q.qsize()):
print("read 從 Queue 獲取到訊息: %s" % q.get(True))
def test_commun():
print("(%s) start" % os.getpid())
q = Manager().Queue()
pw = Process(target=write, args=(q, ))
pr = Process(target=read, args=(q, ))
pw.start()
pr.start()
pw.join()
pr.terminate()
複製程式碼
output
(23544) start
write(29856), 父程式為(23544)
Put P to Queue
Put y to Queue
Put t to Queue
Put h to Queue
Put o to Queue
Put n to Queue
read(25016), 父程式為(23544)
read 從 Queue 獲取到訊息: P
read 從 Queue 獲取到訊息: y
read 從 Queue 獲取到訊息: t
read 從 Queue 獲取到訊息: h
read 從 Queue 獲取到訊息: o
read 從 Queue 獲取到訊息: n
複製程式碼
Python 的 multiprocessing 模組包裝了底層的機制,提供了 Queue、Pipes 等多種方式來交換資料。
11. 程式鎖和執行緒鎖
程式鎖:是為了控制同一作業系統中多個程式訪問一個共享資源,只是因為程式的獨立性,各個程式是無法控制其他程式對資源的訪問的,但是可以使用本地系統的訊號量控制。
訊號量(Semaphore),有時被稱為訊號燈,是在多執行緒環境下使用的一種設施,是可以用來保證兩個或多個關鍵程式碼段不被併發呼叫。
執行緒鎖:當多個執行緒幾乎同時修改一個共享資料的時候,需要進行同步控制,執行緒同步能夠保證多個執行緒安全的訪問競爭資源(全域性內容),最簡單的同步機制就是使用互斥鎖。
某個執行緒要更改共享資料時,先將其鎖定,此時資源的狀態為鎖定狀態,其他執行緒就能更改,直到該執行緒將資源狀態改為非鎖定狀態,也就是釋放資源,其他的執行緒才能再次鎖定資源。互斥鎖保證了每一次只有一個執行緒進入寫入操作。從而保證了多執行緒下資料的安全性。
12. 什麼是併發和並行
並行:多個 CPU 核心,不同的程式就分配給不同的 CPU 來執行。可以讓多個程式同時執行。
併發:單個 CPU 核心,在一個時間切片裡一次只能執行一個程式,如果需要執行多個程式,則序列執行。
13. threading.local 的作用
ThreadLocal 叫做執行緒本地變數,ThreadLocal 在每一個變數中都會建立一個副本,每個執行緒都可以訪問自己內部的副本變數,對其他執行緒時不可見的,修改之後也不會影響到其他執行緒。
14. 什麼是域名解析
域名解析是指將域名解析為 IP 地址。也有反向的“逆解析”,將 IP 通過 DNS 伺服器查詢到對應的域名地址。
DNS 是域名系統 (Domain Name System),域名系統為因特網上的主機分配域名地址和 IP 地址。使用者使用域名地址,該系統就會自動把域名地址轉為 IP 地址。
15. LVS 是什麼及作用
LVS 是 Linux Virtual Server 的簡寫,意即 Linux 虛擬伺服器,是一個虛擬的伺服器叢集系統,即負載均衡伺服器。
LVS 工作模式分為 NAT 模式、TUN 模式、以及 DR 模式。
16. Nginx 的作用
Nginx 主要功能:1、反向代理 2、負載均衡 3、HTTP 伺服器(包含動靜分離) 4、正向代理
正向代理:某些情況下,代理使用者去訪問伺服器,需要手動設定代理伺服器的 IP 和埠號。
反向代理:是用來代理伺服器的,代理要訪問的目標伺服器。代理伺服器接受請求,然後將請求轉發給內部網路的伺服器(叢集化),並將從伺服器上得到的結果返回給客戶端,此時代理伺服器對外就表現為一個伺服器。
負載均衡伺服器類似於 LVS HTTP 伺服器類似於 Tomcat 等。
17. keepalived 及 HAProxy
HAProxy 提供高可用性、負載均衡,以及基於 TCP 和 HTTP 的應用程式代理。
keepalived 是叢集管理中保證叢集高可用的一個服務軟體,其功能類似於 heartbeat,用來防止單點故障。
18. 什麼是 rpc
RPC 是指遠端過程呼叫,也就是說兩臺伺服器 A,B,一個應用部署在 A 伺服器上,想要呼叫 B 伺服器上應用提供的函式/方法,由於不在一個記憶體空間,不能直接呼叫,需要通過網路來表達呼叫的語義和傳達呼叫的資料。
19. 從瀏覽器輸入一個網址到展示網址頁面的過程
- 瀏覽器通過 DNS 伺服器查詢到域名對應的 IP 地址
- 瀏覽器給 IP 對應的 web 伺服器傳送 HTTP 請求
- web 伺服器接收到 HTTP 請求後,返回響應給瀏覽器
- 瀏覽器接收到響應後渲染頁面
20. 什麼是cdn
CDN 的全稱是 Content Delivery Network,即內容分發網路。CDN 是構建在網路之上的內容分發網路,依靠部署在各地的邊緣伺服器,通過中心平臺的負載均衡、內容分發、排程等功能模組,使使用者就近獲取所需內容,降低網路擁塞,提高使用者訪問響應速度和命中率。CDN 的關鍵技術主要有內容儲存和分發技術。
資料庫和框架篇
21. 列舉常見的資料庫
關係型資料庫:MySQL,Oracle,SQLServer,SQLite,DB2
非關係型資料庫:MongoDB,Redis,HBase,Neo4j
22. 資料庫設計三大正規化
建立科學的,規範的的資料庫是需要滿足一些規範的,以此來優化資料資料儲存方式,在關係型資料庫中這些規範就可以稱為正規化。
第一正規化:當關系模式 R 的所有屬性都不能在分解為更基本的資料單位時,稱 R 是滿足第一正規化的,簡記為 1NF。
關係模式R的所有屬性不能再分解
第二正規化:如果關係模式 R 滿足第一正規化,並且 R 的所有非主屬性都完全依賴於 R 的每一個候選關鍵屬性,稱 R 滿足第二正規化,簡記為 2NF。
非主屬性都要依賴於每一個關鍵屬性
三正規化:設 R 是一個滿足第一正規化條件的關係模式,X 是 R 的任意屬性集,如果 X 非傳遞依賴於 R 的任意一個候選關鍵字,稱 R 滿足第三正規化,簡記為 3NF。
資料不能存在傳遞關係,即每個屬性都跟主鍵有直接關係而不是間接關係
23. 什麼是資料庫事務
事務(Transaction)是併發控制的基本單位。所謂的事務,它是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。
在關聯式資料庫中,一個事務可以是一條 SQL 語句、一組 SQL 語句或整個程式。
四個屬性:原子性,一致性,隔離性和永續性。
24. MySQL 索引種類
MySQL 目前主要有以下幾種索引型別:
- 普通索引
- 唯一索引
- 主鍵索引
- 組合索引
- 全文索引
25. 資料庫設計中一對多和多對多的應用場景
一對一關係示例: 一個學生對應一個學生檔案材料,或者每個人都有唯一的身份證編號。
一對多關係示例: 一個學生只屬於一個班,但是一個班級有多名學生。
多對多關係示例: 一個學生可以選擇多門課,一門課也有多名學生。
26. 簡述觸發器、函式、檢視、儲存過程
觸發器:觸發器是一個特殊的儲存過程,它是資料庫在 insert、update、delete 的時候自動執行的程式碼塊。
函式:資料庫中提供了許多內建函式,還可以自定義函式,實現 sql 邏輯。
檢視:檢視是由查詢結果形成的一張虛擬表,是表通過某種運算得到的一個投影。
儲存過程:把一段程式碼封裝起來,當要執行這一段程式碼的時候,可以通過呼叫該儲存過程來實現(經過第一次編譯後再次呼叫不需要再次編譯,比一個個執行 sql 語句效率高)
27. 常用 SQL 語句
DML(資料操作語言)
- SELECT - 從資料庫表中獲取資料
- UPDATE - 更新資料庫表中的資料
- DELETE - 從資料庫表中刪除資料
- INSERT INTO - 向資料庫表中插入資料
DDL(資料定義語言)
- CREATE DATABASE - 建立新資料庫
- ALTER DATABASE - 修改資料庫
- CREATE TABLE - 建立新表
- ALTER TABLE - 變更(改變)資料庫表
- DROP TABLE - 刪除表
- CREATE INDEX - 建立索引(搜尋鍵)
- DROP INDEX - 刪除索引
28. 主鍵和外來鍵的區別
定義主鍵和外來鍵主要是為了維護關聯式資料庫的完整性
主鍵是能確定一條記錄的唯一標識。不能重複,不允許為空。
外來鍵用於與另一張表關聯。是能確定另一張表記錄的欄位,用於保持資料的一致性。
主鍵 | 外來鍵 | 索引 | |
---|---|---|---|
定義 | 唯一標識一條記錄,不能重複,不允許為空 | 表的外來鍵是另一表的主鍵,外來鍵可以重複,可以是空值 | 該欄位沒有重複值,但可以有空值 |
作用 | 用來保證資料完整性 | 用來和其他表建立聯絡 | 提高查詢排序的速度 |
個數 | 只能有一個 | 可有多個 | 可有多個 |
29. 如何開啟 MySQL 慢日誌查詢
- 修改配置檔案,然後重啟服務生效 在linux下,vim /etc/my.cnf,在[mysqld]內容項下增加: slow_query_log = ON long_query_time = 2 # 查詢超過2秒的就會記錄
- 命令列,但是重啟服務後會失效 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2;
30. MySQL 資料庫備份命令
mysqldump -u 使用者名稱 -p 資料庫名 > 匯出的檔名
31. char 和 varchar 的區別
char:儲存定長資料很方便,CHAR 欄位上的索引效率級高,必須在括號裡定義長度,可以有預設值,比如定義 char(10)。
varchar:儲存變長資料,但儲存效率沒有 CHAR 高,必須在括號裡定義長度,可以有預設值。
32. 最左字首原則
mysql 建立多列索引(聯合索引)有最左字首的原則,即最左優先,如:
如果有一個2列的索引(col1,col2),則已經對(col1)、(col1,col2)上建立了索引;
如果有一個3列索引(col1,col2,col3),則已經對(col1)、(col1,col2)、(col1,col2,col3)上建立了索引;
33. 無法命中索引的情況
- 使用or關鍵字會導致無法命中索引
- 左前導查詢會導致無法命中索引,如 like '%a' 或者 like '%a%'
- 單列索引的索引列為 null 時全值匹配會使索引失效,組合索引全為 null 時索引失效
- 組合索引不符合左字首原則的列無法命中索引,如我們有4個列 a、b、c、d,我們建立一個組合索引 INDEX(
a
,b
,c
,d
),那麼能命中索引的查詢為 a,ab,abc,abcd,除此之外都無法命中索引 - 強制型別轉換會導致索引失效
- 負向查詢條件會導致無法使用索引,比如 NOT IN,NOT LIKE,!= 等
- 如果 mysql 估計使用全表掃描要比使用索引快,則不使用索引
34. 資料庫讀寫分離
讀寫分離,就是將資料庫分為了主從庫,一個主庫用於寫資料,多個從庫完成讀資料的操作,主從庫之間通過某種機制進行資料的同步,是一種常見的資料庫架構。
35. 資料庫分庫分表
資料庫水平切分,是一種常見的資料庫架構,是一種通過演算法,將資料庫進行分割的架構。一個水平切分叢集中的每個資料庫,通常稱為一個“分片”。每一個分片中的資料沒有重合,所有分片中的資料並集組成全部資料。
水平切分分為庫內分表和分庫分表,是根據表內資料內在的邏輯關係,將同一個表按不同的條件分散到多個資料庫或多個表中,每個表中只包含一部分資料,從而使得單個表的資料量變小,達到分散式的效果。
36. redis 和 memcached 比較
- redis 和 memcached 都是將資料存放在記憶體中,都是記憶體資料庫。不過 memcached 還可用於快取其他東西,例如圖片、視訊等等。
- redis 不僅僅支援簡單的 k/v 型別的資料,同時還提供 list,set,hash 等資料結構的儲存。
- 分散式設定, 都可以做一主多從或一主一從 。
- 儲存資料安全,memcached 掛掉後,資料完全丟失;redis 可以定期儲存到磁碟(持久化)。
- 災難恢復,memcached 掛掉後,資料不可恢復; redis 資料丟失後可以通過 aof 恢復。
37. redis中資料庫預設是多少個 db 及作用
redis 預設有16個資料庫,每個資料庫中的資料都是隔離的,這樣,在儲存資料的時候,就可以指定把不同的資料儲存到不同的資料庫中。 且只有單機才有,如果是叢集就沒有資料庫的概念。
38. redis 有哪幾種持久化策略
RDB 持久化:是將 Reids 在記憶體中的資料庫記錄定時 dump 到磁碟上的持久化
AOF(append only file)持久化:將 Reids 的操作日誌以追加的方式寫入檔案
39. redis 支援的過期策略
通用的三種過期策略
- 定時刪除 在設定 key 的過期時間的同時,為該 key 建立一個定時器,讓定時器在 key 的過期時間來臨時,對 key 進行刪除
- 惰性刪除 key 過期的時候不刪除,每次從資料庫獲取 key 的時候去檢查是否過期,若過期,則刪除,返回 null。
- 定期刪除 每隔一段時間執行一次刪除過期 key 操作
redis 採用惰性刪除+定期刪除策略
40. 如何保證 redis 中的資料都是熱點資料
限定 Redis 佔用的記憶體,Redis 會根據自身資料淘汰策略,載入熱資料到記憶體。 所以,計算一下所有熱點資料大約佔用的記憶體,然後設定一下 Redis 記憶體限制即可。
41. Python 操作 redis
使用 redis 第三方庫來操作
import redis
# 建立一個 redis 連線池
def redis_conn_pool():
pool = redis.ConnectionPool(host='redis-host', port=redis-port,
decode_responses=True, password='redis-pwd')
r = redis.Redis(connection_pool=pool)
return r
複製程式碼
42. 基於 redis 實現釋出和訂閱
訂閱者
if __name__ == "__main__":
conn = redis.Redis(host='',
port=12143, password='')
ps = conn.pubsub()
ps.subscribe('chat') # 從 chat 訂閱訊息
for item in ps.listen(): # 監聽狀態:有訊息釋出了就拿過來
if item['type'] == 'message':
print(item)
print(item['channel'])
print(item['data'])
複製程式碼
釋出者
if __name__ == "__main__":
number_list = ['300033', '300032', '300031', '300030']
signal = ['1', '-1', '1', '-1']
pool = redis.ConnectionPool(host='redis-12143.c8.us-east-1-3.ec2.cloud.redislabs.com', port=12143,
decode_responses=True, password='pkAWNdYWfbLLfNOfxTJinm9SO16eSJFx')
r = redis.Redis(connection_pool=pool)
for i in range(len(number_list)):
value_new = str(number_list[i]) + ' ' + str(signal[i])
print(value_new)
r.publish("chat", value_new)
複製程式碼
43. 如何高效的找到 redis 中的某個 KEY
import redis
con = redis.Redis()
con.keys(pattern='key*') # *代表萬用字元
複製程式碼
44. 基於 redis 實現先進先出、後進先出及優先順序佇列
class Zhan:
def __init__(self,conn):
self.conn = conn
def push(self,val):
self.conn.rpush('aaa',val)
def pop(self):
return self.conn.rpop('aaa')
class Dui:
def __init__(self,conn):
self.conn = conn
def push(self,val):
self.conn.rpush('bbb',val)
def get(self):
return self.conn.lpop('bbb')
class Xu:
def __init__(self,conn):
self.conn = conn
def push(self,val,count):
self.conn.zadd('ccc',val,count)
def get(self):
a = self.conn.zrange('ccc', 0, 0)[0]
self.conn.zrem('ccc', a)
return a
複製程式碼
45. redis 如何實現主從複製
在從伺服器中配置 SLAVEOF 127.0.0.1 6380 # 主伺服器 IP,埠
46. 迴圈獲取 redis 中某個非常大的列表資料
def list_iter(name):
"""
自定義redis列表增量迭代
:param name: redis中的name,即:迭代name對應的列表
:return: yield 返回 列表元素
"""
list_count = r.llen(name)
for index in xrange(list_count):
yield r.lindex(name, index)
複製程式碼
47. redis 中的 watch 的命令的作用
watch 用於在進行事務操作的最後一步也就是在執行 exec 之前對某個 key 進行監視,如果這個被監視的 key 被改動,那麼事務就被取消,否則事務正常執行。
48. redis 分散式鎖
為 redis 叢集設計的鎖,防止多個任務同時修改資料庫,其本質就是為叢集中的每個主機設定一個會超時的字串,當叢集中有一半多的機器設定成功後就認為加鎖成功,直至鎖過期或解鎖不會有第二個任務加鎖成功。
49. http 協議
超文字傳輸協議(HTTP,HyperText Transfer Protocol)是網際網路上應用最為廣泛的一種網路協議。HTTP 是一個客戶端和伺服器端請求和應答的標準。客戶端是終端使用者,伺服器端是網站。一般由 HTTP 客戶端發起一個請求,建立一個到伺服器指定埠(預設是80埠)的 TCP 連線,HTTP 伺服器則在那個埠監聽客戶端傳送過來的請求,並給與響應。
50. uwsgi,uWSGI 和 WSGI 的區別
WSGI:全稱是 Web Server Gateway Interface,是一種描述 web server 如何與 web application 通訊的規範。django,flask 等都遵循該協議。
uwsgi:是伺服器和服務端應用程式的一種協議,規定了怎麼把請求轉發給應用程式和返回; uwsgi 是一種線路協議而不是通訊協議,在此常用於在 uWSGI 伺服器與其他網路伺服器的資料通訊。
uWSGI:是一個 Web 伺服器,它實現了 WSGI 協議、uwsgi、http 等協議。Nginx 中 HttpUwsgiModule 的作用是與 uWSGI 伺服器進行交換。
51. HTTP 狀態碼
1xx: 資訊
2xx:成功
3xx:重定向
4xx:客戶端錯誤
5xx:伺服器錯誤
52. HTTP常見請求方式
GET,POST,PUT,DELETE,PATCH 等
53. 響應式佈局
響應式佈局是 Ethan Marcotte 在2010年5月份提出的一個概念,簡而言之,就是一個網站能夠相容多個終端——而不是為每個終端做一個特定的版本。
54. 實現一個簡單的 AJAX 請求
AJAX 是一種在無需重新載入整個網頁的情況下,能夠更新部分網頁的技術。
AJAX = 非同步 JavaScript 和 XML
$(function(){
$('#send').click(function(){
$.ajax({
type: "GET",
url: "test.json",
data: {username:$("#username").val(), content:$("#content").val()},
dataType: "json",
success: function(data){
$('#resText').empty(); //清空resText裡面的所有內容
var html = '';
$.each(data, function(commentIndex, comment){
html += '<div class="comment"><h6>' + comment['username']
+ ':</h6><p class="para"' + comment['content']
+ '</p></div>';
});
$('#resText').html(html);
}
});
});
});
複製程式碼
55. 同源策略
同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。
如果兩個頁面的協議,埠(如果有指定)和主機都相同,則兩個頁面具有相同的源。我們也可以把它稱為“協議/主機/埠 tuple”,或簡單地叫做“tuple". ("tuple" ,“元”,是指一些事物組合在一起形成一個整體,比如(1,2)叫二元,(1,2,3)叫三元)
56. 什麼是 CORS
CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 AJAX 跨域請求資源的方式,支援現代瀏覽器。
57. 什麼是 CSRF
CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。
58. 前端實現輪詢、長輪詢
輪詢
var xhr = new XMLHttpRequest();
setInterval(function(){
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
};
xhr.send();
},1000)
複製程式碼
長輪詢
function ajax(){
var xhr = new XMLHttpRequest();
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
ajax();
};
xhr.send();
}
複製程式碼
59. 簡述 MVC 和 MTV
所謂 MVC 就是把 web 應用分為模型(M),控制器(C),檢視(V)三層,他們之間以一種外掛似的,鬆耦合的方式連線在一起。 模型負責業務物件與資料庫的物件(ORM),檢視負責與使用者的互動(頁面),控制器(C)接受使用者的輸入呼叫模型和檢視完成使用者的請求。
Django 中的 MTV 模式:Model(模型):負責業務物件與資料庫的物件(ORM),Template(模版):負責如何把頁面展示給使用者,View(檢視):負責業務邏輯,並在適當的時候呼叫 Model 和 Template,本質上與 MVC 相同。
60. 介面的冪等性
介面冪等性就是使用者對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因為多次點選而產生了副作用。
61. Flask 框架的優勢
簡潔,輕巧,擴充套件性強,自由度高。
62. 什麼是 ORM
ORM 的全稱是 Object Relational Mapping,即物件關係對映。它的實現思想就是將關聯式資料庫中表的資料對映成為物件,以物件的形式展現,這樣開發人員就可以把對資料庫的操作轉化為對這些物件的操作。
63. PV、UV 的含義
PV:是(page view)訪問量,頁面瀏覽量或點選量,衡量網站使用者訪問的網頁數量。在一定統計週期內使用者每開啟或重新整理一個頁面就記錄1次,多次開啟或重新整理同一頁面則瀏覽量累計。 UV:是(Unique Visitor)獨立訪客,統計一段時間內訪問某站點的使用者數(以cookie為依據)。
64. supervisor 的作用
supervisor 管理程式,是通過 fork/exec 的方式將這些被管理的程式當作 supervisor 的子程式來啟動,所以我們只需要將要管理程式的可執行檔案的路徑新增到 supervisor 的配置檔案中即可。
65. 使用 ORM 和原生 SQL 的優缺點
優點:
- 方便的使用物件導向,語句清晰;
- 有效的防止 SQL 注入;
- 方便動態構造語句,對於不同的表的相同操作採用多型實現更優雅;
- 一定程度上方便重構資料層
- 方便設定設定鉤子函式
缺點:
- 不太容易處理複雜查詢語句
- 效能較直接用 SQL 差
66. 列舉一些 django 的內建元件
- Admin 元件:是對 model 中對應的資料表進行增刪改查提供的元件
- model 元件:負責運算元據庫
- form 元件:生成 HTML 程式碼;資料有效性校驗;校驗資訊返回並展示
- ModelForm 元件:用於資料庫操作,也可用於使用者請求的驗證
67. 列舉 Django 中執行原生 sql 的方法
- 使用 execute 執行自定義的 SQL 直接執行 SQL 語句(類似於 pymysql 的用法)
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;")
ret = cursor.fetchall()
print(ret)
複製程式碼
- 使用 extra 方法:queryset.extra(select={"key": "原生的SQL語句"})
- 使用 raw 方法
- 執行原始 sql 並返回模型
- 依賴於 model 模型,多用於查詢操作
68. cookie 和 session 的區別
cookie 是儲存在瀏覽器端的鍵值對,可以用來做使用者認證。
sesseion 是將使用者的會話資訊儲存在服務端,key 值是隨機產生的字串,value 值是 session 的內容,依賴於 cookie 將每個使用者的隨機字串儲存到使用者瀏覽器中。
69. beautifulsoup 模組的作用
BeautifulSoup 庫是解析、遍歷、維護“標籤樹”的功能庫。
url = "http://www.baidu.com/"
request = requests.get(url)
html = request.content
soup = BeautifulSoup(html, "html.parser", from_encoding="utf-8")
複製程式碼
70. Selenium 模組簡述
Selenium 是模擬操作瀏覽器的庫,可以根據我們的指令,讓瀏覽器自動載入頁面,獲取需要的資料,甚至頁面截圖,或者判斷網站上某些動作是否發生等。
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source) # browser.page_source 是獲取網頁的全部 html
browser.close()
複製程式碼
歡迎關注我的微信公眾號--蘿蔔大雜燴,或者掃描下方的二維碼,大家一起交流,學習和進步!