Base heartbeats off Redis's TIME command.

People seem highly unwilling to actually synchronize their clocks for some reason, so I'll have to let them off the hook. Why am I doing this?
This commit is contained in:
Tux 2015-11-15 11:01:54 -05:00
parent 3102034e6b
commit e00d476233
1 changed files with 21 additions and 35 deletions

View File

@ -78,20 +78,24 @@ public final class RedisBungee extends Plugin {
return serverIds; return serverIds;
} }
private List<String> getCurrentServerIds() { private List<String> getCurrentServerIds(boolean nag, boolean lagged) {
try (Jedis jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
int nag = nagAboutServers.decrementAndGet(); long time = getRedisTime(jedis.time());
if (nag <= 0) { int nagTime = 0;
nagAboutServers.set(10); if (nag) {
nagTime = nagAboutServers.decrementAndGet();
if (nagTime <= 0) {
nagAboutServers.set(10);
}
} }
ImmutableList.Builder<String> servers = ImmutableList.builder(); ImmutableList.Builder<String> servers = ImmutableList.builder();
Map<String, String> heartbeats = jedis.hgetAll("heartbeats"); Map<String, String> heartbeats = jedis.hgetAll("heartbeats");
for (Map.Entry<String, String> entry : heartbeats.entrySet()) { for (Map.Entry<String, String> entry : heartbeats.entrySet()) {
try { try {
long stamp = Long.parseLong(entry.getValue()); long stamp = Long.parseLong(entry.getValue());
if (System.currentTimeMillis() < stamp + 30000) if (lagged ? time >= stamp + 30 : time <= stamp + 30)
servers.add(entry.getKey()); servers.add(entry.getKey());
else if (nag <= 0) { else if (nag && nagTime <= 0) {
getLogger().severe(entry.getKey() + " is " + (System.currentTimeMillis() - stamp) + "ms behind! (Time not synchronized or server down?)"); getLogger().severe(entry.getKey() + " is " + (System.currentTimeMillis() - stamp) + "ms behind! (Time not synchronized or server down?)");
} }
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
@ -99,34 +103,11 @@ public final class RedisBungee extends Plugin {
} }
return servers.build(); return servers.build();
} catch (JedisConnectionException e) { } catch (JedisConnectionException e) {
getLogger().log(Level.SEVERE, "Unable to fetch all server IDs", e); getLogger().log(Level.SEVERE, "Unable to fetch server IDs", e);
return Collections.singletonList(configuration.getServerId()); return Collections.singletonList(configuration.getServerId());
} }
} }
private List<String> getLaggedServerIds() {
try (Jedis jedis = pool.getResource()) {
int nag = nagAboutServers.decrementAndGet();
if (nag <= 0) {
nagAboutServers.set(10);
}
ImmutableList.Builder<String> servers = ImmutableList.builder();
Map<String, String> heartbeats = jedis.hgetAll("heartbeats");
for (Map.Entry<String, String> entry : heartbeats.entrySet()) {
try {
long stamp = Long.parseLong(entry.getValue());
if (System.currentTimeMillis() > stamp + 30000)
servers.add(entry.getKey());
} catch (NumberFormatException ignored) {
}
}
return servers.build();
} catch (JedisConnectionException e) {
getLogger().log(Level.SEVERE, "Unable to fetch lagged server IDs", e);
return Collections.emptyList();
}
}
public Set<UUID> getPlayersOnProxy(String server) { public Set<UUID> getPlayersOnProxy(String server) {
checkArgument(getServerIds().contains(server), server + " is not a valid proxy ID"); checkArgument(getServerIds().contains(server), server + " is not a valid proxy ID");
try (Jedis jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
@ -243,6 +224,10 @@ public final class RedisBungee extends Plugin {
} }
} }
private long getRedisTime(List<String> timeRes) {
return Long.parseLong(timeRes.get(0));
}
@Override @Override
public void onEnable() { public void onEnable() {
try { try {
@ -260,7 +245,7 @@ public final class RedisBungee extends Plugin {
if (s.startsWith("redis_version:")) { if (s.startsWith("redis_version:")) {
String version = s.split(":")[1]; String version = s.split(":")[1];
if (!(usingLua = RedisUtil.canUseLua(version))) { if (!(usingLua = RedisUtil.canUseLua(version))) {
getLogger().warning("Your version of Redis (" + version + ") is not at least version 2.6. RedisBungee requires a newer version."); getLogger().warning("Your version of Redis (" + version + ") is not at least version 2.6. RedisBungee requires a newer version of Redis.");
throw new RuntimeException("Unsupported Redis version detected"); throw new RuntimeException("Unsupported Redis version detected");
} else { } else {
LuaManager manager = new LuaManager(this); LuaManager manager = new LuaManager(this);
@ -277,18 +262,19 @@ public final class RedisBungee extends Plugin {
getLogger().info("Looks like you have a really big UUID cache! Run https://www.spigotmc.org/resources/redisbungeecleaner.8505/ as soon as possible."); getLogger().info("Looks like you have a really big UUID cache! Run https://www.spigotmc.org/resources/redisbungeecleaner.8505/ as soon as possible.");
} }
} }
serverIds = getCurrentServerIds(); serverIds = getCurrentServerIds(true, false);
uuidTranslator = new UUIDTranslator(this); uuidTranslator = new UUIDTranslator(this);
heartbeatTask = getProxy().getScheduler().schedule(this, new Runnable() { heartbeatTask = getProxy().getScheduler().schedule(this, new Runnable() {
@Override @Override
public void run() { public void run() {
try (Jedis rsc = pool.getResource()) { try (Jedis rsc = pool.getResource()) {
rsc.hset("heartbeats", configuration.getServerId(), String.valueOf(System.currentTimeMillis())); long redisTime = getRedisTime(rsc.time());
rsc.hset("heartbeats", configuration.getServerId(), String.valueOf(redisTime));
} catch (JedisConnectionException e) { } catch (JedisConnectionException e) {
// Redis server has disappeared! // Redis server has disappeared!
getLogger().log(Level.SEVERE, "Unable to update heartbeat - did your Redis server go away?", e); getLogger().log(Level.SEVERE, "Unable to update heartbeat - did your Redis server go away?", e);
} }
serverIds = getCurrentServerIds(); serverIds = getCurrentServerIds(true, false);
} }
}, 0, 3, TimeUnit.SECONDS); }, 0, 3, TimeUnit.SECONDS);
dataManager = new DataManager(this); dataManager = new DataManager(this);
@ -315,7 +301,7 @@ public final class RedisBungee extends Plugin {
try (Jedis tmpRsc = pool.getResource()) { try (Jedis tmpRsc = pool.getResource()) {
Set<String> players = getLocalPlayersAsUuidStrings(); Set<String> players = getLocalPlayersAsUuidStrings();
Set<String> playersInRedis = tmpRsc.smembers("proxy:" + configuration.getServerId() + ":usersOnline"); Set<String> playersInRedis = tmpRsc.smembers("proxy:" + configuration.getServerId() + ":usersOnline");
List<String> lagged = getLaggedServerIds(); List<String> lagged = getCurrentServerIds(false, true);
// Clean up lagged players. // Clean up lagged players.
for (String s : lagged) { for (String s : lagged) {