-
Notifications
You must be signed in to change notification settings - Fork 404
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
RATIS-523 RATIS-524 RATIS-525 RATIS-526 RATIS-527 RATIS-533 Lots of cleanup on the LogService #18
Changes from all commits
1698e73
4a1697a
cbdf7bd
912365d
f76d779
538ef5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Tuning for the Log Service | ||
|
||
This is a list of Ratis configuration properties which have been | ||
found to be relevant/important to control how Ratis operates for | ||
the purposes of the LogService. | ||
|
||
## RAFT Log | ||
|
||
The default RAFT log implementation uses "segments" on disk to avoid | ||
a single file growing to be very large. By default, each segment is | ||
`8MB` in size and can be set by the API `RaftServerConfigKeys.Log.setSegmentSizeMax()`. | ||
When a new segment is created, Ratis will "preallocate" that segment by writing | ||
data into the file to reduce the risk of latency when we first try to append | ||
entries to the RAFT log. By default, the segment is preallocated with `4MB` | ||
and can be changed via `RaftServerConfigKeys.Log.setPreallocatedSize()`. | ||
|
||
Up to 2 log segments are cached in memory (including the segment actively being | ||
written to). This is controlled by `RaftServerConfigKeys.Log.setMaxCachedSegmentNum()`. | ||
Increasing this configuration would use more memory but should reduce the latency | ||
of reading entries from the RAFT log. | ||
|
||
Writes to the RAFT log are buffered using a Java Direct ByteBuffer (offheap). By default, | ||
this buffer is `64KB` in size and can be changed via `RaftServerConfigKeys.Log.setWriteBufferSize`. | ||
Beware that when one LogServer is hosting multiple RAFT groups (multiple "LogService Logs"), each | ||
will LogServer will have its own buffer. Thus, high concurrency will result in multiple buffers. | ||
|
||
## RAFT Server | ||
|
||
Every RAFT server maintains a queue of I/O actions that it needs to execute. As with | ||
much of Ratis, these actions are executed asynchronously and the client can block on | ||
completion of these tasks as necessary. To prevent saturating memory, this queue of | ||
items can be limited in size by both number of entries and size of the elements in the queue. | ||
The former defaults to 4096 elements and id controlled by `RaftServerConfigKeys.Log.setElementLimit()`, | ||
while the latter defaults to `64MB` and is controlled by `RaftServerConfigKeys.Log.setByteLimit()`. | ||
|
||
## Do Not Set | ||
|
||
Running a snapshot indicates that we can truncate part of the RAFT log, as the expectation is that | ||
a snapshot is an equivalent representation of all of the updates from the log. However, the LogService | ||
is written to expect that we maintain these records. As such, we must not allow snapshots to automatically | ||
happen as we may lose records from the RAFT log. `RaftServerConfigKeys.Snapshot.setAutoTriggerEnabled()` | ||
defaults to `false` and should not be set to `true`. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one | ||
# or more contributor license agreements. See the NOTICE file | ||
# distributed with this work for additional information | ||
# regarding copyright ownership. The ASF licenses this file | ||
# to you 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. | ||
|
||
LOGSERVICE="$(dirname "$0")" | ||
LOGSERVICE="$(cd "$LOGSERVICE">/dev/null; pwd)" | ||
|
||
# Get the version of the project | ||
VERSION="$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" | ||
|
||
# Validate that the tarball is there | ||
if [[ ! -f "target/ratis-logservice-${VERSION}-bin.tar.gz" ]]; then | ||
echo "LogService assembly tarball missing, run 'mvn package assembly:single' first!" | ||
exit 1 | ||
fi | ||
|
||
docker build -t ratis-logservice --build-arg BINARY=target/ratis-logservice-$VERSION-bin.tar.gz --build-arg VERSION=$VERSION . |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one | ||
# or more contributor license agreements. See the NOTICE file | ||
# distributed with this work for additional information | ||
# regarding copyright ownership. The ASF licenses this file | ||
# to you 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. | ||
|
||
docker run --rm --network ratis-logservice_default -it ratis-logservice |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#!/bin/sh | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one | ||
# or more contributor license agreements. See the NOTICE file | ||
# distributed with this work for additional information | ||
# regarding copyright ownership. The ASF licenses this file | ||
# to you 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. | ||
|
||
LOGSERVICE="$(dirname "$0")" | ||
LOGSERVICE="$(cd "$LOGSERVICE/..">/dev/null; pwd)" | ||
|
||
export CLASSPATH="${LOGSERVICE}/conf:${LOGSERVICE}/lib/*" | ||
exec java -XX:OnOutOfMemoryError="kill -9 %p" $LOGSERVICE_OPTS org.apache.ratis.logservice.tool.VerificationTool "$@" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#!/bin/sh | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one | ||
# or more contributor license agreements. See the NOTICE file | ||
# distributed with this work for additional information | ||
# regarding copyright ownership. The ASF licenses this file | ||
# to you 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. | ||
|
||
LOGSERVICE="$(dirname "$0")" | ||
LOGSERVICE="$(cd "$LOGSERVICE/..">/dev/null; pwd)" | ||
|
||
export CLASSPATH="${LOGSERVICE}/conf:${LOGSERVICE}/lib/*" | ||
exec java -XX:OnOutOfMemoryError="kill -9 %p" $LOGSERVICE_OPTS org.apache.ratis.logservice.shell.LogServiceShell "$@" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,9 +20,15 @@ | |
import java.io.Closeable; | ||
import java.net.InetSocketAddress; | ||
import java.util.Objects; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import org.apache.ratis.conf.RaftProperties; | ||
import org.apache.ratis.grpc.GrpcConfigKeys; | ||
import org.apache.ratis.logservice.util.LogServiceUtils; | ||
import org.apache.ratis.netty.NettyConfigKeys; | ||
import org.apache.ratis.server.RaftServerConfigKeys; | ||
import org.apache.ratis.util.NetUtils; | ||
import org.apache.ratis.util.TimeDuration; | ||
|
||
/** | ||
* A base class to encapsulate functionality around a long-lived Java process which runs a state machine. | ||
|
@@ -39,6 +45,32 @@ public ServerOpts getServerOpts() { | |
return opts; | ||
} | ||
|
||
/** | ||
* Sets common Ratis server properties for both the log and metadata state machines. | ||
*/ | ||
void setRaftProperties(RaftProperties properties) { | ||
// Set the ports for the server | ||
GrpcConfigKeys.Server.setPort(properties, opts.getPort()); | ||
NettyConfigKeys.Server.setPort(properties, opts.getPort()); | ||
|
||
// Ozone sets the leader election timeout (min) to 1second. | ||
TimeDuration leaderElectionTimeoutMin = TimeDuration.valueOf(1, TimeUnit.SECONDS); | ||
RaftServerConfigKeys.Rpc.setTimeoutMin(properties, leaderElectionTimeoutMin); | ||
TimeDuration leaderElectionMaxTimeout = TimeDuration.valueOf( | ||
leaderElectionTimeoutMin.toLong(TimeUnit.MILLISECONDS) + 200, | ||
TimeUnit.MILLISECONDS); | ||
RaftServerConfigKeys.Rpc.setTimeoutMax(properties, leaderElectionMaxTimeout); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same, why are we hardcoding these values? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a copy-paste out of Ozone. I don't have a good understand of why they chose these. Was going for just calling out things we want to set in Ratis, but leaving the actual configuration to the work Vlad is going to get to. |
||
} | ||
|
||
/** | ||
* Validates that there are no properties set which are in conflict with the LogService. | ||
*/ | ||
void validateRaftProperties(RaftProperties properties) { | ||
if (RaftServerConfigKeys.Snapshot.autoTriggerEnabled(properties)) { | ||
throw new IllegalStateException("Auto triggering snapshots is disallowed by the LogService"); | ||
} | ||
} | ||
|
||
static ServerOpts buildOpts(String hostname, String metaQuorum, int port, String workingDir) { | ||
ServerOpts opts = new ServerOpts(); | ||
opts.setHost(hostname); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,13 +23,13 @@ | |
import java.net.InetSocketAddress; | ||
import java.util.Collections; | ||
import java.util.Set; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import org.apache.ratis.client.RaftClient; | ||
import org.apache.ratis.client.RaftClientConfigKeys; | ||
import org.apache.ratis.conf.RaftProperties; | ||
import org.apache.ratis.grpc.GrpcConfigKeys; | ||
import org.apache.ratis.logservice.util.LogServiceUtils; | ||
import org.apache.ratis.logservice.util.MetaServiceProtoUtil; | ||
import org.apache.ratis.netty.NettyConfigKeys; | ||
import org.apache.ratis.protocol.ClientId; | ||
import org.apache.ratis.protocol.RaftGroup; | ||
import org.apache.ratis.protocol.RaftGroupId; | ||
|
@@ -38,6 +38,8 @@ | |
import org.apache.ratis.server.RaftServer; | ||
import org.apache.ratis.server.RaftServerConfigKeys; | ||
import org.apache.ratis.statemachine.StateMachine; | ||
import org.apache.ratis.util.SizeInBytes; | ||
import org.apache.ratis.util.TimeDuration; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
|
@@ -51,6 +53,7 @@ public class LogServer extends BaseServer { | |
|
||
public LogServer(ServerOpts opts) { | ||
super(opts); | ||
LOG.debug("Log Server options: {}", opts); | ||
} | ||
|
||
public RaftServer getServer() { | ||
|
@@ -61,13 +64,31 @@ public static Builder newBuilder() { | |
return new Builder(); | ||
} | ||
|
||
@Override | ||
void setRaftProperties(RaftProperties properties) { | ||
super.setRaftProperties(properties); | ||
|
||
// Increase the client timeout | ||
RaftClientConfigKeys.Rpc.setRequestTimeout(properties, TimeDuration.valueOf(100, TimeUnit.SECONDS)); | ||
|
||
// Increase the segment size to avoid rolling so quickly | ||
SizeInBytes segmentSize = SizeInBytes.valueOf("32MB"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why hardcoding? can't we do it through some config? or it is just default and will be overridden in later step? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Edit: was thinking about the write-buffer size. I don't think I played around with this. I left it here as something for us to come back to later, but not something I wanted to have people tweak. Maybe it's OK to still let this be configurable? (with a big-fat-warning :P) |
||
RaftServerConfigKeys.Log.setSegmentSizeMax(properties, segmentSize); | ||
RaftServerConfigKeys.Log.setPreallocatedSize(properties, segmentSize); | ||
|
||
// TODO this seems to cause errors, not sure if pushing Ratis too hard? | ||
// SizeInBytes writeBufferSize = SizeInBytes.valueOf("128KB"); | ||
// RaftServerConfigKeys.Log.setWriteBufferSize(properties, writeBufferSize); | ||
} | ||
|
||
public void start() throws IOException { | ||
final ServerOpts opts = getServerOpts(); | ||
Set<RaftPeer> peers = LogServiceUtils.getPeersFromQuorum(opts.getMetaQuorum()); | ||
RaftProperties properties = new RaftProperties(); | ||
properties.set("raft.client.rpc.request.timeout", "100000"); | ||
GrpcConfigKeys.Server.setPort(properties, opts.getPort()); | ||
NettyConfigKeys.Server.setPort(properties, opts.getPort()); | ||
|
||
// Set properties for the log server state machine | ||
setRaftProperties(properties); | ||
|
||
InetSocketAddress addr = new InetSocketAddress(opts.getHost(), opts.getPort()); | ||
if(opts.getWorkingDir() != null) { | ||
RaftServerConfigKeys.setStorageDirs(properties, Collections.singletonList(new File(opts.getWorkingDir()))); | ||
|
@@ -77,6 +98,10 @@ public void start() throws IOException { | |
final RaftGroupId logServerGroupId = RaftGroupId.valueOf(opts.getLogServerGroupId()); | ||
RaftGroup all = RaftGroup.valueOf(logServerGroupId, peer); | ||
RaftGroup meta = RaftGroup.valueOf(RaftGroupId.valueOf(opts.getMetaGroupId()), peers); | ||
|
||
// Make sure that we aren't setting any invalid/harmful properties | ||
validateRaftProperties(properties); | ||
|
||
raftServer = RaftServer.newBuilder() | ||
.setStateMachineRegistry(new StateMachine.Registry() { | ||
@Override | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good tuning guide.
But Snapshot.setAutoTriggerEnabled() config doesn't look like a tuning, as it impacts the log service, shouldn't we throw an exception if it is set to true or explicitly set to false in code(just to avoid human errors)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good suggestion. Let me change that.