From 0e4de42be87ddce5ad9dcdd1f4438acc100d11b5 Mon Sep 17 00:00:00 2001 From: Miguel Portilla Date: Wed, 19 Nov 2014 20:34:23 -0500 Subject: [PATCH] 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. --- Builds/VisualStudio2013/RippleD.vcxproj | 5 ++ .../VisualStudio2013/RippleD.vcxproj.filters | 6 ++ src/ripple/app/main/Application.cpp | 8 +-- src/ripple/app/websocket/WSConnection.cpp | 2 +- src/ripple/app/websocket/WSConnection.h | 8 +++ src/ripple/app/websocket/WSDoor.cpp | 10 ++-- src/ripple/app/websocket/WSDoor.h | 2 +- src/ripple/app/websocket/WSServerHandler.h | 31 +++++++++- src/ripple/nodestore/ScopedMetrics.h | 52 ++++++++++++++++ src/ripple/nodestore/impl/DatabaseImp.h | 3 + src/ripple/nodestore/impl/ScopedMetrics.cpp | 59 +++++++++++++++++++ src/ripple/rpc/Context.h | 2 + src/ripple/server/impl/ServerHandlerImp.cpp | 26 ++++++-- src/ripple/server/impl/ServerHandlerImp.h | 7 ++- src/ripple/server/make_ServerHandler.h | 3 +- src/ripple/unity/nodestore.cpp | 1 + 16 files changed, 206 insertions(+), 19 deletions(-) create mode 100644 src/ripple/nodestore/ScopedMetrics.h create mode 100644 src/ripple/nodestore/impl/ScopedMetrics.cpp diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 8031d9ade..02920617c 100755 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2560,6 +2560,9 @@ True + + True + @@ -2568,6 +2571,8 @@ + + diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 6726fc089..532cc2966 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -3654,6 +3654,9 @@ ripple\nodestore\impl + + ripple\nodestore\impl + ripple\nodestore\impl @@ -3666,6 +3669,9 @@ ripple\nodestore + + ripple\nodestore + ripple\nodestore diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index bf2f03b1a..54ef26637 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -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 [" << diff --git a/src/ripple/app/websocket/WSConnection.cpp b/src/ripple/app/websocket/WSConnection.cpp index c0041d09b..bf9447fcc 100644 --- a/src/ripple/app/websocket/WSConnection.cpp +++ b/src/ripple/app/websocket/WSConnection.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include namespace ripple { @@ -177,6 +176,7 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) jvRequest, loadType, m_netOPs, role, std::dynamic_pointer_cast (this->shared_from_this ())}; RPC::doCommand (context, jvResult[jss::result]); + recordMetrics (context); } getConsumer().charge (loadType); diff --git a/src/ripple/app/websocket/WSConnection.h b/src/ripple/app/websocket/WSConnection.h index 98c2ca0d8..96e46b3aa 100644 --- a/src/ripple/app/websocket/WSConnection.h +++ b/src/ripple/app/websocket/WSConnection.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,8 @@ protected: virtual void preDestroy () = 0; virtual void disconnect () = 0; + + virtual void recordMetrics (RPC::Context const&) const = 0; public: void onPong (std::string const&); @@ -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) { diff --git a/src/ripple/app/websocket/WSDoor.cpp b/src/ripple/app/websocket/WSDoor.cpp index 15246f43d..a21037cca 100644 --- a/src/ripple/app/websocket/WSDoor.cpp +++ b/src/ripple/app/websocket/WSDoor.cpp @@ -57,15 +57,17 @@ private: InfoSub::Source& m_source; LockType m_endpointLock; std::shared_ptr 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(port)) , m_resourceManager (resourceManager) , m_source (source) + , collectorManager_ (cm) { startThread (); } @@ -85,7 +87,7 @@ private: websocketpp_02::server_autotls::handler::ptr handler ( new WSServerHandler ( - 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 make_WSDoor (HTTP::Port const& port, Resource::Manager& resourceManager, - InfoSub::Source& source) + InfoSub::Source& source, CollectorManager& cm) { std::unique_ptr door; try { - door = std::make_unique (port, resourceManager, source); + door = std::make_unique (port, resourceManager, source, cm); } catch (...) { diff --git a/src/ripple/app/websocket/WSDoor.h b/src/ripple/app/websocket/WSDoor.h index fc2c41214..d93810acf 100644 --- a/src/ripple/app/websocket/WSDoor.h +++ b/src/ripple/app/websocket/WSDoor.h @@ -42,7 +42,7 @@ public: std::unique_ptr make_WSDoor (HTTP::Port const& port, Resource::Manager& resourceManager, - InfoSub::Source& source); + InfoSub::Source& source, CollectorManager& cm); } diff --git a/src/ripple/app/websocket/WSServerHandler.h b/src/ripple/app/websocket/WSServerHandler.h index c5185d7c4..2e4df6f2e 100644 --- a/src/ripple/app/websocket/WSServerHandler.h +++ b/src/ripple/app/websocket/WSServerHandler.h @@ -69,6 +69,10 @@ private: std::shared_ptr 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 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; @@ -426,8 +436,17 @@ public: if (jCmd.isString()) 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 ( + std::chrono::duration_cast ( + std::chrono::high_resolution_clock::now () - start))); + ++rpc_requests_; + rpc_size_.notify (static_cast + (buffer.size ())); + send (cpClient, buffer, false); } return true; @@ -470,6 +489,12 @@ public: " Test

This page shows http(s) connectivity is working.

"); return true; } + + void recordMetrics (RPC::Context const& context) const + { + rpc_io_.notify (static_cast ( + context.metrics.fetches)); + } }; } // ripple diff --git a/src/ripple/nodestore/ScopedMetrics.h b/src/ripple/nodestore/ScopedMetrics.h new file mode 100644 index 000000000..0d5631a2e --- /dev/null +++ b/src/ripple/nodestore/ScopedMetrics.h @@ -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 + +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 diff --git a/src/ripple/nodestore/impl/DatabaseImp.h b/src/ripple/nodestore/impl/DatabaseImp.h index 7775f9f12..e3a45a05b 100644 --- a/src/ripple/nodestore/impl/DatabaseImp.h +++ b/src/ripple/nodestore/impl/DatabaseImp.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -167,6 +168,8 @@ public: NodeObject::Ptr fetch (uint256 const& hash) override { + ScopedMetrics::incrementThreadFetches (); + return doTimedFetch (hash, false); } diff --git a/src/ripple/nodestore/impl/ScopedMetrics.cpp b/src/ripple/nodestore/impl/ScopedMetrics.cpp new file mode 100644 index 000000000..939ad6535 --- /dev/null +++ b/src/ripple/nodestore/impl/ScopedMetrics.cpp @@ -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 +#include + +namespace ripple { +namespace NodeStore { + +static +void +cleanup (ScopedMetrics*) +{ +} + +static +boost::thread_specific_ptr 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; +} + +} +} diff --git a/src/ripple/rpc/Context.h b/src/ripple/rpc/Context.h index 59fbaaa1d..5cba92b3d 100644 --- a/src/ripple/rpc/Context.h +++ b/src/ripple/rpc/Context.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace ripple { @@ -40,6 +41,7 @@ struct Context Role role; InfoSub::pointer infoSub; RPC::Yield yield; + NodeStore::ScopedMetrics metrics; }; } // RPC diff --git a/src/ripple/server/impl/ServerHandlerImp.cpp b/src/ripple/server/impl/ServerHandlerImp.cpp index 42267f41e..8753f943d 100644 --- a/src/ripple/server/impl/ServerHandlerImp.cpp +++ b/src/ripple/server/impl/ServerHandlerImp.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include // #include #include @@ -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 ( + std::chrono::duration_cast ( + std::chrono::high_resolution_clock::now () - start))); + ++rpc_requests_; + rpc_io_.notify (static_cast ( + context.metrics.fetches)); + rpc_size_.notify (static_cast ( + response.size ())); + response += '\n'; usage.charge (loadType); @@ -814,11 +831,12 @@ setup_ServerHandler (BasicConfig const& config, std::ostream& log) std::unique_ptr make_ServerHandler (beast::Stoppable& parent, - boost::asio::io_service& io_service, JobQueue& jobQueue, - NetworkOPs& networkOPs, Resource::Manager& resourceManager) + boost::asio::io_service& io_service, JobQueue& jobQueue, + NetworkOPs& networkOPs, Resource::Manager& resourceManager, + CollectorManager& cm) { return std::make_unique (parent, io_service, - jobQueue, networkOPs, resourceManager); + jobQueue, networkOPs, resourceManager, cm); } } diff --git a/src/ripple/server/impl/ServerHandlerImp.h b/src/ripple/server/impl/ServerHandlerImp.h index ccca56c1b..36aa5d288 100644 --- a/src/ripple/server/impl/ServerHandlerImp.h +++ b/src/ripple/server/impl/ServerHandlerImp.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace ripple { @@ -41,11 +42,15 @@ private: NetworkOPs& m_networkOPs; std::unique_ptr 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(); diff --git a/src/ripple/server/make_ServerHandler.h b/src/ripple/server/make_ServerHandler.h index c1353ede7..b21468e08 100644 --- a/src/ripple/server/make_ServerHandler.h +++ b/src/ripple/server/make_ServerHandler.h @@ -33,7 +33,8 @@ class NetworkOPs; std::unique_ptr 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 diff --git a/src/ripple/unity/nodestore.cpp b/src/ripple/unity/nodestore.cpp index ee032dee3..da4a8281c 100644 --- a/src/ripple/unity/nodestore.cpp +++ b/src/ripple/unity/nodestore.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include