The proxy can now be configured to prefer local object servers for PUT requests, where "local" is governed by the "write_affinity". The "write_affinity_node_count" setting controls how many local object servers to try before giving up and going on to remote ones. I chose to simply re-order the object servers instead of filtering out nonlocal ones so that, if all of the local ones are down, clients can still get successful responses (just slower). The goal is to trade availability for throughput. By writing to local object servers across fast LAN links, clients get better throughput than if the object servers were far away over slow WAN links. The downside, of course, is that data availability (not durability) may suffer when drives fail. The default configuration has no write affinity in it, so the default behavior is unchanged. Added some words about these settings to the admin guide. DocImpact Change-Id: I09a0bd00524544ff627a3bccdcdc48f40720a86e
68 lines
2.5 KiB
Python
Executable File
68 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2010-2012 OpenStack, LLC.
|
|
#
|
|
# 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.
|
|
|
|
import mock
|
|
import unittest
|
|
|
|
from swift.proxy import server as proxy_server
|
|
from test.unit import fake_http_connect, FakeRing, FakeMemcache
|
|
|
|
|
|
class TestObjControllerWriteAffinity(unittest.TestCase):
|
|
def setUp(self):
|
|
self.app = proxy_server.Application(
|
|
None, FakeMemcache(), account_ring=FakeRing(),
|
|
container_ring=FakeRing(), object_ring=FakeRing(max_more_nodes=9))
|
|
self.app.request_node_count = lambda ring: 10000000
|
|
self.app.sort_nodes = lambda l: l # stop shuffling the primary nodes
|
|
|
|
def test_iter_nodes_local_first_noops_when_no_affinity(self):
|
|
controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
|
|
self.app.write_affinity_is_local_fn = None
|
|
|
|
all_nodes = self.app.object_ring.get_part_nodes(1)
|
|
all_nodes.extend(self.app.object_ring.get_more_nodes(1))
|
|
|
|
local_first_nodes = list(controller.iter_nodes_local_first(
|
|
self.app.object_ring, 1))
|
|
|
|
fr = FakeRing()
|
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(all_nodes, local_first_nodes)
|
|
|
|
def test_iter_nodes_local_first_moves_locals_first(self):
|
|
controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
|
|
self.app.write_affinity_is_local_fn = (lambda node: node['region'] == 1)
|
|
self.app.write_affinity_node_count = lambda ring: 4
|
|
|
|
all_nodes = self.app.object_ring.get_part_nodes(1)
|
|
all_nodes.extend(self.app.object_ring.get_more_nodes(1))
|
|
|
|
local_first_nodes = list(controller.iter_nodes_local_first(
|
|
self.app.object_ring, 1))
|
|
|
|
# the local nodes move up in the ordering
|
|
self.assertEqual([1, 1, 1, 1],
|
|
[node['region'] for node in local_first_nodes[:4]])
|
|
# we don't skip any nodes
|
|
self.assertEqual(sorted(all_nodes), sorted(local_first_nodes))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|