mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 13:35:54 +00:00
Add RPC metrics (RIPD-705)
Add metrics to record the number of RPC requests received. Record the number of node store fetches performed per request. Additionally record the byte size of each request response and measure the response time of each request in milliseconds. A new class, ScopedMetrics, uses the Boost Thead Local Storage mechanism to efficiently record NodeStore metrics within the same thread.
This commit is contained in:
committed by
Nik Bougalis
parent
4e389127b5
commit
0e4de42be8
@@ -2560,6 +2560,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\impl\NodeObject.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\impl\ScopedMetrics.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\Tuning.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Manager.h">
|
||||
@@ -2568,6 +2571,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Scheduler.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\ScopedMetrics.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Task.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\Backend.test.cpp">
|
||||
|
||||
@@ -3654,6 +3654,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\impl\NodeObject.cpp">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\impl\ScopedMetrics.cpp">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\Tuning.h">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClInclude>
|
||||
@@ -3666,6 +3669,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Scheduler.h">
|
||||
<Filter>ripple\nodestore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\ScopedMetrics.h">
|
||||
<Filter>ripple\nodestore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Task.h">
|
||||
<Filter>ripple\nodestore</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -311,9 +311,8 @@ public:
|
||||
// VFALCO NOTE LocalCredentials starts the deprecated UNL service
|
||||
, m_deprecatedUNL (make_UniqueNodeList (*m_jobQueue))
|
||||
|
||||
, serverHandler_ (make_ServerHandler (*m_networkOPs,
|
||||
get_io_service(), *m_jobQueue, *m_networkOPs,
|
||||
*m_resourceManager))
|
||||
, serverHandler_ (make_ServerHandler (*m_networkOPs, get_io_service (),
|
||||
*m_jobQueue, *m_networkOPs, *m_resourceManager, *m_collectorManager))
|
||||
|
||||
, m_sntpClient (SNTPClient::New (*this))
|
||||
|
||||
@@ -743,7 +742,8 @@ public:
|
||||
{
|
||||
if (! port.websockets())
|
||||
continue;
|
||||
auto door = make_WSDoor(port, *m_resourceManager, getOPs());
|
||||
auto door (make_WSDoor (port, *m_resourceManager, getOPs (),
|
||||
*m_collectorManager));
|
||||
if (door == nullptr)
|
||||
{
|
||||
m_journal.fatal << "Could not create Websocket for [" <<
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/server/Role.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -177,6 +176,7 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest)
|
||||
jvRequest, loadType, m_netOPs, role,
|
||||
std::dynamic_pointer_cast<InfoSub> (this->shared_from_this ())};
|
||||
RPC::doCommand (context, jvResult[jss::result]);
|
||||
recordMetrics (context);
|
||||
}
|
||||
|
||||
getConsumer().charge (loadType);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <ripple/server/Port.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/unity/websocket.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <beast/asio/placeholders.h>
|
||||
#include <memory>
|
||||
|
||||
@@ -60,6 +61,8 @@ protected:
|
||||
virtual void preDestroy () = 0;
|
||||
virtual void disconnect () = 0;
|
||||
|
||||
virtual void recordMetrics (RPC::Context const&) const = 0;
|
||||
|
||||
public:
|
||||
void onPong (std::string const&);
|
||||
void rcvMessage (message_ptr msg, bool& msgRejected, bool& runQueue);
|
||||
@@ -142,6 +145,11 @@ public:
|
||||
// Just discards the reference
|
||||
}
|
||||
|
||||
void recordMetrics (RPC::Context const& context) const override
|
||||
{
|
||||
m_serverHandler.recordMetrics (context);
|
||||
}
|
||||
|
||||
// Implement overridden functions from base class:
|
||||
void send (Json::Value const& jvObj, bool broadcast)
|
||||
{
|
||||
|
||||
@@ -57,15 +57,17 @@ private:
|
||||
InfoSub::Source& m_source;
|
||||
LockType m_endpointLock;
|
||||
std::shared_ptr<websocketpp_02::server_autotls> m_endpoint;
|
||||
CollectorManager& collectorManager_;
|
||||
|
||||
public:
|
||||
WSDoorImp (HTTP::Port const& port, Resource::Manager& resourceManager,
|
||||
InfoSub::Source& source)
|
||||
InfoSub::Source& source, CollectorManager& cm)
|
||||
: WSDoor (source)
|
||||
, Thread ("websocket")
|
||||
, port_(std::make_shared<HTTP::Port>(port))
|
||||
, m_resourceManager (resourceManager)
|
||||
, m_source (source)
|
||||
, collectorManager_ (cm)
|
||||
{
|
||||
startThread ();
|
||||
}
|
||||
@@ -85,7 +87,7 @@ private:
|
||||
|
||||
websocketpp_02::server_autotls::handler::ptr handler (
|
||||
new WSServerHandler <websocketpp_02::server_autotls> (
|
||||
port_, m_resourceManager, m_source));
|
||||
port_, m_resourceManager, m_source, collectorManager_));
|
||||
|
||||
{
|
||||
ScopedLockType lock (m_endpointLock);
|
||||
@@ -162,13 +164,13 @@ WSDoor::WSDoor (Stoppable& parent)
|
||||
|
||||
std::unique_ptr<WSDoor>
|
||||
make_WSDoor (HTTP::Port const& port, Resource::Manager& resourceManager,
|
||||
InfoSub::Source& source)
|
||||
InfoSub::Source& source, CollectorManager& cm)
|
||||
{
|
||||
std::unique_ptr<WSDoor> door;
|
||||
|
||||
try
|
||||
{
|
||||
door = std::make_unique <WSDoorImp> (port, resourceManager, source);
|
||||
door = std::make_unique <WSDoorImp> (port, resourceManager, source, cm);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
std::unique_ptr<WSDoor>
|
||||
make_WSDoor (HTTP::Port const& port, Resource::Manager& resourceManager,
|
||||
InfoSub::Source& source);
|
||||
InfoSub::Source& source, CollectorManager& cm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ private:
|
||||
std::shared_ptr<HTTP::Port> port_;
|
||||
Resource::Manager& m_resourceManager;
|
||||
InfoSub::Source& m_source;
|
||||
beast::insight::Counter rpc_requests_;
|
||||
beast::insight::Event rpc_io_;
|
||||
beast::insight::Event rpc_size_;
|
||||
beast::insight::Event rpc_time_;
|
||||
|
||||
protected:
|
||||
// VFALCO TODO Make this private.
|
||||
@@ -82,11 +86,17 @@ protected:
|
||||
|
||||
public:
|
||||
WSServerHandler (std::shared_ptr<HTTP::Port> const& port,
|
||||
Resource::Manager& resourceManager, InfoSub::Source& source)
|
||||
Resource::Manager& resourceManager, InfoSub::Source& source,
|
||||
CollectorManager& cm)
|
||||
: port_(port)
|
||||
, m_resourceManager (resourceManager)
|
||||
, m_source (source)
|
||||
{
|
||||
auto const& group (cm.group ("rpc"));
|
||||
rpc_requests_ = group->make_counter ("requests");
|
||||
rpc_io_ = group->make_event ("io");
|
||||
rpc_size_ = group->make_event ("size");
|
||||
rpc_time_ = group->make_event ("time");
|
||||
}
|
||||
|
||||
WSServerHandler(WSServerHandler const&) = delete;
|
||||
@@ -427,7 +437,16 @@ public:
|
||||
job.rename (std::string ("WSClient::") + jCmd.asString());
|
||||
}
|
||||
|
||||
send (cpClient, conn->invokeCommand (jvRequest), false);
|
||||
auto const start (std::chrono::high_resolution_clock::now ());
|
||||
Json::Value const jvObj (conn->invokeCommand (jvRequest));
|
||||
std::string const buffer (to_string (jvObj));
|
||||
rpc_time_.notify (static_cast <beast::insight::Event::value_type> (
|
||||
std::chrono::duration_cast <std::chrono::milliseconds> (
|
||||
std::chrono::high_resolution_clock::now () - start)));
|
||||
++rpc_requests_;
|
||||
rpc_size_.notify (static_cast <beast::insight::Event::value_type>
|
||||
(buffer.size ()));
|
||||
send (cpClient, buffer, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -470,6 +489,12 @@ public:
|
||||
" Test</h1><p>This page shows http(s) connectivity is working.</p></body></html>");
|
||||
return true;
|
||||
}
|
||||
|
||||
void recordMetrics (RPC::Context const& context) const
|
||||
{
|
||||
rpc_io_.notify (static_cast <beast::insight::Event::value_type> (
|
||||
context.metrics.fetches));
|
||||
}
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
52
src/ripple/nodestore/ScopedMetrics.h
Normal file
52
src/ripple/nodestore/ScopedMetrics.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_NODESTORE_SCOPEDMETRICS_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_SCOPEDMETRICS_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
|
||||
/** RAII observer to track NodeStore fetches made by the calling thread. */
|
||||
class ScopedMetrics
|
||||
{
|
||||
private:
|
||||
ScopedMetrics* prev_;
|
||||
|
||||
public:
|
||||
ScopedMetrics ();
|
||||
~ScopedMetrics ();
|
||||
|
||||
static
|
||||
ScopedMetrics*
|
||||
get ();
|
||||
|
||||
static
|
||||
void
|
||||
incrementThreadFetches ();
|
||||
|
||||
std::size_t fetches = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/seconds_clock.h>
|
||||
#include <beast/threads/Thread.h>
|
||||
#include <ripple/nodestore/ScopedMetrics.h>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <set>
|
||||
@@ -167,6 +168,8 @@ public:
|
||||
|
||||
NodeObject::Ptr fetch (uint256 const& hash) override
|
||||
{
|
||||
ScopedMetrics::incrementThreadFetches ();
|
||||
|
||||
return doTimedFetch (hash, false);
|
||||
}
|
||||
|
||||
|
||||
59
src/ripple/nodestore/impl/ScopedMetrics.cpp
Normal file
59
src/ripple/nodestore/impl/ScopedMetrics.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/nodestore/ScopedMetrics.h>
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
|
||||
static
|
||||
void
|
||||
cleanup (ScopedMetrics*)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
boost::thread_specific_ptr<ScopedMetrics> scopedMetricsPtr (&cleanup);
|
||||
|
||||
ScopedMetrics::ScopedMetrics () : prev_ (scopedMetricsPtr.get ())
|
||||
{
|
||||
scopedMetricsPtr.reset (this);
|
||||
}
|
||||
|
||||
ScopedMetrics::~ScopedMetrics ()
|
||||
{
|
||||
scopedMetricsPtr.reset (prev_);
|
||||
}
|
||||
|
||||
ScopedMetrics*
|
||||
ScopedMetrics::get ()
|
||||
{
|
||||
return scopedMetricsPtr.get ();
|
||||
}
|
||||
|
||||
void
|
||||
ScopedMetrics::incrementThreadFetches ()
|
||||
{
|
||||
if (scopedMetricsPtr.get ())
|
||||
++scopedMetricsPtr.get ()->fetches;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/net/InfoSub.h>
|
||||
#include <ripple/rpc/Yield.h>
|
||||
#include <ripple/server/Role.h>
|
||||
#include <ripple/nodestore/ScopedMetrics.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -40,6 +41,7 @@ struct Context
|
||||
Role role;
|
||||
InfoSub::pointer infoSub;
|
||||
RPC::Yield yield;
|
||||
NodeStore::ScopedMetrics metrics;
|
||||
};
|
||||
|
||||
} // RPC
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/Coroutine.h>
|
||||
#include <beast/crypto/base64.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <beast/cxx14/algorithm.h> // <algorithm>
|
||||
#include <beast/http/rfc2616.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -53,7 +54,8 @@ ServerHandler::ServerHandler (Stoppable& parent)
|
||||
|
||||
ServerHandlerImp::ServerHandlerImp (Stoppable& parent,
|
||||
boost::asio::io_service& io_service, JobQueue& jobQueue,
|
||||
NetworkOPs& networkOPs, Resource::Manager& resourceManager)
|
||||
NetworkOPs& networkOPs, Resource::Manager& resourceManager,
|
||||
CollectorManager& cm)
|
||||
: ServerHandler (parent)
|
||||
, m_resourceManager (resourceManager)
|
||||
, m_journal (deprecatedLogs().journal("Server"))
|
||||
@@ -62,6 +64,11 @@ ServerHandlerImp::ServerHandlerImp (Stoppable& parent,
|
||||
, m_server (HTTP::make_Server(
|
||||
*this, io_service, deprecatedLogs().journal("Server")))
|
||||
{
|
||||
auto const& group (cm.group ("rpc"));
|
||||
rpc_requests_ = group->make_counter ("requests");
|
||||
rpc_io_ = group->make_event ("io");
|
||||
rpc_size_ = group->make_event ("size");
|
||||
rpc_time_ = group->make_event ("time");
|
||||
}
|
||||
|
||||
ServerHandlerImp::~ServerHandlerImp()
|
||||
@@ -362,6 +369,7 @@ ServerHandlerImp::processRequest (
|
||||
WriteLog (lsTRACE, RPCHandler)
|
||||
<< "doRpcCommand:" << strMethod << ":" << params;
|
||||
|
||||
auto const start (std::chrono::high_resolution_clock::now ());
|
||||
RPC::Context context {params, loadType, m_networkOPs, role, nullptr, yield};
|
||||
std::string response;
|
||||
|
||||
@@ -393,6 +401,15 @@ ServerHandlerImp::processRequest (
|
||||
response = to_string (reply);
|
||||
}
|
||||
|
||||
rpc_time_.notify (static_cast <beast::insight::Event::value_type> (
|
||||
std::chrono::duration_cast <std::chrono::milliseconds> (
|
||||
std::chrono::high_resolution_clock::now () - start)));
|
||||
++rpc_requests_;
|
||||
rpc_io_.notify (static_cast <beast::insight::Event::value_type> (
|
||||
context.metrics.fetches));
|
||||
rpc_size_.notify (static_cast <beast::insight::Event::value_type> (
|
||||
response.size ()));
|
||||
|
||||
response += '\n';
|
||||
usage.charge (loadType);
|
||||
|
||||
@@ -815,10 +832,11 @@ setup_ServerHandler (BasicConfig const& config, std::ostream& log)
|
||||
std::unique_ptr <ServerHandler>
|
||||
make_ServerHandler (beast::Stoppable& parent,
|
||||
boost::asio::io_service& io_service, JobQueue& jobQueue,
|
||||
NetworkOPs& networkOPs, Resource::Manager& resourceManager)
|
||||
NetworkOPs& networkOPs, Resource::Manager& resourceManager,
|
||||
CollectorManager& cm)
|
||||
{
|
||||
return std::make_unique <ServerHandlerImp> (parent, io_service,
|
||||
jobQueue, networkOPs, resourceManager);
|
||||
jobQueue, networkOPs, resourceManager, cm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/server/Session.h>
|
||||
#include <ripple/rpc/Output.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/app/main/CollectorManager.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -41,11 +42,15 @@ private:
|
||||
NetworkOPs& m_networkOPs;
|
||||
std::unique_ptr<HTTP::Server> m_server;
|
||||
Setup setup_;
|
||||
beast::insight::Counter rpc_requests_;
|
||||
beast::insight::Event rpc_io_;
|
||||
beast::insight::Event rpc_size_;
|
||||
beast::insight::Event rpc_time_;
|
||||
|
||||
public:
|
||||
ServerHandlerImp (Stoppable& parent, boost::asio::io_service& io_service,
|
||||
JobQueue& jobQueue, NetworkOPs& networkOPs,
|
||||
Resource::Manager& resourceManager);
|
||||
Resource::Manager& resourceManager, CollectorManager& cm);
|
||||
|
||||
~ServerHandlerImp();
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ class NetworkOPs;
|
||||
|
||||
std::unique_ptr <ServerHandler>
|
||||
make_ServerHandler (beast::Stoppable& parent, boost::asio::io_service& io_service,
|
||||
JobQueue& jobQueue, NetworkOPs& networkOPs, Resource::Manager& resourceManager);
|
||||
JobQueue& jobQueue, NetworkOPs& networkOPs, Resource::Manager& resourceManager,
|
||||
CollectorManager& cm);
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <ripple/nodestore/impl/EncodedBlob.cpp>
|
||||
#include <ripple/nodestore/impl/ManagerImp.cpp>
|
||||
#include <ripple/nodestore/impl/NodeObject.cpp>
|
||||
#include <ripple/nodestore/impl/ScopedMetrics.cpp>
|
||||
|
||||
#include <ripple/nodestore/tests/Backend.test.cpp>
|
||||
#include <ripple/nodestore/tests/Basics.test.cpp>
|
||||
|
||||
Reference in New Issue
Block a user