高性能libcurl
本文主要介绍一下curl接口的使用方法,以及获取高性能的一些实践。
什么是libcurl?用处?
|
|
官网摘的一段,意思大概是免费且容易使用的url传输库,支持下面一堆特性。
项目内用处:基于libcurl实现了一个单线程异步的httpc,用于msdk、防沉迷、信用分等需要接入外部http的服务。
接口介绍
curl一共有三种接口:
Easy Interface
|
|
简单接口是一个同步接口,非常方便使用,接口以curl_easy_开头,下面一个简单的使用例子。
|
|
Multi Interface
|
|
多重接口是异步接口,libcurl使用一个或者多个线程完成数据传输,通过多重接口可以再单线程下同时操作多个easy handle。
例子:https://gist.github.com/clemensg/4960504
|
|
Share Interface
|
|
用于再多个easy handle共享一些数据,比如dns cache、tls session。
其他
curl_global_init:进程启动时初始化curl
curl_global_cleanup:进程关闭时清理curl
使用异步DNS,防止同步解析DNS卡住主循环
实践
-
最初实现了一个使用Multi Interface的HTTPC。
-
httpc/unittest/httpc.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
TEST_F(HTTPC_TEST, HTTP_GET) { HTTPC_CFG cfg; REQUEST_DRIVER driver(10); HTTPC c(cfg, driver); auto cb = [&](RESPONSE &rsp) { printf("result:%d code:%ld \n", rsp._result, rsp._http_status_code); printf("body:%s", rsp._body.c_str()); }; for (u32 i = 0; i < 10; ++i) { c.get("http://www.baidu.com", cb); } bool idle; while (!driver._ctx_map.empty()) { driver.loop(idle, 0); }; }
-
-
在压测过程中发现性能不足,DNS解析卡住主循环。根据https://moz.com/devblog/high-performance-libcurl-tips,增加了c-ares库,使得libcurl支持异步DNS,最终性能到了3000TPS。
-
尝试使用Share Interface共享DNS,效果在接入异步DNS后不明显。
1 2 3 4 5 6 7 8 9 10 11
// 初始化共享 pthread_mutex_t _dns_lock = PTHREAD_MUTEX_INITIALIZER CURLSH* _share_handler = curl_share_init(); curl_share_setopt(_share_handler, CURLSHOPT_USERDATA, &_dns_lock); curl_share_setopt(_share_handler, CURLSHOPT_LOCKFUNC, _lock); curl_share_setopt(_share_handler, CURLSHOPT_UNLOCKFUNC, _unlock); curl_share_setopt(_share_handler, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); // 设置共享 curl_easy_setopt(ctx->_requst->_curl_handle, CURLOPT_SHARE, _share_handler); curl_easy_setopt(ctx->_requst->_curl_handle, CURLOPT_DNS_CACHE_TIMEOUT, 5 * 60);//5min
-
请求处理完毕后,不适用curl_easy_cleanup,而是采用连接池的方式通过curl_easy_reset重用连接。
-
https://curl.se/libcurl/c/libcurl-tutorial.html#Persistence
1 2 3 4 5 6 7 8 9
Re-cycling the same easy handle several times when doing multiple requests is the way to go. After each single curl_easy_perform operation, libcurl will keep the connection alive and open. A subsequent request using the same easy handle to the same host might just be able to use the already open connection! This reduces network impact a lot. Even if the connection is dropped, all connections involving SSL to the same host again, will benefit from libcurl's session ID cache that drastically reduces re-connection time. .... libcurl caches DNS name resolving results, to make lookups of a previously looked up name a lot faster.
-
https://curl.se/libcurl/c/curl_easy_reset.html
1 2 3
Re-initializes all options previously set on a specified CURL handle to the default values. This puts back the handle to the same state as it was in when it was just created with curl_easy_init. It does not change the following information kept in the handle: live connections, the Session ID cache, the DNS cache, the cookies, the shares or the alt-svc cache.
-