Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simulation for load balancing logic. #127

Merged
merged 7 commits into from
Oct 7, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ add_executable(envoy-test
common/upstream/health_checker_impl_test.cc
common/upstream/host_utility_test.cc
common/upstream/load_balancer_impl_test.cc
common/upstream/load_balancer_simulation_test.cc
common/upstream/logical_dns_cluster_test.cc
common/upstream/resource_manager_impl_test.cc
common/upstream/sds_test.cc
Expand Down
126 changes: 126 additions & 0 deletions test/common/upstream/load_balancer_simulation_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "common/runtime/runtime_impl.h"
#include "common/upstream/load_balancer_impl.h"
#include "common/upstream/upstream_impl.h"

#include "test/mocks/runtime/mocks.h"
#include "test/mocks/upstream/mocks.h"

using testing::NiceMock;
using testing::Return;

namespace Upstream {

static HostPtr newTestHost(const Upstream::Cluster& cluster, const std::string& url,
uint32_t weight = 1, const std::string& zone = "") {
return HostPtr{new HostImpl(cluster, url, false, weight, zone)};
}

/**
* This test is for simulation only and should not be run as part of unit tests.
*/
class DISABLED_SimulationTest : public testing::Test {
public:
DISABLED_SimulationTest() : stats_(ClusterImplBase::generateStats("", stats_store_)) {}

/**
* @param originating_cluster total number of hosts in each zone in originating cluster.
* @param all_destination_cluster total number of hosts in each zone in upstream cluster.
* @param healthy_destination_cluster total number of healthy hosts in each zone in upstream
* cluster.
*/
void run(std::vector<uint32_t> originating_cluster, std::vector<uint32_t> all_destination_cluster,
std::vector<uint32_t> healthy_destination_cluster) {
setupRuntime();
stats_.upstream_zone_count_.set(all_destination_cluster.size());

std::unordered_map<std::string, std::vector<HostPtr>> healthy_map =
generateMap(healthy_destination_cluster);
std::unordered_map<std::string, std::vector<HostPtr>> all_map =
generateMap(all_destination_cluster);

std::vector<HostPtr> originatingHosts = generateList(originating_cluster);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

originatingHosts naming

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

cluster_.healthy_hosts_ = generateList(healthy_destination_cluster);
cluster_.hosts_ = generateList(all_destination_cluster);

std::map<std::string, uint32_t> hits;
for (uint32_t i = 0; i < total_number_of_requests; ++i) {
HostPtr from_host = selectOriginatingHost(originatingHosts);

cluster_.local_zone_hosts_ = all_map[from_host->zone()];
cluster_.local_zone_healthy_hosts_ = healthy_map[from_host->zone()];

ConstHostPtr selected = lb_.chooseHost();
hits[selected->url()]++;
}

for (const auto& host_hit_num_pair : hits) {
std::cout << fmt::format("url:{}, hits:{}", host_hit_num_pair.first, host_hit_num_pair.second)
<< std::endl;
}
}

HostPtr selectOriginatingHost(const std::vector<HostPtr>& hosts) {
// Originating cluster should have roughly the same per host request distribution.
return hosts[random_.random() % hosts.size()];
}

std::vector<HostPtr> generateList(const std::vector<uint32_t>& hosts) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better name and function comment, what does this do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

std::vector<HostPtr> ret;
for (size_t i = 0; i < hosts.size(); ++i) {
const std::string zone = std::to_string(i);
for (uint32_t j = 0; j < hosts[i]; ++j) {
const std::string url = fmt::format("tcp://host.{}.{}:80", i, j);
ret.push_back(newTestHost(cluster_, url, 1, zone));
}
}

return ret;
}

std::unordered_map<std::string, std::vector<HostPtr>>
generateMap(const std::vector<uint32_t>& hosts) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better name and function comment, what does this do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

std::unordered_map<std::string, std::vector<HostPtr>> ret;
for (size_t i = 0; i < hosts.size(); ++i) {
const std::string zone = std::to_string(i);
std::vector<HostPtr> zone_hosts;

for (uint32_t j = 0; j < hosts[i]; ++j) {
const std::string url = fmt::format("tcp://host.{}.{}:80", i, j);
zone_hosts.push_back(newTestHost(cluster_, url, 1, zone));
}

ret.insert({zone, std::move(zone_hosts)});
}

return ret;
};

void setupRuntime() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do in constructor

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I actually meant just run this code in the constructor, you don't need the setupRuntime() function at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, ok, moving there

ON_CALL(runtime_.snapshot_, getInteger("upstream.healthy_panic_threshold", 50U))
.WillByDefault(Return(50U));
ON_CALL(runtime_.snapshot_, featureEnabled("upstream.zone_routing.enabled", 100))
.WillByDefault(Return(true));
ON_CALL(runtime_.snapshot_, getInteger("upstream.zone_routing.percent_diff", 3))
.WillByDefault(Return(3));
}

const uint32_t total_number_of_requests = 100000;

NiceMock<MockCluster> cluster_;
NiceMock<Runtime::MockLoader> runtime_;
Runtime::RandomGeneratorImpl random_;
Stats::IsolatedStoreImpl stats_store_;
ClusterStats stats_;
// TODO: make per originating host load balancer.
RandomLoadBalancer lb_{cluster_, stats_, runtime_, random_};
};

TEST_F(DISABLED_SimulationTest, strictlyEqualDistribution) {
run({1U, 1U, 1U}, {3U, 3U, 3U}, {3U, 3U, 3U});
}

TEST_F(DISABLED_SimulationTest, unequalZoneDistribution) {
run({1U, 1U, 1U}, {5U, 5U, 6U}, {5U, 5U, 6U});
}

} // Upstream