Skip to content

Commit b6e4f03

Browse files
authored
Optimize server latency (#2886)
* Optimize server latency * Only update real sent time to span
1 parent da4e33a commit b6e4f03

9 files changed

Lines changed: 115 additions & 40 deletions

src/brpc/details/method_status.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ void MethodStatus::SetConcurrencyLimiter(ConcurrencyLimiter* cl) {
149149
_cl.reset(cl);
150150
}
151151

152+
int HandleResponseWritten(bthread_id_t id, void* data, int /*error_code*/) {
153+
auto args = static_cast<ResponseWriteInfo*>(data);
154+
args->sent_us = butil::cpuwide_time_us();
155+
CHECK_EQ(0, bthread_id_unlock_and_destroy(id));
156+
return 0;
157+
}
158+
152159
ConcurrencyRemover::~ConcurrencyRemover() {
153160
if (_status) {
154161
_status->OnResponded(_c->ErrorCode(), butil::cpuwide_time_us() - _received_us);

src/brpc/details/method_status.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,23 @@ friend class Server;
7575
bvar::PassiveStatus<int32_t> _max_concurrency_bvar;
7676
};
7777

78+
struct ResponseWriteInfo {
79+
int64_t sent_us{0};
80+
};
81+
82+
int HandleResponseWritten(bthread_id_t id, void* data, int error_code);
83+
7884
class ConcurrencyRemover {
7985
public:
8086
ConcurrencyRemover(MethodStatus* status, Controller* c, int64_t received_us)
81-
: _status(status)
82-
, _c(c)
83-
, _received_us(received_us) {}
87+
: _status(status) , _c(c) , _received_us(received_us) {}
8488
~ConcurrencyRemover();
89+
8590
private:
8691
DISALLOW_COPY_AND_ASSIGN(ConcurrencyRemover);
8792
MethodStatus* _status;
8893
Controller* _c;
89-
uint64_t _received_us;
94+
int64_t _received_us;
9095
};
9196

9297
inline bool MethodStatus::OnRequested(int* rejected_cc, Controller* cntl) {

src/brpc/policy/baidu_rpc_protocol.cpp

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -184,37 +184,39 @@ struct BaiduProxyPBMessages : public RpcPBMessages {
184184
}
185185

186186
// Used by UT, can't be static.
187-
void SendRpcResponse(int64_t correlation_id,
188-
Controller* cntl,
189-
RpcPBMessages* messages,
190-
const Server* server,
191-
MethodStatus* method_status,
192-
int64_t received_us) {
187+
void SendRpcResponse(int64_t correlation_id, Controller* cntl,
188+
RpcPBMessages* messages, const Server* server,
189+
MethodStatus* method_status, int64_t received_us) {
193190
ControllerPrivateAccessor accessor(cntl);
194191
Span* span = accessor.span();
195192
if (span) {
196193
span->set_start_send_us(butil::cpuwide_time_us());
197194
}
198195
Socket* sock = accessor.get_sending_socket();
199196

200-
std::unique_ptr<Controller, LogErrorTextAndDelete> recycle_cntl(cntl);
201-
ConcurrencyRemover concurrency_remover(method_status, cntl, received_us);
197+
const google::protobuf::Message* req = NULL == messages ? NULL : messages->Request();
198+
const google::protobuf::Message* res = NULL == messages ? NULL : messages->Response();
199+
200+
// Recycle resources at the end of this function.
201+
BRPC_SCOPE_EXIT {
202+
{
203+
// Remove concurrency and record latency at first.
204+
ConcurrencyRemover concurrency_remover(method_status, cntl, received_us);
205+
}
206+
207+
std::unique_ptr<Controller, LogErrorTextAndDelete> recycle_cntl(cntl);
202208

203-
auto messages_guard = butil::MakeScopeGuard([server, messages] {
204209
if (NULL == messages) {
205210
return;
206211
}
207-
if (NULL != server->options().baidu_master_service) {
208-
BaiduProxyPBMessages::Return(static_cast<BaiduProxyPBMessages*>(messages));
209-
} else {
212+
213+
cntl->CallAfterRpcResp(req, res);
214+
if (NULL == server->options().baidu_master_service) {
210215
server->options().rpc_pb_message_factory->Return(messages);
216+
} else {
217+
BaiduProxyPBMessages::Return(static_cast<BaiduProxyPBMessages*>(messages));
211218
}
212-
});
213-
214-
const google::protobuf::Message* req = NULL == messages ? NULL : messages->Request();
215-
const google::protobuf::Message* res = NULL == messages ? NULL : messages->Response();
216-
ClosureGuard guard(brpc::NewCallback(
217-
cntl, &Controller::CallAfterRpcResp, req, res));
219+
};
218220

219221
StreamIds response_stream_ids = accessor.response_streams();
220222

@@ -299,32 +301,37 @@ void SendRpcResponse(int64_t correlation_id,
299301
}
300302
}
301303

304+
ResponseWriteInfo args;
305+
bthread_id_t response_id = INVALID_BTHREAD_ID;
302306
if (span) {
303307
span->set_response_size(res_buf.size());
308+
CHECK_EQ(0, bthread_id_create(&response_id, &args, HandleResponseWritten));
304309
}
310+
305311
// Send rpc response over stream even if server side failed to create
306312
// stream for some reason.
307-
if(cntl->has_remote_stream()){
313+
if (cntl->has_remote_stream()) {
308314
// Send the response over stream to notify that this stream connection
309315
// is successfully built.
310316
// Response_stream can be INVALID_STREAM_ID when error occurs.
311317
if (SendStreamData(sock, &res_buf,
312318
accessor.remote_stream_settings()->stream_id(),
313-
response_stream_id) != 0) {
314-
const int errcode = errno;
315-
std::string error_text = butil::string_printf(64, "Fail to write into %s",
316-
sock->description().c_str());
317-
PLOG_IF(WARNING, errcode != EPIPE) << error_text;
318-
cntl->SetFailed(errcode, "%s", error_text.c_str());
319-
Stream::SetFailed(response_stream_ids, errcode, "%s",
320-
error_text.c_str());
319+
response_stream_id, response_id) != 0) {
320+
error_code = errno;
321+
PLOG_IF(WARNING, error_code != EPIPE)
322+
<< "Fail to write into " << sock->description();
323+
cntl->SetFailed(error_code, "Fail to write into %s",
324+
sock->description().c_str());
325+
Stream::SetFailed(response_stream_ids, error_code,
326+
"Fail to write into %s",
327+
sock->description().c_str());
321328
return;
322329
}
323330

324331
// Now it's ok the mark these server-side streams as connected as all the
325332
// written user data would follower the RPC response.
326333
// Reuse stream_ptr to avoid address first stream id again
327-
if(stream_ptr) {
334+
if (stream_ptr) {
328335
((Stream*)stream_ptr->conn())->SetConnected();
329336
}
330337
for (size_t i = 1; i < response_stream_ids.size(); ++i) {
@@ -344,6 +351,10 @@ void SendRpcResponse(int64_t correlation_id,
344351
// users to set max_concurrency.
345352
Socket::WriteOptions wopt;
346353
wopt.ignore_eovercrowded = true;
354+
if (INVALID_BTHREAD_ID != response_id) {
355+
wopt.id_wait = response_id;
356+
wopt.notify_on_success = true;
357+
}
347358
if (sock->Write(&res_buf, &wopt) != 0) {
348359
const int errcode = errno;
349360
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *sock;
@@ -354,8 +365,10 @@ void SendRpcResponse(int64_t correlation_id,
354365
}
355366

356367
if (span) {
368+
bthread_id_join(response_id);
369+
// Do not care about the result of background writing.
357370
// TODO: this is not sent
358-
span->set_sent_us(butil::cpuwide_time_us());
371+
span->set_sent_us(args.sent_us);
359372
}
360373
}
361374

src/brpc/policy/http_rpc_protocol.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,8 +934,15 @@ HttpResponseSender::~HttpResponseSender() {
934934
int rc = -1;
935935
// Have the risk of unlimited pending responses, in which case, tell
936936
// users to set max_concurrency.
937+
ResponseWriteInfo args;
937938
Socket::WriteOptions wopt;
938939
wopt.ignore_eovercrowded = true;
940+
bthread_id_t response_id = INVALID_BTHREAD_ID;
941+
if (span) {
942+
CHECK_EQ(0, bthread_id_create(&response_id, &args, HandleResponseWritten));
943+
wopt.id_wait = response_id;
944+
wopt.notify_on_success = true;
945+
}
939946
if (is_http2) {
940947
if (is_grpc) {
941948
// Append compressed and length before body
@@ -980,9 +987,12 @@ HttpResponseSender::~HttpResponseSender() {
980987
cntl->SetFailed(errcode, "Fail to write into %s", socket->description().c_str());
981988
return;
982989
}
990+
983991
if (span) {
992+
bthread_id_join(response_id);
993+
// Do not care about the result of background writing.
984994
// TODO: this is not sent
985-
span->set_sent_us(butil::cpuwide_time_us());
995+
span->set_sent_us(args.sent_us);
986996
}
987997
}
988998

src/brpc/policy/hulu_pbrpc_protocol.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,18 +304,28 @@ static void SendHuluResponse(int64_t correlation_id,
304304

305305
// Have the risk of unlimited pending responses, in which case, tell
306306
// users to set max_concurrency.
307+
ResponseWriteInfo args;
307308
Socket::WriteOptions wopt;
308309
wopt.ignore_eovercrowded = true;
310+
bthread_id_t response_id = INVALID_BTHREAD_ID;
311+
if (span) {
312+
CHECK_EQ(0, bthread_id_create(&response_id, &args, HandleResponseWritten));
313+
wopt.id_wait = response_id;
314+
wopt.notify_on_success = true;
315+
}
309316
if (sock->Write(&res_buf, &wopt) != 0) {
310317
const int errcode = errno;
311318
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *sock;
312319
cntl->SetFailed(errcode, "Fail to write into %s",
313320
sock->description().c_str());
314321
return;
315322
}
323+
316324
if (span) {
325+
bthread_id_join(response_id);
326+
// Do not care about the result of background writing.
317327
// TODO: this is not sent
318-
span->set_sent_us(butil::cpuwide_time_us());
328+
span->set_sent_us(args.sent_us);
319329
}
320330
}
321331

src/brpc/policy/nshead_protocol.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ void NsheadClosure::Run() {
9595
return;
9696
}
9797

98+
int64_t sent_us = 0;
9899
if (_do_respond) {
99100
// response uses request's head as default.
100101
// Notice that the response use request.head.log_id directly rather
@@ -112,19 +113,32 @@ void NsheadClosure::Run() {
112113
write_buf.append(_response.body.movable());
113114
// Have the risk of unlimited pending responses, in which case, tell
114115
// users to set max_concurrency.
116+
ResponseWriteInfo args;
115117
Socket::WriteOptions wopt;
116118
wopt.ignore_eovercrowded = true;
119+
bthread_id_t response_id = INVALID_BTHREAD_ID;
120+
if (span) {
121+
CHECK_EQ(0, bthread_id_create(&response_id, &args, HandleResponseWritten));
122+
wopt.id_wait = response_id;
123+
wopt.notify_on_success = true;
124+
}
117125
if (sock->Write(&write_buf, &wopt) != 0) {
118126
const int errcode = errno;
119127
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *sock;
120128
_controller.SetFailed(errcode, "Fail to write into %s",
121129
sock->description().c_str());
122130
return;
123131
}
132+
133+
if (span) {
134+
bthread_id_join(response_id);
135+
// Do not care about the result of background writing.
136+
sent_us = args.sent_us;
137+
}
124138
}
125139
if (span) {
126140
// TODO: this is not sent
127-
span->set_sent_us(butil::cpuwide_time_us());
141+
span->set_sent_us(0 == sent_us ? butil::cpuwide_time_us() : sent_us);
128142
}
129143
}
130144

src/brpc/policy/sofa_pbrpc_protocol.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,18 +281,28 @@ static void SendSofaResponse(int64_t correlation_id,
281281
}
282282
// Have the risk of unlimited pending responses, in which case, tell
283283
// users to set max_concurrency.
284+
ResponseWriteInfo args;
284285
Socket::WriteOptions wopt;
285286
wopt.ignore_eovercrowded = true;
287+
bthread_id_t response_id = INVALID_BTHREAD_ID;
288+
if (span) {
289+
CHECK_EQ(0, bthread_id_create(&response_id, &args, HandleResponseWritten));
290+
wopt.id_wait = response_id;
291+
wopt.notify_on_success = true;
292+
}
286293
if (sock->Write(&res_buf, &wopt) != 0) {
287294
const int errcode = errno;
288295
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *sock;
289296
cntl->SetFailed(errcode, "Fail to write into %s",
290297
sock->description().c_str());
291298
return;
292299
}
300+
293301
if (span) {
302+
bthread_id_join(response_id);
303+
// Do not care about the result of background writing.
294304
// TODO: this is not sent
295-
span->set_sent_us(butil::cpuwide_time_us());
305+
span->set_sent_us(args.sent_us);
296306
}
297307
}
298308

src/brpc/policy/streaming_rpc_protocol.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ void SendStreamClose(Socket *sock, int64_t remote_stream_id,
154154
}
155155

156156
int SendStreamData(Socket* sock, const butil::IOBuf* data,
157-
int64_t remote_stream_id, int64_t source_stream_id) {
157+
int64_t remote_stream_id, int64_t source_stream_id,
158+
bthread_id_t response_id) {
158159
CHECK(sock != NULL);
159160
StreamFrameMeta fm;
160161
fm.set_stream_id(remote_stream_id);
@@ -164,6 +165,10 @@ int SendStreamData(Socket* sock, const butil::IOBuf* data,
164165
butil::IOBuf out;
165166
PackStreamMessage(&out, fm, data);
166167
Socket::WriteOptions wopt;
168+
if (INVALID_BTHREAD_ID != response_id) {
169+
wopt.id_wait = response_id;
170+
wopt.notify_on_success = true;
171+
}
167172
wopt.ignore_eovercrowded = true;
168173
return sock->Write(&out, &wopt);
169174
}

src/brpc/policy/streaming_rpc_protocol.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
#ifndef BRPC_STREAMING_RPC_PROTOCOL_H
2020
#define BRPC_STREAMING_RPC_PROTOCOL_H
2121

22+
#include "bthread/types.h"
2223
#include "brpc/protocol.h"
2324
#include "brpc/streaming_rpc_meta.pb.h"
2425

25-
2626
namespace brpc {
2727
namespace policy {
2828

@@ -41,7 +41,8 @@ void SendStreamClose(Socket *sock, int64_t remote_stream_id,
4141
int64_t source_stream_id);
4242

4343
int SendStreamData(Socket* sock, const butil::IOBuf* data,
44-
int64_t remote_stream_id, int64_t source_stream_id);
44+
int64_t remote_stream_id, int64_t source_stream_id,
45+
bthread_id_t);
4546

4647
} // namespace policy
4748
} // namespace brpc

0 commit comments

Comments
 (0)