mirror of
https://github.com/wassname/ray.git
synced 2026-08-16 11:27:09 +08:00
Remove raylet monitor after use GCS service (#9179)
This commit is contained in:
@@ -239,7 +239,5 @@ std::string TEST_GCS_SERVER_EXEC_PATH;
|
||||
std::string TEST_RAYLET_EXEC_PATH;
|
||||
/// Path to mock worker executable binary. Required by raylet.
|
||||
std::string TEST_MOCK_WORKER_EXEC_PATH;
|
||||
/// Path to raylet monitor executable binary.
|
||||
std::string TEST_RAYLET_MONITOR_EXEC_PATH;
|
||||
|
||||
} // namespace ray
|
||||
|
||||
@@ -75,8 +75,6 @@ extern std::string TEST_GCS_SERVER_EXEC_PATH;
|
||||
extern std::string TEST_RAYLET_EXEC_PATH;
|
||||
/// Path to mock worker executable binary. Required by raylet.
|
||||
extern std::string TEST_MOCK_WORKER_EXEC_PATH;
|
||||
/// Path to raylet monitor executable binary.
|
||||
extern std::string TEST_RAYLET_MONITOR_EXEC_PATH;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// COMPONENT MANAGEMENT CLASSES FOR TEST CASES
|
||||
|
||||
@@ -895,7 +895,7 @@ TEST_F(TwoNodeTest, TestActorTaskCrossNodesFailure) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RAY_CHECK(argc == 9);
|
||||
RAY_CHECK(argc == 8);
|
||||
ray::TEST_STORE_EXEC_PATH = std::string(argv[1]);
|
||||
ray::TEST_RAYLET_EXEC_PATH = std::string(argv[2]);
|
||||
|
||||
@@ -904,12 +904,11 @@ int main(int argc, char **argv) {
|
||||
std::uniform_int_distribution<int> random_gen{2000, 2009};
|
||||
// Use random port to avoid port conflicts between UTs.
|
||||
node_manager_port = random_gen(gen);
|
||||
ray::TEST_RAYLET_MONITOR_EXEC_PATH = std::string(argv[3]);
|
||||
ray::TEST_MOCK_WORKER_EXEC_PATH = std::string(argv[4]);
|
||||
ray::TEST_GCS_SERVER_EXEC_PATH = std::string(argv[5]);
|
||||
ray::TEST_MOCK_WORKER_EXEC_PATH = std::string(argv[3]);
|
||||
ray::TEST_GCS_SERVER_EXEC_PATH = std::string(argv[4]);
|
||||
|
||||
ray::TEST_REDIS_CLIENT_EXEC_PATH = std::string(argv[6]);
|
||||
ray::TEST_REDIS_SERVER_EXEC_PATH = std::string(argv[7]);
|
||||
ray::TEST_REDIS_MODULE_LIBRARY_PATH = std::string(argv[8]);
|
||||
ray::TEST_REDIS_CLIENT_EXEC_PATH = std::string(argv[5]);
|
||||
ray::TEST_REDIS_SERVER_EXEC_PATH = std::string(argv[6]);
|
||||
ray::TEST_REDIS_MODULE_LIBRARY_PATH = std::string(argv[7]);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ray/raylet/monitor.h"
|
||||
|
||||
#include "ray/common/ray_config.h"
|
||||
#include "ray/common/status.h"
|
||||
#include "ray/gcs/pb_util.h"
|
||||
#include "ray/util/util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace raylet {
|
||||
|
||||
/// \class Monitor
|
||||
///
|
||||
/// The monitor is responsible for listening for heartbeats from Raylets and
|
||||
/// deciding when a Raylet has died. If the monitor does not hear from a Raylet
|
||||
/// within heartbeat_timeout_milliseconds * num_heartbeats_timeout (defined in
|
||||
/// the Ray configuration), then the monitor will mark that Raylet as dead in
|
||||
/// the client table, which broadcasts the event to all other Raylets.
|
||||
Monitor::Monitor(boost::asio::io_service &io_service,
|
||||
const gcs::GcsClientOptions &gcs_client_options)
|
||||
: gcs_client_(new gcs::RedisGcsClient(gcs_client_options)),
|
||||
num_heartbeats_timeout_(RayConfig::instance().num_heartbeats_timeout()),
|
||||
heartbeat_timer_(io_service) {
|
||||
RAY_CHECK_OK(gcs_client_->Connect(io_service));
|
||||
}
|
||||
|
||||
void Monitor::HandleHeartbeat(const ClientID &node_id,
|
||||
const HeartbeatTableData &heartbeat_data) {
|
||||
heartbeats_[node_id] = num_heartbeats_timeout_;
|
||||
heartbeat_buffer_[node_id] = heartbeat_data;
|
||||
}
|
||||
|
||||
void Monitor::Start() {
|
||||
const auto heartbeat_callback = [this](const ClientID &id,
|
||||
const HeartbeatTableData &heartbeat_data) {
|
||||
HandleHeartbeat(id, heartbeat_data);
|
||||
};
|
||||
RAY_CHECK_OK(gcs_client_->Nodes().AsyncSubscribeHeartbeat(heartbeat_callback, nullptr));
|
||||
Tick();
|
||||
}
|
||||
|
||||
/// A periodic timer that checks for timed out clients.
|
||||
void Monitor::Tick() {
|
||||
for (auto it = heartbeats_.begin(); it != heartbeats_.end();) {
|
||||
it->second--;
|
||||
if (it->second == 0) {
|
||||
if (dead_nodes_.count(it->first) == 0) {
|
||||
auto node_id = it->first;
|
||||
RAY_LOG(WARNING) << "Node timed out: " << node_id;
|
||||
auto lookup_callback = [this, node_id](Status status,
|
||||
const std::vector<GcsNodeInfo> &all_node) {
|
||||
RAY_CHECK(status.ok()) << status.CodeAsString();
|
||||
bool marked = false;
|
||||
for (const auto &node : all_node) {
|
||||
if (node_id.Binary() == node.node_id() && node.state() == GcsNodeInfo::DEAD) {
|
||||
// The node has been marked dead by itself.
|
||||
marked = true;
|
||||
}
|
||||
}
|
||||
if (!marked) {
|
||||
RAY_CHECK_OK(
|
||||
gcs_client_->Nodes().AsyncUnregister(node_id, /* callback */ nullptr));
|
||||
// Broadcast a warning to all of the drivers indicating that the node
|
||||
// has been marked as dead.
|
||||
// TODO(rkn): Define this constant somewhere else.
|
||||
std::string type = "node_removed";
|
||||
std::ostringstream error_message;
|
||||
error_message << "The node with client ID " << node_id
|
||||
<< " has been marked dead because the monitor"
|
||||
<< " has missed too many heartbeats from it.";
|
||||
auto error_data_ptr =
|
||||
gcs::CreateErrorTableData(type, error_message.str(), current_time_ms());
|
||||
RAY_CHECK_OK(
|
||||
gcs_client_->Errors().AsyncReportJobError(error_data_ptr, nullptr));
|
||||
}
|
||||
};
|
||||
RAY_CHECK_OK(gcs_client_->Nodes().AsyncGetAll(lookup_callback));
|
||||
dead_nodes_.insert(node_id);
|
||||
}
|
||||
it = heartbeats_.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// Send any buffered heartbeats as a single publish.
|
||||
if (!heartbeat_buffer_.empty()) {
|
||||
auto batch = std::make_shared<HeartbeatBatchTableData>();
|
||||
for (const auto &heartbeat : heartbeat_buffer_) {
|
||||
batch->add_batch()->CopyFrom(heartbeat.second);
|
||||
}
|
||||
RAY_CHECK_OK(gcs_client_->Nodes().AsyncReportBatchHeartbeat(batch, nullptr));
|
||||
heartbeat_buffer_.clear();
|
||||
}
|
||||
|
||||
auto heartbeat_period = boost::posix_time::milliseconds(
|
||||
RayConfig::instance().raylet_heartbeat_timeout_milliseconds());
|
||||
heartbeat_timer_.expires_from_now(heartbeat_period);
|
||||
heartbeat_timer_.async_wait([this](const boost::system::error_code &error) {
|
||||
RAY_CHECK(!error);
|
||||
Tick();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace raylet
|
||||
|
||||
} // namespace ray
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/gcs/redis_gcs_client.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace raylet {
|
||||
|
||||
using rpc::GcsNodeInfo;
|
||||
using rpc::HeartbeatBatchTableData;
|
||||
using rpc::HeartbeatTableData;
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
/// Create a Raylet monitor attached to the given GCS address and port.
|
||||
///
|
||||
/// \param io_service The event loop to run the monitor on.
|
||||
/// \param redis_address The GCS Redis address to connect to.
|
||||
/// \param redis_port The GCS Redis port to connect to.
|
||||
Monitor(boost::asio::io_service &io_service,
|
||||
const gcs::GcsClientOptions &gcs_client_options);
|
||||
|
||||
/// Start the monitor. Listen for heartbeats from Raylets and mark Raylets
|
||||
/// that do not send a heartbeat within a given period as dead.
|
||||
void Start();
|
||||
|
||||
/// A periodic timer that fires on every heartbeat period. Raylets that have
|
||||
/// not sent a heartbeat within the last num_heartbeats_timeout ticks will be
|
||||
/// marked as dead in the client table.
|
||||
void Tick();
|
||||
|
||||
/// Handle a heartbeat from a Raylet.
|
||||
///
|
||||
/// \param client_id The client ID of the Raylet that sent the heartbeat.
|
||||
/// \param heartbeat_data The heartbeat sent by the client.
|
||||
void HandleHeartbeat(const ClientID &client_id,
|
||||
const HeartbeatTableData &heartbeat_data);
|
||||
|
||||
private:
|
||||
/// A client to the GCS, through which heartbeats are received.
|
||||
std::unique_ptr<gcs::GcsClient> gcs_client_;
|
||||
/// The number of heartbeats that can be missed before a client is removed.
|
||||
int64_t num_heartbeats_timeout_;
|
||||
/// A timer that ticks every heartbeat_timeout_ms_ milliseconds.
|
||||
boost::asio::deadline_timer heartbeat_timer_;
|
||||
/// For each Raylet that we receive a heartbeat from, the number of ticks
|
||||
/// that may pass before the Raylet will be declared dead.
|
||||
std::unordered_map<ClientID, int64_t> heartbeats_;
|
||||
/// The Raylets that have been marked as dead in gcs.
|
||||
std::unordered_set<ClientID> dead_nodes_;
|
||||
/// A buffer containing heartbeats received from node managers in the last tick.
|
||||
std::unordered_map<ClientID, HeartbeatTableData> heartbeat_buffer_;
|
||||
};
|
||||
|
||||
} // namespace raylet
|
||||
|
||||
} // namespace ray
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "ray/common/ray_config.h"
|
||||
#include "ray/raylet/monitor.h"
|
||||
#include "ray/util/util.h"
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
DEFINE_string(redis_address, "", "The ip address of redis.");
|
||||
DEFINE_int32(redis_port, -1, "The port of redis.");
|
||||
DEFINE_string(config_list, "", "The config list of raylet.");
|
||||
DEFINE_string(redis_password, "", "The password of redis.");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
InitShutdownRAII ray_log_shutdown_raii(ray::RayLog::StartRayLog,
|
||||
ray::RayLog::ShutDownRayLog, argv[0],
|
||||
ray::RayLogLevel::INFO, /*log_dir=*/"");
|
||||
ray::RayLog::InstallFailureSignalHandler();
|
||||
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
const std::string redis_address = FLAGS_redis_address;
|
||||
const int redis_port = static_cast<int>(FLAGS_redis_port);
|
||||
const std::string config_list = FLAGS_config_list;
|
||||
const std::string redis_password = FLAGS_redis_password;
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
|
||||
ray::gcs::GcsClientOptions gcs_client_options(redis_address, redis_port,
|
||||
redis_password);
|
||||
|
||||
std::unordered_map<std::string, std::string> raylet_config;
|
||||
|
||||
// Parse the configuration list.
|
||||
std::istringstream config_string(config_list);
|
||||
std::string config_name;
|
||||
std::string config_value;
|
||||
|
||||
while (std::getline(config_string, config_name, ',')) {
|
||||
RAY_CHECK(std::getline(config_string, config_value, ','));
|
||||
// TODO(rkn): The line below could throw an exception. What should we do about this?
|
||||
raylet_config[config_name] = config_value;
|
||||
}
|
||||
|
||||
RayConfig::instance().initialize(raylet_config);
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
// The code below is commented out because it appears to introduce a double
|
||||
// free error in the raylet monitor.
|
||||
// // Destroy the Raylet monitor on a SIGTERM. The pointer to io_service is
|
||||
// // guaranteed to be valid since this function will run the event loop
|
||||
// // instead of returning immediately.
|
||||
// auto handler = [&io_service](const boost::system::error_code &error,
|
||||
// int signal_number) { io_service.stop(); };
|
||||
// boost::asio::signal_set signals(io_service);
|
||||
// #ifdef _WIN32
|
||||
// signals.add(SIGBREAK);
|
||||
// #else
|
||||
// signals.add(SIGTERM);
|
||||
// #endif
|
||||
// signals.async_wait(handler);
|
||||
|
||||
// Initialize the monitor.
|
||||
ray::raylet::Monitor monitor(io_service, gcs_client_options);
|
||||
monitor.Start();
|
||||
io_service.run();
|
||||
}
|
||||
Reference in New Issue
Block a user