mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-3.11' into trunk
This commit is contained in:
commit
edcbef3e34
|
|
@ -247,6 +247,7 @@ Merged from 3.0:
|
|||
* Correct log message for statistics of offheap memtable flush (CASSANDRA-12776)
|
||||
* Explicitly set locale for string validation (CASSANDRA-12541,CASSANDRA-12542,CASSANDRA-12543,CASSANDRA-12545)
|
||||
Merged from 2.2:
|
||||
* Coalescing strategy sleeps too much and shouldn't be enabled by default (CASSANDRA-13090)
|
||||
* Fix speculative retry bugs (CASSANDRA-13009)
|
||||
* Fix handling of nulls and unsets in IN conditions (CASSANDRA-12981)
|
||||
* Fix race causing infinite loop if Thrift server is stopped before it starts listening (CASSANDRA-12856)
|
||||
|
|
|
|||
|
|
@ -1093,3 +1093,30 @@ back_pressure_strategy:
|
|||
- high_ratio: 0.90
|
||||
factor: 5
|
||||
flow: FAST
|
||||
|
||||
# Coalescing Strategies #
|
||||
# Coalescing multiples messages turns out to significantly boost message processing throughput (think doubling or more).
|
||||
# On bare metal, the floor for packet processing throughput is high enough that many applications won’t notice, but in
|
||||
# virtualized environments, the point at which an application can be bound by network packet processing can be
|
||||
# surprisingly low compared to the throughput of task processing that is possible inside a VM. It’s not that bare metal
|
||||
# doesn’t benefit from coalescing messages, it’s that the number of packets a bare metal network interface can process
|
||||
# is sufficient for many applications such that no load starvation is experienced even without coalescing.
|
||||
# There are other benefits to coalescing network messages that are harder to isolate with a simple metric like messages
|
||||
# per second. By coalescing multiple tasks together, a network thread can process multiple messages for the cost of one
|
||||
# trip to read from a socket, and all the task submission work can be done at the same time reducing context switching
|
||||
# and increasing cache friendliness of network message processing.
|
||||
# See CASSANDRA-8692 for details.
|
||||
|
||||
# Strategy to use for coalescing messages in OutboundTcpConnection.
|
||||
# Can be fixed, movingaverage, timehorizon (default), disabled.
|
||||
# You can also specify a subclass of CoalescingStrategies.CoalescingStrategy by name.
|
||||
# otc_coalescing_strategy: TIMEHORIZON
|
||||
|
||||
# How many microseconds to wait for coalescing. For fixed strategy this is the amount of time after the first
|
||||
# message is received before it will be sent with any accompanying messages. For moving average this is the
|
||||
# maximum amount of time that will be waited as well as the interval at which messages must arrive on average
|
||||
# for coalescing to be enabled.
|
||||
# otc_coalescing_window_us: 200
|
||||
|
||||
# Do not try to coalesce messages if we already got that many messages. This should be more than 2 and less than 128.
|
||||
# otc_coalescing_enough_coalesced_messages: 8
|
||||
|
|
|
|||
|
|
@ -283,12 +283,13 @@ public class Config
|
|||
|
||||
/*
|
||||
* How many microseconds to wait for coalescing. For fixed strategy this is the amount of time after the first
|
||||
* messgae is received before it will be sent with any accompanying messages. For moving average this is the
|
||||
* message is received before it will be sent with any accompanying messages. For moving average this is the
|
||||
* maximum amount of time that will be waited as well as the interval at which messages must arrive on average
|
||||
* for coalescing to be enabled.
|
||||
*/
|
||||
public static final int otc_coalescing_window_us_default = 200;
|
||||
public int otc_coalescing_window_us = otc_coalescing_window_us_default;
|
||||
public int otc_coalescing_enough_coalesced_messages = 8;
|
||||
|
||||
public int windows_timer_interval = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -686,6 +686,12 @@ public class DatabaseDescriptor
|
|||
{
|
||||
throw new ConfigurationException("Error configuring back-pressure strategy: " + conf.back_pressure_strategy, ex);
|
||||
}
|
||||
|
||||
if (conf.otc_coalescing_enough_coalesced_messages > 128)
|
||||
throw new ConfigurationException("otc_coalescing_enough_coalesced_messages must be smaller than 128", false);
|
||||
|
||||
if (conf.otc_coalescing_enough_coalesced_messages <= 0)
|
||||
throw new ConfigurationException("otc_coalescing_enough_coalesced_messages must be positive", false);
|
||||
}
|
||||
|
||||
private static String storagedirFor(String type)
|
||||
|
|
@ -2116,6 +2122,16 @@ public class DatabaseDescriptor
|
|||
return conf.otc_coalescing_window_us;
|
||||
}
|
||||
|
||||
public static int getOtcCoalescingEnoughCoalescedMessages()
|
||||
{
|
||||
return conf.otc_coalescing_enough_coalesced_messages;
|
||||
}
|
||||
|
||||
public static void setOtcCoalescingEnoughCoalescedMessages(int otc_coalescing_enough_coalesced_messages)
|
||||
{
|
||||
conf.otc_coalescing_enough_coalesced_messages = otc_coalescing_enough_coalesced_messages;
|
||||
}
|
||||
|
||||
public static int getWindowsTimerInterval()
|
||||
{
|
||||
return conf.windows_timer_interval;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ public class OutboundTcpConnection extends FastThreadLocalThread
|
|||
//Size of 3 elements added to every message
|
||||
private static final int PROTOCOL_MAGIC_ID_TIMESTAMP_SIZE = 12;
|
||||
|
||||
public static final int MAX_COALESCED_MESSAGES = 128;
|
||||
|
||||
private static CoalescingStrategy newCoalescingStrategy(String displayName)
|
||||
{
|
||||
return CoalescingStrategies.newCoalescingStrategy(DatabaseDescriptor.getOtcCoalescingStrategy(),
|
||||
|
|
@ -200,7 +202,7 @@ public class OutboundTcpConnection extends FastThreadLocalThread
|
|||
|
||||
public void run()
|
||||
{
|
||||
final int drainedMessageSize = 128;
|
||||
final int drainedMessageSize = MAX_COALESCED_MESSAGES;
|
||||
// keeping list (batch) size small for now; that way we don't have an unbounded array (that we never resize)
|
||||
final List<QueuedMessage> drainedMessages = new ArrayList<>(drainedMessageSize);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@ package org.apache.cassandra.utils;
|
|||
|
||||
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.io.util.FileUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
|
|
@ -40,6 +43,7 @@ import com.google.common.base.Preconditions;
|
|||
|
||||
public class CoalescingStrategies
|
||||
{
|
||||
static protected final Logger logger = LoggerFactory.getLogger(CoalescingStrategies.class);
|
||||
|
||||
/*
|
||||
* Log debug information at info level about what the average is and when coalescing is enabled/disabled
|
||||
|
|
@ -89,15 +93,23 @@ public class CoalescingStrategies
|
|||
{
|
||||
long now = System.nanoTime();
|
||||
final long timer = now + nanos;
|
||||
// We shouldn't loop if it's within a few % of the target sleep time if on a second iteration.
|
||||
// See CASSANDRA-8692.
|
||||
final long limit = timer - nanos / 16;
|
||||
do
|
||||
{
|
||||
LockSupport.parkNanos(timer - now);
|
||||
now = System.nanoTime();
|
||||
}
|
||||
while (timer - (now = System.nanoTime()) > nanos / 16);
|
||||
while (now < limit);
|
||||
}
|
||||
|
||||
private static boolean maybeSleep(int messages, long averageGap, long maxCoalesceWindow, Parker parker)
|
||||
{
|
||||
// Do not sleep if there are still items in the backlog (CASSANDRA-13090).
|
||||
if (messages >= DatabaseDescriptor.getOtcCoalescingEnoughCoalescedMessages())
|
||||
return false;
|
||||
|
||||
// only sleep if we can expect to double the number of messages we're sending in the time interval
|
||||
long sleep = messages * averageGap;
|
||||
if (sleep <= 0 || sleep > maxCoalesceWindow)
|
||||
|
|
@ -335,7 +347,7 @@ public class CoalescingStrategies
|
|||
if (input.drainTo(out, maxItems) == 0)
|
||||
{
|
||||
out.add(input.take());
|
||||
input.drainTo(out, maxItems - 1);
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
}
|
||||
|
||||
for (Coalescable qm : out)
|
||||
|
|
@ -418,15 +430,16 @@ public class CoalescingStrategies
|
|||
if (input.drainTo(out, maxItems) == 0)
|
||||
{
|
||||
out.add(input.take());
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
}
|
||||
|
||||
long average = notifyOfSample(out.get(0).timestampNanos());
|
||||
|
||||
debugGap(average);
|
||||
|
||||
maybeSleep(out.size(), average, maxCoalesceWindow, parker);
|
||||
if (maybeSleep(out.size(), average, maxCoalesceWindow, parker)) {
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
}
|
||||
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
for (int ii = 1; ii < out.size(); ii++)
|
||||
notifyOfSample(out.get(ii).timestampNanos());
|
||||
}
|
||||
|
|
@ -455,11 +468,16 @@ public class CoalescingStrategies
|
|||
@Override
|
||||
protected <C extends Coalescable> void coalesceInternal(BlockingQueue<C> input, List<C> out, int maxItems) throws InterruptedException
|
||||
{
|
||||
int enough = DatabaseDescriptor.getOtcCoalescingEnoughCoalescedMessages();
|
||||
|
||||
if (input.drainTo(out, maxItems) == 0)
|
||||
{
|
||||
out.add(input.take());
|
||||
parker.park(coalesceWindow);
|
||||
input.drainTo(out, maxItems - 1);
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
if (out.size() < enough) {
|
||||
parker.park(coalesceWindow);
|
||||
input.drainTo(out, maxItems - out.size());
|
||||
}
|
||||
}
|
||||
debugTimestamps(out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@
|
|||
*/
|
||||
package org.apache.cassandra.utils;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.utils.CoalescingStrategies.Clock;
|
||||
import org.apache.cassandra.utils.CoalescingStrategies.Coalescable;
|
||||
import org.apache.cassandra.utils.CoalescingStrategies.CoalescingStrategy;
|
||||
import org.apache.cassandra.utils.CoalescingStrategies.Parker;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -101,6 +103,12 @@ public class CoalescingStrategiesTest
|
|||
Semaphore queueParked = new Semaphore(0);
|
||||
Semaphore queueRelease = new Semaphore(0);
|
||||
|
||||
@BeforeClass
|
||||
public static void initDD()
|
||||
{
|
||||
DatabaseDescriptor.daemonInitialization();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "serial" })
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
|
|
@ -206,6 +214,38 @@ public class CoalescingStrategiesTest
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixedCoalescingStrategyEnough() throws Exception
|
||||
{
|
||||
int oldValue = DatabaseDescriptor.getOtcCoalescingEnoughCoalescedMessages();
|
||||
DatabaseDescriptor.setOtcCoalescingEnoughCoalescedMessages(1);
|
||||
try {
|
||||
cs = newStrategy("FIXED", 200);
|
||||
|
||||
//Test that when a stream of messages continues arriving it keeps sending until all are drained
|
||||
//It does this because it is already awake and sending messages
|
||||
add(42);
|
||||
add(42);
|
||||
cs.coalesce(input, output, 128);
|
||||
assertEquals(2, output.size());
|
||||
assertNull(parker.parks.poll());
|
||||
|
||||
clear();
|
||||
|
||||
runBlocker(queueParked);
|
||||
add(42);
|
||||
add(42);
|
||||
add(42);
|
||||
release();
|
||||
assertEquals(3, output.size());
|
||||
assertNull(parker.parks.poll());
|
||||
}
|
||||
finally {
|
||||
DatabaseDescriptor.setOtcCoalescingEnoughCoalescedMessages(oldValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledCoalescingStrateg() throws Exception
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue