自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

高并發(fā) HTTP 請求實(shí)踐

開發(fā) 前端
當(dāng)今,正處于互聯(lián)網(wǎng)高速發(fā)展的時(shí)代,每個(gè)人的生活都離不開互聯(lián)網(wǎng),互聯(lián)網(wǎng)已經(jīng)影響了每個(gè)人生活的方方面面。

 [[431694]]

當(dāng)今,正處于互聯(lián)網(wǎng)高速發(fā)展的時(shí)代,每個(gè)人的生活都離不開互聯(lián)網(wǎng),互聯(lián)網(wǎng)已經(jīng)影響了每個(gè)人生活的方方面面。我們使用淘寶、京東進(jìn)行購物,使用微信進(jìn)行溝通,使用美圖秀秀進(jìn)行拍照美化等等。而這些每一步的操作下面,都離不開一個(gè)技術(shù)概念HTTP(Hypertext Transfer Protocol,超文本傳輸協(xié)議)。

舉個(gè):chestnut:,當(dāng)我們打開京東APP的時(shí)候,首先進(jìn)入的是開屏頁面,然后進(jìn)入首頁。在開屏一般是廣告,而首頁是內(nèi)容相關(guān),包括秒殺,商品推薦以及各個(gè)tag頁面,而各個(gè)tag也有其對應(yīng)的內(nèi)容。當(dāng)我們在進(jìn)入開屏之前或者開屏之后(這塊依賴于各個(gè)app的技術(shù)實(shí)現(xiàn)),會向后端服務(wù)發(fā)送一個(gè)http請求,這個(gè)請求會帶上該頁面廣告位信息,向后端要內(nèi)容,后端根據(jù)廣告位的配置,挑選一個(gè)合適的廣告或者推薦商品返回給APP端進(jìn)行展示。在這里,為了描述方便,后端當(dāng)做一個(gè)簡單的整體,實(shí)際上,后端會有非常復(fù)雜的業(yè)務(wù)調(diào)度,比如獲取用戶畫像,廣告定向,獲取素材,計(jì)算坐標(biāo),返回APP,APP端根據(jù)坐標(biāo)信息,下載素材,然后進(jìn)行渲染,從而在用戶端進(jìn)行展示,這一切都是秒級甚至毫秒級響應(yīng),一個(gè)高效的HTTP Client在這里就顯得尤為重要,本文主要從業(yè)務(wù)場景來分析,如何實(shí)現(xiàn)一個(gè)高效的HTTP Client。

一、概念

當(dāng)我們需要模擬發(fā)送一個(gè)http請求的時(shí)候,往往有兩種方式:

1、通過瀏覽器

2、通過 curl 命令進(jìn)行發(fā)送請求

如果我們在大規(guī)模高并發(fā)的業(yè)務(wù)中,如果使用curl來進(jìn)行http請求,其效果以及性能是不能滿足業(yè)務(wù)需求的,這就引入了另外一個(gè)概念 libcurl。

二、實(shí)現(xiàn)

在開始實(shí)現(xiàn)client發(fā)送http請求之前,我們先理解兩個(gè)概念:

同步請求

異步請求

客戶端把請求發(fā)送給服務(wù)器之后,不會等待服務(wù)器返回,而是去做其他事情,待服務(wù)器處理完成之后,通知客戶端該事件已經(jīng)完成,客戶端在獲取到通知后,將服務(wù)器處理后的結(jié)果返回給調(diào)用方。

通過這倆概念,就能看出,異步在實(shí)現(xiàn)上,要比同步復(fù)雜的多。同步,即我們簡單的等待處理結(jié)果,待處理結(jié)果完成之后,再返回調(diào)用方。而對于異步,往往在實(shí)現(xiàn)上,需要各種回調(diào)機(jī)制,各種通知機(jī)制,即在處理完成的時(shí)候,需要知道是哪個(gè)任務(wù)完成了,從而通知客戶端去處理該任務(wù)完成后剩下的邏輯。

下面,我們將從代碼實(shí)現(xiàn)的角度,來更深一步的理解libcurl在實(shí)現(xiàn)同步和異步請求操作上的區(qū)別,從而更近異步的了解同步和異步的實(shí)現(xiàn)原理。 

同步

使用libcurl完成同步http請求,原理和代碼都比較簡單,主要是分位以下幾個(gè)步驟:

1、初始化easy handle

2、在該easy handle上設(shè)置相關(guān)參數(shù),在本例中主要有以下幾個(gè)參數(shù)

  • CURLOPT_URL,即請求的url

  • CURLOPT_WRITEFUNCTION,即回調(diào)函數(shù),將http server返回?cái)?shù)據(jù)寫入對應(yīng)的地方

  • CURLOPT_FOLLOWLOCATION,是否獲取302跳轉(zhuǎn)后的內(nèi)容

  • CURLOPT_POSTFIELDSIZE,此次發(fā)送的數(shù)據(jù)大小

  • CURLOPT_POSTFIELDS,此次發(fā)送的數(shù)據(jù)內(nèi)容

  • 更多的參數(shù)設(shè)置,請參考libcurl官網(wǎng)

3、 curl_easy_perform,調(diào)用該函數(shù)發(fā)送http請求,并同步等待返回結(jié)果

4、 curl_easy_cleanup,釋放步驟一中申請的easy handle資源

代碼實(shí)現(xiàn)(easy_curl.cc)

編譯

結(jié)果

異步

接 觸過網(wǎng)絡(luò)編程的讀者,都或多或少的了解多路復(fù)用的原理。 IO多路復(fù)用在Linux下包括了三種, select 、 poll 、 epoll ,抽象來看,他們功能是類似的,但具體細(xì)節(jié)各有不同:首先都會對一組文件描述符進(jìn)行相關(guān)事件的注冊,然后阻塞等待某些事件的發(fā)生或等待超時(shí)。

在使用Libcurl進(jìn)行異步請求,從上層結(jié)構(gòu)來看,簡單來說,就是對easy handle 和 multi 接口的結(jié)合使用。其中,easy handle底層也是一個(gè)socket,multi接口,其底層實(shí)現(xiàn)也用的是epoll,那么我們?nèi)绾问褂胑asy handle和multi接口,來實(shí)現(xiàn)一個(gè)高性能的異步http 請求client呢?下面我們將使用代碼的形式,使得讀者能夠進(jìn)一步了解其實(shí)現(xiàn)機(jī)制。

multi 接口的使用是在easy 接口的基礎(chǔ)之上,將easy handle放到一個(gè)隊(duì)列中(multi handle),然后并發(fā)發(fā)送請求。與easy 接口相比,multi接口是一個(gè)異步的,非阻塞的傳輸方式。

multi接口的使用,主要有以下幾個(gè)步驟:

  • curl_multi _init初始化一個(gè)multi handler對象

  • 初始化多個(gè)easy handler對象,使用curl_easy_setopt進(jìn)行相關(guān)設(shè)置

  • 調(diào)用curl_multi _add_handle把easy handler添加到multi curl對象中

  • 添加完畢后執(zhí)行curl_multi_perform方法進(jìn)行并發(fā)的訪問

  • 訪問結(jié)束后curl_multi_remove_handle移除相關(guān)easy curl對象,先用curl_easy_cleanup清除easy handler對象,最后curl_multi_cleanup清除multi handler對象。

http_request.h

http_request.cc

main.cc

至此,我們已經(jīng)可以使用libcurl來實(shí)現(xiàn)并發(fā)發(fā)送http請求,當(dāng)然這個(gè)只是一個(gè)簡單異步實(shí)現(xiàn)功能,更多的功能,還需要讀者去使用libcurl中的其他功能去實(shí)現(xiàn),此處留給讀者一個(gè)問題(這個(gè)問題,也是筆者項(xiàng)目中使用的一個(gè)功能,該項(xiàng)目已經(jīng)線上穩(wěn)定運(yùn)行4年,日請求量在20E ),業(yè)務(wù)需要,某一個(gè)請求需要并發(fā)發(fā)送給指定的幾家,即該請求,需要并發(fā)發(fā)送給幾個(gè)http server,在一個(gè)特定的超時(shí)時(shí)間內(nèi),獲取這幾個(gè)http server的返回內(nèi)容,并進(jìn)行處理,那么這種功能應(yīng)該如何使用libcurl來實(shí)現(xiàn)呢?透露下,可以使用libcurl的另外一個(gè)參數(shù)CURLOPT_PRIVATE。

三、性能對比

至此,我們已經(jīng)基本完成了 高性能http 并發(fā)功能的設(shè)計(jì),那么到底性能如何呢?筆者從 以下幾個(gè)角度來做了測試:

1、串行發(fā)送同步請求

2、多線程情況下,發(fā)送同步請求(此處線程為4個(gè),筆者測試的服務(wù)器為4C)

3、使用multi接口

4、使用multi接口,并復(fù)用其對應(yīng)的easy handle

5、使用dns cache(對easy handle設(shè)置CURLOPT_DNS_CACHE_TIMEOUT),即不用每次都進(jìn)行dns解析

方法

平均耗時(shí)(ms)

最大耗時(shí)(ms)

串行 同步

21.381

30.617

多線程同步

4.331

16.751

multi接口

1.376

11.974

multi接口 連接復(fù)用

0.352

0.748

multi 接口使用dns cache

0 .381

0.731

四、一點(diǎn)心得

libcurl是一個(gè)高性能,較易用的HTTP client,在使用其直接,一定要對其接口功能進(jìn)行詳細(xì)的了解,否則很容易入坑,猶記得在18年中的時(shí)候,上 線了某一個(gè)功能,會偶現(xiàn)coredump(在上線之前,也進(jìn)行了大量的性能測試,都沒有出現(xiàn)過一次coredump),為了分析這個(gè)原因,筆者將服務(wù)的代碼一直精簡精簡,然后模擬測試,縮小coredump定位范圍,最終發(fā)現(xiàn),只有在超時(shí)的時(shí)候,才會導(dǎo)致coredump,這就說明了為什么測試環(huán)境沒有coredump,而線上會產(chǎn)生coredump,這是因?yàn)榫€上的超時(shí)時(shí)間設(shè)置的是5ms,而測試環(huán)境超時(shí)時(shí)間是20ms,這就基本把原因定位到超時(shí)導(dǎo)致的coredump。

然后,分析libcurl源碼,發(fā)送時(shí)一個(gè)libcurl的參數(shù)設(shè)置導(dǎo)致coredump,至此,筆者耗費(fèi)了23個(gè)小時(shí),問題才得以解決。

 

 

責(zé)任編輯:張燕妮 來源: 高性能架構(gòu)探索
相關(guān)推薦

2016-12-28 14:16:25

京東高并發(fā)系統(tǒng)設(shè)計(jì)

2016-11-28 09:00:10

瀏覽器瀏覽器緩存服務(wù)端

2021-01-21 15:36:27

AndroidAMSSDK

2019-12-24 09:30:59

蘇寧高可用高并發(fā)

2023-02-03 15:16:42

SpringHystrix

2019-09-19 09:44:08

HTTPCDNTCP

2019-03-27 10:50:50

HTTP請求管線式

2024-08-05 09:29:00

前端接口請求

2025-04-27 01:22:00

QPS高并發(fā)MySQL

2021-05-13 21:58:00

高并發(fā)應(yīng)用Asyncio

2019-06-28 10:55:04

預(yù)熱高并發(fā)并發(fā)高

2025-02-12 08:07:40

2018-07-24 13:01:52

前端優(yōu)化前端性能瀏覽器

2024-10-08 11:21:11

2025-02-14 03:00:00

2024-08-29 09:32:36

2022-08-10 21:43:29

HttpClientHttp工具網(wǎng)絡(luò)

2021-06-17 09:32:39

重復(fù)請求并發(fā)請求Java

2025-03-10 10:00:00

Ollama高并發(fā)

2018-10-18 10:05:43

HTTP網(wǎng)絡(luò)協(xié)議TCP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號