From ad45897d8b46b8ab59586f264d22ee3250f707c3 Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Mon, 22 Feb 2021 21:32:47 +0100 Subject: [PATCH 1/6] Add Rack awareness support --- src/riak_core_claim.erl | 38 +++++-- src/riak_core_claimant.erl | 38 +++++-- src/riak_core_cluster_cli.erl | 67 ++++++++++-- src/riak_core_console.erl | 22 +++- src/riak_core_location.erl | 53 +++++++++ src/riak_core_ring.erl | 26 +++++ test/rack_awareness_test.erl | 196 ++++++++++++++++++++++++++++++++++ 7 files changed, 414 insertions(+), 26 deletions(-) create mode 100644 src/riak_core_location.erl create mode 100644 test/rack_awareness_test.erl diff --git a/src/riak_core_claim.erl b/src/riak_core_claim.erl index e40247c0d..f205698db 100644 --- a/src/riak_core_claim.erl +++ b/src/riak_core_claim.erl @@ -187,7 +187,12 @@ wants_claim_v2(Ring, Node) -> Count = proplists:get_value(Node, Counts, 0), case Count < Avg of false -> - no; + case riak_core_ring:has_location_changed(Ring) of + true -> + {yes, 1}; + false -> + no + end; true -> {yes, Avg - Count} end. @@ -289,7 +294,8 @@ choose_claim_v2(Ring, Node) -> Params = default_choose_params(), choose_claim_v2(Ring, Node, Params). -choose_claim_v2(Ring, Node, Params0) -> +choose_claim_v2(RingOrig, Node, Params0) -> + Ring = riak_core_ring:clear_location_changed(RingOrig), Params = default_choose_params(Params0), %% Active::[node()] Active = riak_core_ring:claiming_members(Ring), @@ -326,7 +332,8 @@ choose_claim_v2(Ring, Node, Params0) -> %% number of indices desired is less than the computed set. Padding = lists:duplicate(TargetN, undefined), Expanded = lists:sublist(Active ++ Padding, TargetN), - PreferredClaim = riak_core_claim:diagonal_stripe(Ring, Expanded), + ExpandedLocation = get_nodes_by_location(Expanded, Ring), + PreferredClaim = riak_core_claim:diagonal_stripe(Ring, ExpandedLocation), PreferredNth = [begin {Nth, Idx} = lists:keyfind(Idx, 2, AllIndices), Nth @@ -343,8 +350,10 @@ choose_claim_v2(Ring, Node, Params0) -> Indices2 = prefilter_violations(Ring, Node, AllIndices, Indices, TargetN, RingSize), %% Claim indices from the remaining candidate set - Claim = select_indices(Owners, Deltas, Indices2, TargetN, RingSize), - Claim2 = lists:sublist(Claim, Want), + Claim2 = case select_indices(Owners, Deltas, Indices2, TargetN, RingSize) of + [] -> []; + Claim -> lists:sublist(Claim, Want) + end, NewRing = lists:foldl(fun(Idx, Ring0) -> riak_core_ring:transfer_node(Idx, Node, Ring0) end, Ring, Claim2), @@ -622,7 +631,8 @@ claim_diagonal(Wants, Owners, Params) -> riak_core_ring:riak_core_ring(). sequential_claim(Ring0, Node, TargetN) -> Ring = riak_core_ring:upgrade(Ring0), - Nodes = lists:usort([Node|riak_core_ring:claiming_members(Ring)]), + OrigNodes = lists:usort([Node|riak_core_ring:claiming_members(Ring)]), + Nodes = get_nodes_by_location(OrigNodes, Ring), NodeCount = length(Nodes), RingSize = riak_core_ring:num_partitions(Ring), @@ -709,7 +719,8 @@ backfill_ring(RingSize, Nodes, Remaining, Acc) -> claim_rebalance_n(Ring0, Node) -> Ring = riak_core_ring:upgrade(Ring0), - Nodes = lists:usort([Node|riak_core_ring:claiming_members(Ring)]), + OrigNodes = lists:usort([Node|riak_core_ring:claiming_members(Ring)]), + Nodes = get_nodes_by_location(OrigNodes, Ring), Zipped = diagonal_stripe(Ring, Nodes), lists:foldl(fun({P, N}, Acc) -> @@ -1270,6 +1281,19 @@ indices_within_n([This | Indices], TN, Last, Q, Acc) -> circular_distance(I1, I2, Q) -> min((Q + I1 - I2) rem Q, (Q + I2 - I1) rem Q). +%% @private +%% Get active nodes ordered by take location parameters into account +-spec get_nodes_by_location([node()|undefined], riak_core_ring:riak_core_ring()) -> + [node()|undefined]. +get_nodes_by_location(Nodes, Ring) -> + NodesLocations = riak_core_ring:get_nodes_locations(Ring), + case riak_core_location:has_location_set_in_cluster(NodesLocations) of + false -> + Nodes; + true -> + riak_core_location:stripe_nodes_by_location(Nodes, NodesLocations) + end. + %% =================================================================== %% Unit tests %% =================================================================== diff --git a/src/riak_core_claimant.erl b/src/riak_core_claimant.erl index 33ab44956..a02ecc0aa 100644 --- a/src/riak_core_claimant.erl +++ b/src/riak_core_claimant.erl @@ -42,7 +42,8 @@ activate_bucket_type/1, get_bucket_type/2, get_bucket_type/3, - bucket_type_iterator/0]). + bucket_type_iterator/0, + set_node_location/2]). -export([reassign_indices/1]). % helpers for claim sim %% gen_server callbacks @@ -52,7 +53,8 @@ -type action() :: leave | remove | {replace, node()} - | {force_replace, node()}. + | {force_replace, node()} + | {set_location, string()}. -type riak_core_ring() :: riak_core_ring:riak_core_ring(). @@ -164,6 +166,11 @@ abort_resize() -> pending_close(Ring, RingID) -> gen_server:call(?MODULE, {pending_close, Ring, RingID}). +%% @doc Stage a request to set a new location for the given node. +-spec set_node_location(node(), string()) -> ok | {error, atom()}. +set_node_location(Node, Location) -> + stage(Node, {set_location, Location}). + %% @doc Clear the current set of staged transfers clear() -> gen_server:call(claimant(), clear, infinity). @@ -446,8 +453,9 @@ maybe_commit_staged(Ring, NextRing, #state{next_ring=PlannedRing}) -> {_, _, false} -> {ignore, plan_changed}; _ -> - NewRing = riak_core_ring:increment_vclock(Claimant, NextRing), - {new_ring, NewRing} + NewRing0 = riak_core_ring:clear_location_changed(NextRing), + NewRing1 = riak_core_ring:increment_vclock(Claimant, NewRing0), + {new_ring, NewRing1} end. %% @private @@ -502,7 +510,9 @@ valid_request(Node, Action, Changes, Ring) -> {resize, NewRingSize} -> valid_resize_request(NewRingSize, Changes, Ring); abort_resize -> - valid_resize_abort_request(Ring) + valid_resize_abort_request(Ring); + {set_location, Location} -> + valid_set_location_request(Location, Node, Ring) end. %% @private @@ -615,6 +625,20 @@ valid_resize_abort_request(Ring) -> false -> {error, not_resizing} end. +%% @private +%% Validating node member status +valid_set_location_request(_Location, Node, Ring) -> + case riak_core_ring:member_status(Ring, Node) of + valid -> + true; + joining -> + true; + invalid -> + {error, not_member}; + _ -> + true + end. + %% @private %% @doc Filter out any staged changes that are no longer valid. Changes %% can become invalid based on other staged changes, or by cluster @@ -1094,7 +1118,9 @@ change({{force_replace, NewNode}, Node}, Ring) -> change({{resize, NewRingSize}, _Node}, Ring) -> riak_core_ring:resize(Ring, NewRingSize); change({abort_resize, _Node}, Ring) -> - riak_core_ring:set_pending_resize_abort(Ring). + riak_core_ring:set_pending_resize_abort(Ring); +change({{set_location, Location}, Node}, Ring) -> + riak_core_ring:set_node_location(Node, Location, Ring). internal_ring_changed(Node, CState) -> {Changed, CState5} = do_claimant(Node, CState, fun log/2), diff --git a/src/riak_core_cluster_cli.erl b/src/riak_core_cluster_cli.erl index 81bd929ef..48560741b 100644 --- a/src/riak_core_cluster_cli.erl +++ b/src/riak_core_cluster_cli.erl @@ -46,12 +46,15 @@ register_all_usage() -> clique:register_usage(["riak-admin", "cluster", "status"], status_usage()), clique:register_usage(["riak-admin", "cluster", "partition"], partition_usage()), clique:register_usage(["riak-admin", "cluster", "partitions"], partitions_usage()), - clique:register_usage(["riak-admin", "cluster", "partition_count"], partition_count_usage()). + clique:register_usage(["riak-admin", "cluster", "partition_count"], partition_count_usage()), + clique:register_usage(["riak-admin", "cluster", "partition_count"], partition_count_usage()), + clique:register_usage(["riak-admin", "cluster", "location"], location_usage()), + clique:register_usage(["riak-admin", "cluster", "location", '*'], location_usage()). register_all_commands() -> lists:foreach(fun(Args) -> apply(clique, register_command, Args) end, [status_register(), partition_count_register(), - partitions_register(), partition_register()]). + partitions_register(), partition_register(), location_register()]). %%% %% Cluster status @@ -72,6 +75,7 @@ cluster_usage() -> " partition Map partition IDs to indexes\n", " partitions Display partitions on a node\n", " partition-count Display ring size or node partition count\n\n", + " location Set node location\n\n", " Use --help after a sub-command for more details.\n" ]. @@ -111,12 +115,20 @@ status(_CmdBase, [], []) -> [T0,T1,Table,T2]. format_status(Node, Status, Ring, RingStatus) -> - {Claimant, _RingReady, Down, MarkedDown, Changes} = RingStatus, - [{node, is_claimant(Node, Claimant)}, - {status, Status}, - {avail, node_availability(Node, Down, MarkedDown)}, - {ring, claim_percent(Ring, Node)}, - {pending, future_claim_percentage(Changes, Ring, Node)}]. + NodesLocations = riak_core_ring:get_nodes_locations(Ring), + HasLocationInCluster = riak_core_location:has_location_set_in_cluster(NodesLocations), + format_status(Node, Status, Ring, RingStatus, HasLocationInCluster, NodesLocations). + +format_status(Node, Status, Ring, RingStatus, false, _) -> + {Claimant, _RingReady, Down, MarkedDown, Changes} = RingStatus, + [{node, is_claimant(Node, Claimant)}, + {status, Status}, + {avail, node_availability(Node, Down, MarkedDown)}, + {ring, claim_percent(Ring, Node)}, + {pending, future_claim_percentage(Changes, Ring, Node)}]; +format_status(Node, Status, Ring, RingStatus, true, NodesLocations) -> + Row = format_status(Node, Status, Ring, RingStatus, false, NodesLocations), + Row ++ [{location, riak_core_location:get_node_location(Node, NodesLocations)}]. is_claimant(Node, Node) -> " (C) " ++ atom_to_list(Node) ++ " "; @@ -263,6 +275,45 @@ id_out1(id, Id, Ring, RingSize) when Id < RingSize -> id_out1(id, Id, _Ring, _RingSize) -> make_alert(["ERROR: Id ", integer_to_list(Id), " is invalid."]). + +%%% +%% Location +%%% +location_usage() -> + ["riak-admin cluster location [--node node]\n\n", + " Set the node location parameter\n\n", + "Options\n", + " -n , --node \n", + " Set node location for the specified node.\n" + ]. + +location_register() -> + [["riak-admin", "cluster", "location", '*'], % Cmd + [], % KeySpecs + [{node, [{shortname, "n"}, {longname, "node"}, + {typecast, fun clique_typecast:to_node/1}]}], % FlagSpecs + fun stage_set_location/3]. % Implementation callback + +stage_set_location([_, _, _, Location], _, Flags) -> + Node = proplists:get_value(node, Flags, node()), + try + case riak_core_claimant:set_node_location(Node, Location) of + ok -> + [clique_status:text( + io_lib:format("Success: staged changing location of node ~p to ~s~n", + [Node, Location]))]; + {error, not_member} -> + make_alert( + io_lib:format("Failed: ~p is not a member of the cluster.~n", [Node]) + ) + end + catch + Exception:Reason -> + lager:error("Setting node location failed ~p:~p", [Exception, Reason]), + make_alert("Setting node location failed, see log for details~n") + end. + + %%% %% Internal %%% diff --git a/src/riak_core_console.erl b/src/riak_core_console.erl index cf8ff5400..c8f99ee0e 100644 --- a/src/riak_core_console.erl +++ b/src/riak_core_console.erl @@ -67,6 +67,7 @@ print_member_status(Ring, LegacyGossip) -> io:format("~79..-s~n", [""]), AllStatus = lists:keysort(2, riak_core_ring:all_member_status(Ring)), IsPending = ([] /= riak_core_ring:pending_changes(Ring)), + Locations = riak_core_ring:get_nodes_locations(Ring), {Joining, Valid, Down, Leaving, Exiting} = lists:foldl(fun({Node, Status}, @@ -78,15 +79,16 @@ print_member_status(Ring, LegacyGossip) -> {RingPercent, NextPercent} = pending_claim_percentage(Ring, Node), + DisplayNode = maybe_add_location(Node, Locations), case IsPending of true -> - io:format("~-8s ~5.1f% ~5.1f% ~p~n", + io:format("~-8s ~5.1f% ~5.1f% ~s~n", [StatusOut, RingPercent, - NextPercent, Node]); + NextPercent, DisplayNode]); false -> - io:format("~-8s ~5.1f% -- ~p~n", - [StatusOut, RingPercent, Node]) + io:format("~-8s ~5.1f% -- ~s~n", + [StatusOut, RingPercent, DisplayNode]) end, case Status of joining -> @@ -106,6 +108,14 @@ print_member_status(Ring, LegacyGossip) -> [Valid, Leaving, Exiting, Joining, Down]), ok. +maybe_add_location(Node, Locations) -> + case riak_core_location:get_node_location(Node, Locations) of + unknown -> + atom_to_list(Node); + Location -> + atom_to_list(Node) ++ " (" ++ Location ++ ")" + end. + ring_status([]) -> {Claimant, RingReady, Down, MarkedDown, Changes} = riak_core_status:ring_status(), @@ -649,7 +659,9 @@ print_plan(Changes, Ring, NextRings) -> io:format("resize-ring ~p to ~p partitions~n",[CurrentSize,NewRingSize]); ({_, abort_resize}) -> CurrentSize = riak_core_ring:num_partitions(Ring), - io:format("resize-ring abort. current size: ~p~n", [CurrentSize]) + io:format("resize-ring abort. current size: ~p~n", [CurrentSize]); + ({Node, {set_location, Location}}) -> + io:format("set-location ~p to ~s~n", [Node, Location]) end, Changes), io:format("~79..-s~n", [""]), io:format("~n"), diff --git a/src/riak_core_location.erl b/src/riak_core_location.erl new file mode 100644 index 000000000..5f5e1f4f1 --- /dev/null +++ b/src/riak_core_location.erl @@ -0,0 +1,53 @@ +-module(riak_core_location). + +%% API +-export([get_node_location/2, + has_location_set_in_cluster/1, + stripe_nodes_by_location/2]). + +-spec get_node_location(node(), dict:dict()) -> string() | unknown. +get_node_location(Node, Locations) -> + case dict:find(Node, Locations) of + error -> + unknown; + {ok, Location} -> + Location + end. + +-spec has_location_set_in_cluster(dict:dict()) -> boolean(). +has_location_set_in_cluster(NodesLocations) -> + 0 =/= dict:size(NodesLocations). + +-spec get_location_nodes([node()|undefined], dict:dict()) -> dict:dict(). +get_location_nodes(Nodes, Locations) -> + lists:foldl(fun(undefined, Acc) -> + dict:append(unknown, undefined, Acc); + (Node, Acc) -> + NodeLocation = get_node_location(Node, Locations), + dict:append(NodeLocation, Node, Acc) + end, dict:new(), Nodes). + +%% Order nodes list by having a different location after each other +-spec stripe_nodes_by_location([node()|undefined], dict:dict()) -> + [node()|undefined]. +stripe_nodes_by_location(Nodes, NodesLocations) -> + LocationsNodes = get_location_nodes(Nodes, NodesLocations), + Locations = dict:fetch_keys(LocationsNodes), + stripe_nodes_by_location(Locations, LocationsNodes, []). + +-spec stripe_nodes_by_location([node()|undefined], dict:dict(), [node()|undefined]) -> + [node()|undefined]. +stripe_nodes_by_location([], _LocationsNodes, NewNodeList) -> + lists:reverse(NewNodeList); +stripe_nodes_by_location(Locations, LocationsNodes, NewNodeList) -> + Nth = (length(NewNodeList) rem length(Locations)) + 1, + CurrentLocation = lists:nth(Nth, Locations), + case dict:find(CurrentLocation, LocationsNodes) of + {ok, []} -> + NewLocations = lists:delete(CurrentLocation, Locations), + NewLocationsNodes = dict:erase(CurrentLocation, LocationsNodes), + stripe_nodes_by_location(NewLocations, NewLocationsNodes, NewNodeList); + {ok, [Node | RemNodes]} -> + NewLocationNodes = dict:store(CurrentLocation, RemNodes, LocationsNodes), + stripe_nodes_by_location(Locations, NewLocationNodes, [Node | NewNodeList]) + end. diff --git a/src/riak_core_ring.erl b/src/riak_core_ring.erl index 318a10812..b79ef5c0a 100644 --- a/src/riak_core_ring.erl +++ b/src/riak_core_ring.erl @@ -81,6 +81,10 @@ set_member/4, set_member/5, members/2, + has_location_changed/1, + clear_location_changed/1, + set_node_location/3, + get_nodes_locations/1, set_claimant/2, increment_vclock/2, ring_version/1, @@ -326,6 +330,28 @@ all_members(?CHSTATE{members=Members}) -> members(?CHSTATE{members=Members}, Types) -> get_members(Members, Types). +-spec has_location_changed(chstate()) -> boolean(). +has_location_changed(State) -> + {ok, Value} = get_meta('$nodes_locations_changed', false, State), + Value. + +-spec clear_location_changed(chstate()) -> chstate(). +clear_location_changed(State) -> + update_meta('$nodes_locations_changed', false, State). + +-spec set_node_location(node(), string(), chstate()) -> chstate(). +set_node_location(Node, Location, State) -> + NodesLocations = get_nodes_locations(State), + NewNodesLocations = dict:store(Node, Location, NodesLocations), + NewState = update_meta('$nodes_locations_changed', true, State), + update_meta('$nodes_locations', NewNodesLocations, NewState). + +-spec get_nodes_locations(chstate()) -> dict:dict(). +get_nodes_locations(?CHSTATE{members =Members} = ChState) -> + {ok, Value} = get_meta('$nodes_locations', dict:new(), ChState), + Nodes = get_members(Members), + dict:filter(fun(Node, _) -> lists:member(Node, Nodes) end, Value). + %% @doc Produce a list of all active (not marked as down) cluster members active_members(?CHSTATE{members=Members}) -> get_members(Members, [joining, valid, leaving, exiting]). diff --git a/test/rack_awareness_test.erl b/test/rack_awareness_test.erl new file mode 100644 index 000000000..44e64797b --- /dev/null +++ b/test/rack_awareness_test.erl @@ -0,0 +1,196 @@ +%%% @author Peter Tihanyi +%%% @copyright (C) 2021, Peter Tihanyi +%%% @doc +%%% +%%% @end +-module(rack_awareness_test). + +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). + +-define(RING_SIZES, [8, 64, 128, 256, 512]). +-define(NODE_COUNTS, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20]). + +sync_test_() -> + {setup, + fun generate_rings/0, + fun (_) -> ok end, + fun(Rings) -> + RingsWithLocation = lists:flatten(lists:map(fun add_loc_to_ring/1, Rings)), + Threads = erlang:system_info(schedulers_online), + {inparallel, Threads, [{get_test_desc(Ring), + fun() -> assert_vnode_location(claim(Ring)) end} + || Ring <- RingsWithLocation]} + end + }. + +get_test_desc(Ring) -> + lists:flatten( + io_lib:format("ring_size: ~p node_count: ~p nodes with locations: ~p", + [riak_core_ring:num_partitions(Ring), + length(riak_core_ring:all_members(Ring)), + dict:size(riak_core_ring:get_nodes_locations(Ring))]) + ). + +add_loc_to_ring(Ring) -> + Nodes = riak_core_ring:all_members(Ring), + NodeCount = length(Nodes), + Locations = generate_site_names(NodeCount), + %Permutations = gen_loc_permutations(Locations, #{}, NodeCount), + Permutations = gen_loc_permutations_opt(Locations, NodeCount), + lists:map(fun(Permutation) -> + {_, NewRing} = + maps:fold(fun(Location, Count, {CNodes, CRing}) -> + do_set_locations(CNodes, Location, Count, CRing) + end, {Nodes, Ring}, Permutation), + NewRing + end, Permutations). + +do_set_locations(Nodes, _Location, 0, Ring) -> + {Nodes, Ring}; +do_set_locations([Node | RemNodes], Location, Count, Ring) -> + NewRing = riak_core_ring:set_node_location(Node, Location, Ring), + do_set_locations(RemNodes, Location, Count-1, NewRing). + +gen_loc_permutations_opt(Locations, Max) -> + InitPermutationMap = init_permutation_map(Locations), + HeadLoc = hd(Locations), + gen_loc_permutations_opt(HeadLoc, Locations, InitPermutationMap, Max, + [InitPermutationMap]). + +gen_loc_permutations_opt(_, [], _Permutation, _Max, Acc) -> + Acc; +gen_loc_permutations_opt(TopLoc, [HeadLoc | RestLoc] = Locations, Permutation, Max, + Acc) -> + case get_location_combination_count(Permutation) =:= Max of + true -> + NewPermutations = increase(Permutation, TopLoc, -1), + TopLocCount = maps:get(TopLoc, NewPermutations), + HeadLocCount = maps:get(HeadLoc, NewPermutations), + case TopLocCount > HeadLocCount of + true -> + NewPermutations2 = increase(NewPermutations, HeadLoc, -1), + gen_loc_permutations_opt(TopLoc, Locations, NewPermutations2, Max, Acc); + _ -> + gen_loc_permutations_opt(HeadLoc, RestLoc, NewPermutations, Max, Acc) + end; + _ -> + NewPermutations = increase(Permutation, HeadLoc, 1), + gen_loc_permutations_opt(TopLoc, Locations, NewPermutations, Max, + [NewPermutations | Acc]) + end. + + +init_permutation_map(Locations) -> + lists:foldl(fun(LocName, Acc) -> Acc#{LocName => 0} end, #{}, Locations). + +gen_loc_permutations([], Acc, _Max) -> + Acc; +gen_loc_permutations(Loc, Acc, Max) when length(Loc) > 6 -> + LocLength = length(Loc), + NewLocations = lists:delete(lists:nth(rand:uniform(LocLength), Loc), Loc), + gen_loc_permutations(NewLocations, Acc, Max); +gen_loc_permutations([LocationName | Rest] = _Full, Acc, Max) -> + Result = [gen_loc_permutations(Rest, increase(Acc, LocationName, Add), Max) || Add <- lists:seq(0, Max)], + lists:filter(fun(Item) -> + get_location_combination_count(Item) =< Max + end, lists:flatten(Result)). + +increase(State, LocationName, Add) -> + State#{LocationName => maps:get(LocationName, State, 0)+Add}. + +get_location_combination_count(Locations) -> + maps:fold(fun(_, V, A) -> V+A end, 0, Locations). + +assert_vnode_location(Ring) -> + Locations = dict:to_list(riak_core_ring:get_nodes_locations(Ring)), + assert_vnode_location(Ring, Locations). + +assert_vnode_location(_Ring, []) -> + true; +assert_vnode_location(Ring, Locations) -> + Owners = riak_core_ring:all_owners(Ring), + CheckResult = check(Owners, Locations), + case CheckResult of + false -> + Data = print_ring_partitions(Owners, Locations, "\r\n\r\n"), + RSize = io_lib:format("Ring size: ~p~n", [length(Owners)]), + LocationData = io_lib:format("Location data: ~p~n", [Locations]), + NewData = ["***********************\r\n", RSize, LocationData, "\r\n" |Data], + file:write_file("ring_debug.txt", NewData, [append, write]); + _ -> + ok + end, + ?assert(CheckResult). + +check(Owners, Locations) -> + UniqueLoc = get_unique_locations(Locations), + MaxError = (length(Owners) - length(UniqueLoc)), + check(Owners, Locations, not_set, MaxError). + +check([], _Locations, _LastLoc, _MaxError) -> + true; +check([{_Idx, Node} | Rem], Locations, LastLoc, MaxError) -> + case proplists:get_value(Node, Locations, not_set) of + LastLoc when MaxError > 0 -> + check(Rem, Locations, LastLoc, MaxError-1); + LastLoc -> + false; + NewLoc -> + check(Rem, Locations, NewLoc, MaxError) + end. + +get_unique_locations(Locations) -> + lists:foldl(fun({_, ActualLoc}, Acc) -> + case lists:member(ActualLoc, Acc) of + false -> + [ActualLoc | Acc]; + _ -> + Acc + end + end, [], Locations). + +print_ring_partitions(Owners, Locations) -> + io:format(user, "~s", [print_ring_partitions(Owners, Locations, [])]). + +print_ring_partitions([], _Locations, Acc) -> + Acc; +print_ring_partitions([{Idx, Node} | Rem], Locations, Acc) -> + Location = proplists:get_value(Node, Locations, not_set), + Line = io_lib:format("Node: ~p \t Loc: ~p \t idx: ~p ~n", [Node, Location, Idx]), + print_ring_partitions(Rem, Locations, [Line | Acc]). + +generate_rings() -> + generate_rings(?RING_SIZES, ?NODE_COUNTS). + +generate_rings(Sizes, NodeCounts) -> + [do_generate_ring(S, generate_node_names(N)) || + S <- Sizes, N <- NodeCounts]. + +do_generate_ring(Size, ContributorNodes) when length(ContributorNodes) > Size -> + do_generate_ring(Size, lists:sublist(ContributorNodes, 1, Size)); +do_generate_ring(Size, ContributorNodes) -> + [CNode] = generate_node_names(1), + Ring = riak_core_ring:fresh(Size, CNode), + NewRing = lists:foldl(fun(Node, CRing) -> + riak_core_ring:add_member(CNode, CRing, Node) + end, Ring, ContributorNodes), + claim(NewRing). + +claim(Ring) -> + WantsClaimFun = {riak_core_claim, default_wants_claim}, + ChooseClaimFun = {riak_core_claim, default_choose_claim}, + riak_core_claim:claim(Ring, WantsClaimFun, ChooseClaimFun). + +generate_site_names(Count) -> + lists:map(fun(Name) -> binary_to_list(Name) end, + tl(generate_name(<<"site_">>, Count+1))). + +generate_node_names(Count) -> + lists:map(fun(Name) -> binary_to_atom(<>, utf8) end, + generate_name(<<"node_">>, Count)). + +generate_name(Prefix, Count) when Count =< 25 andalso Count >= 1 -> + GenList = lists:seq(65, 65+Count-1), + [<> || C <- GenList]. From 185f4a132e02eac4ccff5dc38f05d3682d820534 Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Sun, 7 Mar 2021 21:05:44 +0100 Subject: [PATCH 2/6] Add warning message when not all replicas will be on distinct locations --- src/riak_core_console.erl | 9 ++++- src/riak_core_location.erl | 65 ++++++++++++++++++++++++++++++---- test/rack_awareness_test.erl | 68 +++++++++++++++++++++++++----------- 3 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/riak_core_console.erl b/src/riak_core_console.erl index c8f99ee0e..fcb085799 100644 --- a/src/riak_core_console.erl +++ b/src/riak_core_console.erl @@ -110,7 +110,7 @@ print_member_status(Ring, LegacyGossip) -> maybe_add_location(Node, Locations) -> case riak_core_location:get_node_location(Node, Locations) of - unknown -> + undefined -> atom_to_list(Node); Location -> atom_to_list(Node) ++ " (" ++ Location ++ ")" @@ -709,6 +709,13 @@ output(Ring, NextRing) -> io:format("WARNING: Not all replicas will be on distinct nodes~n~n") end, + case riak_core_location:check_ring(FutureRing) of + [] -> + ok; + _ -> + io:format("WARNING: Not all replicas will be on distinct locations~n~n") + end, + Owners1 = riak_core_ring:all_owners(Ring), Owners2 = riak_core_ring:all_owners(NextRing), Owners3 = lists:zip(Owners1, Owners2), diff --git a/src/riak_core_location.erl b/src/riak_core_location.erl index 5f5e1f4f1..554b86546 100644 --- a/src/riak_core_location.erl +++ b/src/riak_core_location.erl @@ -3,13 +3,15 @@ %% API -export([get_node_location/2, has_location_set_in_cluster/1, - stripe_nodes_by_location/2]). + stripe_nodes_by_location/2, + check_ring/1, + check_ring/2]). --spec get_node_location(node(), dict:dict()) -> string() | unknown. +-spec get_node_location(node(), dict:dict()) -> string() | undefined. get_node_location(Node, Locations) -> case dict:find(Node, Locations) of error -> - unknown; + undefined; {ok, Location} -> Location end. @@ -21,7 +23,7 @@ has_location_set_in_cluster(NodesLocations) -> -spec get_location_nodes([node()|undefined], dict:dict()) -> dict:dict(). get_location_nodes(Nodes, Locations) -> lists:foldl(fun(undefined, Acc) -> - dict:append(unknown, undefined, Acc); + dict:append(undefined, undefined, Acc); (Node, Acc) -> NodeLocation = get_node_location(Node, Locations), dict:append(NodeLocation, Node, Acc) @@ -32,10 +34,29 @@ get_location_nodes(Nodes, Locations) -> [node()|undefined]. stripe_nodes_by_location(Nodes, NodesLocations) -> LocationsNodes = get_location_nodes(Nodes, NodesLocations), - Locations = dict:fetch_keys(LocationsNodes), - stripe_nodes_by_location(Locations, LocationsNodes, []). + stripe_nodes_by_location(get_locations(LocationsNodes), LocationsNodes, []). --spec stripe_nodes_by_location([node()|undefined], dict:dict(), [node()|undefined]) -> +-spec get_locations(dict:dict()) -> [node()|undefined]. +get_locations(LocationsNodes) -> + LocationNodesSorted = sort_by_node_count(dict:to_list(LocationsNodes)), + lists:map(fun({Location, _}) -> Location end, LocationNodesSorted). + +-spec sort_by_node_count(list()) -> list(). +sort_by_node_count(LocationsNodes) -> + lists:sort(fun compare/2, LocationsNodes). + +-spec compare({any(), list()}, {any(), list()}) -> boolean(). +compare({_, NodesA}, {_, NodesB}) -> + LengthA = length(NodesA), + LengthB = length(NodesB), + case LengthA =:= LengthB of + true -> + lists:last(NodesA) >= lists:last(NodesB); + _ -> + LengthA >= LengthB + end. + +-spec stripe_nodes_by_location([node()|undefined], dist:dict(), [node()|undefined]) -> [node()|undefined]. stripe_nodes_by_location([], _LocationsNodes, NewNodeList) -> lists:reverse(NewNodeList); @@ -51,3 +72,33 @@ stripe_nodes_by_location(Locations, LocationsNodes, NewNodeList) -> NewLocationNodes = dict:store(CurrentLocation, RemNodes, LocationsNodes), stripe_nodes_by_location(Locations, NewLocationNodes, [Node | NewNodeList]) end. + +-spec check_ring(riak_core_ring:riak_core_ring()) -> list(). +check_ring(Ring) -> + {ok, Props} = application:get_env(riak_core, default_bucket_props), + check_ring(Ring, proplists:get_value(n_val, Props)). + +-spec check_ring(riak_core_ring:riak_core_ring(), pos_integer()) -> list(). +check_ring(Ring, Nval) -> + Locations = riak_core_ring:get_nodes_locations(Ring), + case has_location_set_in_cluster(Locations) of + true -> + check_ring(Ring, Nval, Locations); + _ -> + [] % no location set, not needed to check + end. + +-spec check_ring(riak_core_ring:riak_core_ring(), pos_integer(), dict:dict()) -> + list(). +check_ring(Ring, Nval, Locations) -> + lists:foldl(fun(PL, Acc) -> + case length(get_unique_locations(PL, Locations)) of + Nval -> Acc; + _ -> [PL | Acc] + end + end, [], riak_core_ring:all_preflists(Ring, Nval)). + +-spec get_unique_locations(list(), dict:dict()) -> + list(). +get_unique_locations(PrefLists, Locations) -> + lists:usort([get_node_location(Node, Locations) || {_, Node} <- PrefLists]). \ No newline at end of file diff --git a/test/rack_awareness_test.erl b/test/rack_awareness_test.erl index 44e64797b..0fadbc880 100644 --- a/test/rack_awareness_test.erl +++ b/test/rack_awareness_test.erl @@ -12,7 +12,7 @@ -define(RING_SIZES, [8, 64, 128, 256, 512]). -define(NODE_COUNTS, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20]). -sync_test_() -> +ring_claim_test_() -> {setup, fun generate_rings/0, fun (_) -> ok end, @@ -110,37 +110,65 @@ assert_vnode_location(Ring) -> assert_vnode_location(_Ring, []) -> true; assert_vnode_location(Ring, Locations) -> - Owners = riak_core_ring:all_owners(Ring), - CheckResult = check(Owners, Locations), + CheckResult = check(Ring, Locations), case CheckResult of false -> - Data = print_ring_partitions(Owners, Locations, "\r\n\r\n"), + Owners = riak_core_ring:all_owners(Ring), + Members = riak_core_ring:all_members(Ring), + Data = print_ring_partitions(Owners, Locations, ""), RSize = io_lib:format("Ring size: ~p~n", [length(Owners)]), LocationData = io_lib:format("Location data: ~p~n", [Locations]), - NewData = ["***********************\r\n", RSize, LocationData, "\r\n" |Data], + MemberCount = io_lib:format("Nodes: ~p~n", [length(Members)]), + RingErrors = io_lib:format("Check ring: ~p~n", + [riak_core_location:check_ring(Ring, 3)]), + NewData = ["\r\n *********************** \r\n", RSize, MemberCount, + LocationData, RingErrors, "\r\n" | Data], file:write_file("ring_debug.txt", NewData, [append, write]); _ -> ok end, ?assert(CheckResult). -check(Owners, Locations) -> - UniqueLoc = get_unique_locations(Locations), - MaxError = (length(Owners) - length(UniqueLoc)), - check(Owners, Locations, not_set, MaxError). - -check([], _Locations, _LastLoc, _MaxError) -> - true; -check([{_Idx, Node} | Rem], Locations, LastLoc, MaxError) -> - case proplists:get_value(Node, Locations, not_set) of - LastLoc when MaxError > 0 -> - check(Rem, Locations, LastLoc, MaxError-1); - LastLoc -> +check(Ring, Locations) -> + Owners = riak_core_ring:all_owners(Ring), + MemberCount = length(riak_core_ring:active_members(Ring)), + NVal = 3, + Rs = length(Owners), + UniqueLocCount = length(get_unique_locations(Locations)), + + MaxError = get_max_error(NVal, Rs, MemberCount, UniqueLocCount), + case riak_core_location:check_ring(Ring, NVal) of + Errors when length(Errors) > MaxError -> + io:format("Max error; ~p > ~p | ~p~n", + [length(Errors), MaxError, {NVal, Rs, MemberCount, + UniqueLocCount}]), false; - NewLoc -> - check(Rem, Locations, NewLoc, MaxError) + _ -> + true end. +% @TODO better evaluation +get_max_error(NVal, RingSize, MemberCount, UniqueLocationCount) + when UniqueLocationCount > NVal andalso + MemberCount == UniqueLocationCount andalso + RingSize rem MemberCount == 0 -> + 0; +get_max_error(NVal, _RingSize, MemberCount, UniqueLocationCount) + when UniqueLocationCount > NVal andalso + MemberCount == UniqueLocationCount -> + NVal; +get_max_error(NVal, RingSize, MemberCount, UniqueLocationCount) + when RingSize rem MemberCount == 0 -> % no tail violations + MaxNodesOnSameLoc = (MemberCount - UniqueLocationCount)+1, + case MaxNodesOnSameLoc > NVal of + true -> + RingSize; + false -> + (RingSize - ((NVal rem MaxNodesOnSameLoc))+1) + end; +get_max_error(_NVal, RingSize, _MemberCount, _UniqueLocationCount) -> + RingSize. + get_unique_locations(Locations) -> lists:foldl(fun({_, ActualLoc}, Acc) -> case lists:member(ActualLoc, Acc) of @@ -155,7 +183,7 @@ print_ring_partitions(Owners, Locations) -> io:format(user, "~s", [print_ring_partitions(Owners, Locations, [])]). print_ring_partitions([], _Locations, Acc) -> - Acc; + lists:reverse(Acc); print_ring_partitions([{Idx, Node} | Rem], Locations, Acc) -> Location = proplists:get_value(Node, Locations, not_set), Line = io_lib:format("Node: ~p \t Loc: ~p \t idx: ~p ~n", [Node, Location, Idx]), From bdb0b3d94acf6fb5e6ad1908df3efc12efb7fb6e Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Mon, 8 Mar 2021 16:24:03 +0100 Subject: [PATCH 3/6] Fix dialyzer. --- src/riak_core_cluster_cli.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/riak_core_cluster_cli.erl b/src/riak_core_cluster_cli.erl index 48560741b..09cec463d 100644 --- a/src/riak_core_cluster_cli.erl +++ b/src/riak_core_cluster_cli.erl @@ -48,8 +48,7 @@ register_all_usage() -> clique:register_usage(["riak-admin", "cluster", "partitions"], partitions_usage()), clique:register_usage(["riak-admin", "cluster", "partition_count"], partition_count_usage()), clique:register_usage(["riak-admin", "cluster", "partition_count"], partition_count_usage()), - clique:register_usage(["riak-admin", "cluster", "location"], location_usage()), - clique:register_usage(["riak-admin", "cluster", "location", '*'], location_usage()). + clique:register_usage(["riak-admin", "cluster", "location"], location_usage()). register_all_commands() -> lists:foreach(fun(Args) -> apply(clique, register_command, Args) end, From 9a9e2eda2d211d491b55b9d67bc6ab0ffbd0c5ef Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Mon, 22 Mar 2021 19:40:03 +0100 Subject: [PATCH 4/6] Add minimum number of distinct locations parameter to location check_ring --- src/riak_core_location.erl | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/riak_core_location.erl b/src/riak_core_location.erl index 554b86546..6220b5019 100644 --- a/src/riak_core_location.erl +++ b/src/riak_core_location.erl @@ -5,7 +5,8 @@ has_location_set_in_cluster/1, stripe_nodes_by_location/2, check_ring/1, - check_ring/2]). + check_ring/2, + check_ring/3]). -spec get_node_location(node(), dict:dict()) -> string() | undefined. get_node_location(Node, Locations) -> @@ -80,21 +81,27 @@ check_ring(Ring) -> -spec check_ring(riak_core_ring:riak_core_ring(), pos_integer()) -> list(). check_ring(Ring, Nval) -> + check_ring(Ring, Nval, Nval). + +-spec check_ring(riak_core_ring:riak_core_ring(), pos_integer(), pos_integer()) -> list(). +check_ring(Ring, NVal, MinimumNumberOfDistinctLocations) -> Locations = riak_core_ring:get_nodes_locations(Ring), case has_location_set_in_cluster(Locations) of true -> - check_ring(Ring, Nval, Locations); + check_ring(Ring, NVal, MinimumNumberOfDistinctLocations, Locations); _ -> [] % no location set, not needed to check end. --spec check_ring(riak_core_ring:riak_core_ring(), pos_integer(), dict:dict()) -> +-spec check_ring(riak_core_ring:riak_core_ring(), pos_integer(), pos_integer(), dict:dict()) -> list(). -check_ring(Ring, Nval, Locations) -> +check_ring(Ring, Nval, MinimumNumberOfDistinctLocations, Locations) -> lists:foldl(fun(PL, Acc) -> - case length(get_unique_locations(PL, Locations)) of - Nval -> Acc; - _ -> [PL | Acc] + case length(get_unique_locations(PL, Locations)) < MinimumNumberOfDistinctLocations of + false -> Acc; + _ -> + Error = [{Idx, Node, get_node_location(Node, Locations)} || {Idx, Node} <- PL], + [Error | Acc] end end, [], riak_core_ring:all_preflists(Ring, Nval)). From 8e0faa75ed588f408fc4ac128c901c6acb165de5 Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Wed, 14 Apr 2021 22:30:21 +0200 Subject: [PATCH 5/6] Add rack-awareness docs --- docs/rack-awareness.md | 74 +++++++++++++++++++++++++++++++++++++++++ docs/ring-location.png | Bin 0 -> 91888 bytes 2 files changed, 74 insertions(+) create mode 100644 docs/rack-awareness.md create mode 100644 docs/ring-location.png diff --git a/docs/rack-awareness.md b/docs/rack-awareness.md new file mode 100644 index 000000000..aa3782aeb --- /dev/null +++ b/docs/rack-awareness.md @@ -0,0 +1,74 @@ +# Rack Awareness / Availability zones / Location support + +The aim is to be able to increase data safety, and make the cluster more resilient +against a location/site/availability zone/rack loss. + +To achieve this, a location parameter has been introduced. +It can be set at runtime for each RIAK node. +When claiming a new ring, the list of nodes is ordered taking into consideration the +location of the individual nodes, in a manner that adjacent nodes are preferably +from different locations. + +Basically it only changes the order of the nodes fed into the claiming algorithm. + +The default location is `undefined`. This means every node with no location parameter set +will be handled as being in the same location. + +## Ring visualization + +![RIAK Ring Location](ring-location.png) + +## Setup node's location parameter + +Setting up nodes’ location parameter is a staged operation like +other ring manipulations (join, leave, resize-ring, etc). + +### via riak admin +Change current node location parameter: +```bash +riak admin cluster location rack_a +``` +or specify a node: +```bash +riak admin cluster location site_b --node=dev2@127.0.0.1 +``` + +#### by erlang function call + +```erlang +riak_core_claimant:set_node_location(node(), "location_a"), +``` +```erlang +riak_core_claimant:plan(), +riak_core_claimant:comit(). +``` + +## Pitfalls +There are circumstances in which the preferable node location assignment cannot be guaranteed. + +If at least one location parameter is set in the cluster when planning a cluster change, a warning +message will be displayed when not all nodes in a preflist are assigned to a different location. + +For example, if the default `n_val = 3` is specified and there are only `two distinct locations` set in the cluster, +the message `WARNING: Not all replicas will be on distinct locations` will be shown. + +### Not enough distinct locations +When Distinct Location Count is not divisible by Ring size. + +### Tail violations +When Ring Size not divisible by Count Of Nodes. +[claim-fixes](claim-fixes.md) cover this, but improper distinct location count could result in undesirable location distribution within the ring. + +For example, there are 8 nodes on 3 distinct locations. +To ensure that every site/location has a piece of data, n_val must be at least 4. + +It can be checked: +```erlang +{ok, Ring} = riak_core_ring_manager:get_my_ring(), +riak_core_location:check_ring(Ring, Nval = 4, MinimumNumberOfDistinctLocations = 3). +``` + +If `riak_core_location:check_ring/3` returns with an empty list `[]`, there is no location violation. + +### Won't optimize transfers between old and new ring +When location parameter change triggers ring ownership change, it currently does not optimize transfers. diff --git a/docs/ring-location.png b/docs/ring-location.png new file mode 100644 index 0000000000000000000000000000000000000000..cca6bc1aa2ab816f924e830ef65d7bb828124336 GIT binary patch literal 91888 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 z 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

S8iAdKYEXA??NUvrTvo?`E(aC|WHD7y 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 literal 0 HcmV?d00001 From c196b6e57b0194d1b136206d4aa2fbc995a4961d Mon Sep 17 00:00:00 2001 From: Peter Tihanyi Date: Thu, 29 Apr 2021 15:17:58 +0200 Subject: [PATCH 6/6] Add rack-awareness docs update --- docs/rack-awareness.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/rack-awareness.md b/docs/rack-awareness.md index aa3782aeb..a10f456c6 100644 --- a/docs/rack-awareness.md +++ b/docs/rack-awareness.md @@ -62,7 +62,15 @@ When Ring Size not divisible by Count Of Nodes. For example, there are 8 nodes on 3 distinct locations. To ensure that every site/location has a piece of data, n_val must be at least 4. -It can be checked: +It can be checked: + +Stages changes: +```erlang +PlannedRing = element(1, lists:last(element(3, riak_core_claimant:plan()))). +riak_core_location:check_ring(PlannedRing, Nval = 4, MinimumNumberOfDistinctLocations = 3). +``` + +Actual ring: ```erlang {ok, Ring} = riak_core_ring_manager:get_my_ring(), riak_core_location:check_ring(Ring, Nval = 4, MinimumNumberOfDistinctLocations = 3).