HBASE-12954 Ability impaired using HBase on multihomed hosts

This commit is contained in:
tedyu 2015-04-01 06:49:09 -07:00
parent 6415742c37
commit 874aa9eb85
9 changed files with 459 additions and 66 deletions

View File

@ -921,6 +921,13 @@ possible configurations would overwhelm and obscure the important.
<description>Set no delay on rpc socket connections. See <description>Set no delay on rpc socket connections. See
http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#getTcpNoDelay()</description> http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#getTcpNoDelay()</description>
</property> </property>
<property>
<name>hbase.regionserver.hostname</name>
<value></value>
<description>This config is for experts: don't set its value unless you really know what you are doing.
When set to a non-empty value, this represents the (external facing) hostname for the underlying server.
See https://issues.apache.org/jira/browse/HBASE-12954 for details.</description>
</property>
<!-- The following properties configure authentication information for <!-- The following properties configure authentication information for
HBase processes when using Kerberos security. There are no default HBase processes when using Kerberos security. There are no default
values, included here for documentation purposes --> values, included here for documentation purposes -->

View File

@ -64,6 +64,33 @@ public final class RegionServerStatusProtos {
* </pre> * </pre>
*/ */
long getServerCurrentTime(); long getServerCurrentTime();
// optional string use_this_hostname_instead = 4;
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
boolean hasUseThisHostnameInstead();
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
java.lang.String getUseThisHostnameInstead();
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
com.google.protobuf.ByteString
getUseThisHostnameInsteadBytes();
} }
/** /**
* Protobuf type {@code RegionServerStartupRequest} * Protobuf type {@code RegionServerStartupRequest}
@ -131,6 +158,11 @@ public final class RegionServerStatusProtos {
serverCurrentTime_ = input.readUInt64(); serverCurrentTime_ = input.readUInt64();
break; break;
} }
case 34: {
bitField0_ |= 0x00000008;
useThisHostnameInstead_ = input.readBytes();
break;
}
} }
} }
} catch (com.google.protobuf.InvalidProtocolBufferException e) { } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -243,10 +275,66 @@ public final class RegionServerStatusProtos {
return serverCurrentTime_; return serverCurrentTime_;
} }
// optional string use_this_hostname_instead = 4;
public static final int USE_THIS_HOSTNAME_INSTEAD_FIELD_NUMBER = 4;
private java.lang.Object useThisHostnameInstead_;
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public boolean hasUseThisHostnameInstead() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public java.lang.String getUseThisHostnameInstead() {
java.lang.Object ref = useThisHostnameInstead_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
useThisHostnameInstead_ = s;
}
return s;
}
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public com.google.protobuf.ByteString
getUseThisHostnameInsteadBytes() {
java.lang.Object ref = useThisHostnameInstead_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
useThisHostnameInstead_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private void initFields() { private void initFields() {
port_ = 0; port_ = 0;
serverStartCode_ = 0L; serverStartCode_ = 0L;
serverCurrentTime_ = 0L; serverCurrentTime_ = 0L;
useThisHostnameInstead_ = "";
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@ -281,6 +369,9 @@ public final class RegionServerStatusProtos {
if (((bitField0_ & 0x00000004) == 0x00000004)) { if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeUInt64(3, serverCurrentTime_); output.writeUInt64(3, serverCurrentTime_);
} }
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(4, getUseThisHostnameInsteadBytes());
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@ -302,6 +393,10 @@ public final class RegionServerStatusProtos {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeUInt64Size(3, serverCurrentTime_); .computeUInt64Size(3, serverCurrentTime_);
} }
if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, getUseThisHostnameInsteadBytes());
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@ -340,6 +435,11 @@ public final class RegionServerStatusProtos {
result = result && (getServerCurrentTime() result = result && (getServerCurrentTime()
== other.getServerCurrentTime()); == other.getServerCurrentTime());
} }
result = result && (hasUseThisHostnameInstead() == other.hasUseThisHostnameInstead());
if (hasUseThisHostnameInstead()) {
result = result && getUseThisHostnameInstead()
.equals(other.getUseThisHostnameInstead());
}
result = result && result = result &&
getUnknownFields().equals(other.getUnknownFields()); getUnknownFields().equals(other.getUnknownFields());
return result; return result;
@ -365,6 +465,10 @@ public final class RegionServerStatusProtos {
hash = (37 * hash) + SERVER_CURRENT_TIME_FIELD_NUMBER; hash = (37 * hash) + SERVER_CURRENT_TIME_FIELD_NUMBER;
hash = (53 * hash) + hashLong(getServerCurrentTime()); hash = (53 * hash) + hashLong(getServerCurrentTime());
} }
if (hasUseThisHostnameInstead()) {
hash = (37 * hash) + USE_THIS_HOSTNAME_INSTEAD_FIELD_NUMBER;
hash = (53 * hash) + getUseThisHostnameInstead().hashCode();
}
hash = (29 * hash) + getUnknownFields().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash; memoizedHashCode = hash;
return hash; return hash;
@ -480,6 +584,8 @@ public final class RegionServerStatusProtos {
bitField0_ = (bitField0_ & ~0x00000002); bitField0_ = (bitField0_ & ~0x00000002);
serverCurrentTime_ = 0L; serverCurrentTime_ = 0L;
bitField0_ = (bitField0_ & ~0x00000004); bitField0_ = (bitField0_ & ~0x00000004);
useThisHostnameInstead_ = "";
bitField0_ = (bitField0_ & ~0x00000008);
return this; return this;
} }
@ -520,6 +626,10 @@ public final class RegionServerStatusProtos {
to_bitField0_ |= 0x00000004; to_bitField0_ |= 0x00000004;
} }
result.serverCurrentTime_ = serverCurrentTime_; result.serverCurrentTime_ = serverCurrentTime_;
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
result.useThisHostnameInstead_ = useThisHostnameInstead_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@ -545,6 +655,11 @@ public final class RegionServerStatusProtos {
if (other.hasServerCurrentTime()) { if (other.hasServerCurrentTime()) {
setServerCurrentTime(other.getServerCurrentTime()); setServerCurrentTime(other.getServerCurrentTime());
} }
if (other.hasUseThisHostnameInstead()) {
bitField0_ |= 0x00000008;
useThisHostnameInstead_ = other.useThisHostnameInstead_;
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@ -731,6 +846,104 @@ public final class RegionServerStatusProtos {
return this; return this;
} }
// optional string use_this_hostname_instead = 4;
private java.lang.Object useThisHostnameInstead_ = "";
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public boolean hasUseThisHostnameInstead() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public java.lang.String getUseThisHostnameInstead() {
java.lang.Object ref = useThisHostnameInstead_;
if (!(ref instanceof java.lang.String)) {
java.lang.String s = ((com.google.protobuf.ByteString) ref)
.toStringUtf8();
useThisHostnameInstead_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public com.google.protobuf.ByteString
getUseThisHostnameInsteadBytes() {
java.lang.Object ref = useThisHostnameInstead_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
useThisHostnameInstead_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public Builder setUseThisHostnameInstead(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000008;
useThisHostnameInstead_ = value;
onChanged();
return this;
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public Builder clearUseThisHostnameInstead() {
bitField0_ = (bitField0_ & ~0x00000008);
useThisHostnameInstead_ = getDefaultInstance().getUseThisHostnameInstead();
onChanged();
return this;
}
/**
* <code>optional string use_this_hostname_instead = 4;</code>
*
* <pre>
** hostname for region server, optional
* </pre>
*/
public Builder setUseThisHostnameInsteadBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000008;
useThisHostnameInstead_ = value;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:RegionServerStartupRequest) // @@protoc_insertion_point(builder_scope:RegionServerStartupRequest)
} }
@ -8891,48 +9104,49 @@ public final class RegionServerStatusProtos {
static { static {
java.lang.String[] descriptorData = { java.lang.String[] descriptorData = {
"\n\030RegionServerStatus.proto\032\013HBase.proto\032" + "\n\030RegionServerStatus.proto\032\013HBase.proto\032" +
"\023ClusterStatus.proto\"b\n\032RegionServerStar" + "\023ClusterStatus.proto\"\205\001\n\032RegionServerSta" +
"tupRequest\022\014\n\004port\030\001 \002(\r\022\031\n\021server_start" + "rtupRequest\022\014\n\004port\030\001 \002(\r\022\031\n\021server_star" +
"_code\030\002 \002(\004\022\033\n\023server_current_time\030\003 \002(\004" + "t_code\030\002 \002(\004\022\033\n\023server_current_time\030\003 \002(" +
"\"C\n\033RegionServerStartupResponse\022$\n\013map_e" + "\004\022!\n\031use_this_hostname_instead\030\004 \001(\t\"C\n\033" +
"ntries\030\001 \003(\0132\017.NameStringPair\"S\n\031RegionS" + "RegionServerStartupResponse\022$\n\013map_entri" +
"erverReportRequest\022\033\n\006server\030\001 \002(\0132\013.Ser" + "es\030\001 \003(\0132\017.NameStringPair\"S\n\031RegionServe" +
"verName\022\031\n\004load\030\002 \001(\0132\013.ServerLoad\"\034\n\032Re" + "rReportRequest\022\033\n\006server\030\001 \002(\0132\013.ServerN" +
"gionServerReportResponse\"O\n\031ReportRSFata" + "ame\022\031\n\004load\030\002 \001(\0132\013.ServerLoad\"\034\n\032Region" +
"lErrorRequest\022\033\n\006server\030\001 \002(\0132\013.ServerNa", "ServerReportResponse\"O\n\031ReportRSFatalErr",
"me\022\025\n\rerror_message\030\002 \002(\t\"\034\n\032ReportRSFat" + "orRequest\022\033\n\006server\030\001 \002(\0132\013.ServerName\022\025" +
"alErrorResponse\"6\n\037GetLastFlushedSequenc" + "\n\rerror_message\030\002 \002(\t\"\034\n\032ReportRSFatalEr" +
"eIdRequest\022\023\n\013region_name\030\001 \002(\014\"~\n GetLa" + "rorResponse\"6\n\037GetLastFlushedSequenceIdR" +
"stFlushedSequenceIdResponse\022 \n\030last_flus" + "equest\022\023\n\013region_name\030\001 \002(\014\"~\n GetLastFl" +
"hed_sequence_id\030\001 \002(\004\0228\n\036store_last_flus" + "ushedSequenceIdResponse\022 \n\030last_flushed_" +
"hed_sequence_id\030\002 \003(\0132\020.StoreSequenceId\"" + "sequence_id\030\001 \002(\004\0228\n\036store_last_flushed_" +
"\322\002\n\025RegionStateTransition\022>\n\017transition_" + "sequence_id\030\002 \003(\0132\020.StoreSequenceId\"\322\002\n\025" +
"code\030\001 \002(\0162%.RegionStateTransition.Trans" + "RegionStateTransition\022>\n\017transition_code" +
"itionCode\022 \n\013region_info\030\002 \003(\0132\013.RegionI" + "\030\001 \002(\0162%.RegionStateTransition.Transitio" +
"nfo\022\024\n\014open_seq_num\030\003 \001(\004\"\300\001\n\016Transition", "nCode\022 \n\013region_info\030\002 \003(\0132\013.RegionInfo\022",
"Code\022\n\n\006OPENED\020\000\022\017\n\013FAILED_OPEN\020\001\022\n\n\006CLO" + "\024\n\014open_seq_num\030\003 \001(\004\"\300\001\n\016TransitionCode" +
"SED\020\002\022\022\n\016READY_TO_SPLIT\020\003\022\022\n\016READY_TO_ME" + "\022\n\n\006OPENED\020\000\022\017\n\013FAILED_OPEN\020\001\022\n\n\006CLOSED\020" +
"RGE\020\004\022\016\n\nSPLIT_PONR\020\005\022\016\n\nMERGE_PONR\020\006\022\t\n" + "\002\022\022\n\016READY_TO_SPLIT\020\003\022\022\n\016READY_TO_MERGE\020" +
"\005SPLIT\020\007\022\n\n\006MERGED\020\010\022\022\n\016SPLIT_REVERTED\020\t" + "\004\022\016\n\nSPLIT_PONR\020\005\022\016\n\nMERGE_PONR\020\006\022\t\n\005SPL" +
"\022\022\n\016MERGE_REVERTED\020\n\"m\n\"ReportRegionStat" + "IT\020\007\022\n\n\006MERGED\020\010\022\022\n\016SPLIT_REVERTED\020\t\022\022\n\016" +
"eTransitionRequest\022\033\n\006server\030\001 \002(\0132\013.Ser" + "MERGE_REVERTED\020\n\"m\n\"ReportRegionStateTra" +
"verName\022*\n\ntransition\030\002 \003(\0132\026.RegionStat" + "nsitionRequest\022\033\n\006server\030\001 \002(\0132\013.ServerN" +
"eTransition\"<\n#ReportRegionStateTransiti" + "ame\022*\n\ntransition\030\002 \003(\0132\026.RegionStateTra" +
"onResponse\022\025\n\rerror_message\030\001 \001(\t2\326\003\n\031Re" + "nsition\"<\n#ReportRegionStateTransitionRe" +
"gionServerStatusService\022P\n\023RegionServerS", "sponse\022\025\n\rerror_message\030\001 \001(\t2\326\003\n\031Region",
"tartup\022\033.RegionServerStartupRequest\032\034.Re" + "ServerStatusService\022P\n\023RegionServerStart" +
"gionServerStartupResponse\022M\n\022RegionServe" + "up\022\033.RegionServerStartupRequest\032\034.Region" +
"rReport\022\032.RegionServerReportRequest\032\033.Re" + "ServerStartupResponse\022M\n\022RegionServerRep" +
"gionServerReportResponse\022M\n\022ReportRSFata" + "ort\022\032.RegionServerReportRequest\032\033.Region" +
"lError\022\032.ReportRSFatalErrorRequest\032\033.Rep" + "ServerReportResponse\022M\n\022ReportRSFatalErr" +
"ortRSFatalErrorResponse\022_\n\030GetLastFlushe" + "or\022\032.ReportRSFatalErrorRequest\032\033.ReportR" +
"dSequenceId\022 .GetLastFlushedSequenceIdRe" + "SFatalErrorResponse\022_\n\030GetLastFlushedSeq" +
"quest\032!.GetLastFlushedSequenceIdResponse" + "uenceId\022 .GetLastFlushedSequenceIdReques" +
"\022h\n\033ReportRegionStateTransition\022#.Report" + "t\032!.GetLastFlushedSequenceIdResponse\022h\n\033" +
"RegionStateTransitionRequest\032$.ReportReg", "ReportRegionStateTransition\022#.ReportRegi",
"ionStateTransitionResponseBN\n*org.apache" + "onStateTransitionRequest\032$.ReportRegionS" +
".hadoop.hbase.protobuf.generatedB\030Region" + "tateTransitionResponseBN\n*org.apache.had" +
"ServerStatusProtosH\001\210\001\001\240\001\001" "oop.hbase.protobuf.generatedB\030RegionServ" +
"erStatusProtosH\001\210\001\001\240\001\001"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -8944,7 +9158,7 @@ public final class RegionServerStatusProtos {
internal_static_RegionServerStartupRequest_fieldAccessorTable = new internal_static_RegionServerStartupRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_RegionServerStartupRequest_descriptor, internal_static_RegionServerStartupRequest_descriptor,
new java.lang.String[] { "Port", "ServerStartCode", "ServerCurrentTime", }); new java.lang.String[] { "Port", "ServerStartCode", "ServerCurrentTime", "UseThisHostnameInstead", });
internal_static_RegionServerStartupResponse_descriptor = internal_static_RegionServerStartupResponse_descriptor =
getDescriptor().getMessageTypes().get(1); getDescriptor().getMessageTypes().get(1);
internal_static_RegionServerStartupResponse_fieldAccessorTable = new internal_static_RegionServerStartupResponse_fieldAccessorTable = new

View File

@ -36,6 +36,9 @@ message RegionServerStartupRequest {
/** Current time of the region server in ms */ /** Current time of the region server in ms */
required uint64 server_current_time = 3; required uint64 server_current_time = 3;
/** hostname for region server, optional */
optional string use_this_hostname_instead = 4;
} }
message RegionServerStartupResponse { message RegionServerStartupResponse {

View File

@ -304,8 +304,9 @@ public class MasterRpcServices extends RSRpcServices
master.checkServiceStarted(); master.checkServiceStarted();
InetAddress ia = master.getRemoteInetAddress( InetAddress ia = master.getRemoteInetAddress(
request.getPort(), request.getServerStartCode()); request.getPort(), request.getServerStartCode());
ServerName rs = master.serverManager.regionServerStartup(ia, request.getPort(), // if regionserver passed hostname to use,
request.getServerStartCode(), request.getServerCurrentTime()); // then use it instead of doing a reverse DNS lookup
ServerName rs = master.serverManager.regionServerStartup(request, ia);
// Send back some config info // Send back some config info
RegionServerStartupResponse.Builder resp = createConfigurationSubset(); RegionServerStartupResponse.Builder resp = createConfigurationSubset();

View File

@ -62,6 +62,7 @@ import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionResponse; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionResponse;
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds; import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionStoreSequenceIds;
import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.StoreSequenceId; import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.StoreSequenceId;
import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode;
@ -239,15 +240,12 @@ public class ServerManager {
/** /**
* Let the server manager know a new regionserver has come online * Let the server manager know a new regionserver has come online
* @param ia The remote address * @param request the startup request
* @param port The remote port * @param ia the InetAddress from which request is received
* @param serverStartcode
* @param serverCurrentTime The current time of the region server in ms
* @return The ServerName we know this server as. * @return The ServerName we know this server as.
* @throws IOException * @throws IOException
*/ */
ServerName regionServerStartup(final InetAddress ia, final int port, ServerName regionServerStartup(RegionServerStartupRequest request, InetAddress ia)
final long serverStartcode, long serverCurrentTime)
throws IOException { throws IOException {
// Test for case where we get a region startup message from a regionserver // Test for case where we get a region startup message from a regionserver
// that has been quickly restarted but whose znode expiration handler has // that has been quickly restarted but whose znode expiration handler has
@ -256,8 +254,12 @@ public class ServerManager {
// is, reject the server and trigger its expiration. The next time it comes // is, reject the server and trigger its expiration. The next time it comes
// in, it should have been removed from serverAddressToServerInfo and queued // in, it should have been removed from serverAddressToServerInfo and queued
// for processing by ProcessServerShutdown. // for processing by ProcessServerShutdown.
ServerName sn = ServerName.valueOf(ia.getHostName(), port, serverStartcode);
checkClockSkew(sn, serverCurrentTime); final String hostname = request.hasUseThisHostnameInstead() ?
request.getUseThisHostnameInstead() :ia.getHostName();
ServerName sn = ServerName.valueOf(hostname, request.getPort(),
request.getServerStartCode());
checkClockSkew(sn, request.getServerCurrentTime());
checkIsDead(sn, "STARTUP"); checkIsDead(sn, "STARTUP");
if (!checkAndRecordNewServer(sn, ServerLoad.EMPTY_SERVERLOAD)) { if (!checkAndRecordNewServer(sn, ServerLoad.EMPTY_SERVERLOAD)) {
LOG.warn("THIS SHOULD NOT HAPPEN, RegionServerStartup" LOG.warn("THIS SHOULD NOT HAPPEN, RegionServerStartup"

View File

@ -399,6 +399,16 @@ public class HRegionServer extends HasThread implements
*/ */
protected ServerName serverName; protected ServerName serverName;
/*
* hostname specified by hostname config
*/
protected String useThisHostnameInstead;
// key to the config parameter of server hostname
// the specification of server hostname is optional. The hostname should be resolvable from
// both master and region server
final static String HOSTNAME_KEY = "hbase.regionserver.hostname";
/** /**
* This servers startcode. * This servers startcode.
*/ */
@ -516,7 +526,9 @@ public class HRegionServer extends HasThread implements
rpcServices = createRpcServices(); rpcServices = createRpcServices();
this.startcode = System.currentTimeMillis(); this.startcode = System.currentTimeMillis();
String hostName = rpcServices.isa.getHostName(); useThisHostnameInstead = conf.get(HOSTNAME_KEY);
String hostName = shouldUseThisHostnameInstead() ? useThisHostnameInstead :
rpcServices.isa.getHostName();
serverName = ServerName.valueOf(hostName, rpcServices.isa.getPort(), startcode); serverName = ServerName.valueOf(hostName, rpcServices.isa.getPort(), startcode);
rpcControllerFactory = RpcControllerFactory.instantiate(this.conf); rpcControllerFactory = RpcControllerFactory.instantiate(this.conf);
@ -582,6 +594,13 @@ public class HRegionServer extends HasThread implements
this.fs, this.rootDir, !canUpdateTableDescriptor(), false); this.fs, this.rootDir, !canUpdateTableDescriptor(), false);
} }
/*
* Returns true if configured hostname should be used
*/
protected boolean shouldUseThisHostnameInstead() {
return useThisHostnameInstead != null && !useThisHostnameInstead.isEmpty();
}
protected void login(UserProvider user, String host) throws IOException { protected void login(UserProvider user, String host) throws IOException {
user.login("hbase.regionserver.keytab.file", user.login("hbase.regionserver.keytab.file",
"hbase.regionserver.kerberos.principal", host); "hbase.regionserver.kerberos.principal", host);
@ -1290,9 +1309,18 @@ public class HRegionServer extends HasThread implements
String hostnameFromMasterPOV = e.getValue(); String hostnameFromMasterPOV = e.getValue();
this.serverName = ServerName.valueOf(hostnameFromMasterPOV, this.serverName = ServerName.valueOf(hostnameFromMasterPOV,
rpcServices.isa.getPort(), this.startcode); rpcServices.isa.getPort(), this.startcode);
if (!hostnameFromMasterPOV.equals(rpcServices.isa.getHostName())) { if (shouldUseThisHostnameInstead() &&
LOG.info("Master passed us a different hostname to use; was=" + !hostnameFromMasterPOV.equals(useThisHostnameInstead)) {
rpcServices.isa.getHostName() + ", but now=" + hostnameFromMasterPOV); String msg = "Master passed us a different hostname to use; was=" +
this.useThisHostnameInstead + ", but now=" + hostnameFromMasterPOV;
LOG.error(msg);
throw new IOException(msg);
}
if (!shouldUseThisHostnameInstead() &&
!hostnameFromMasterPOV.equals(rpcServices.isa.getHostName())) {
String msg = "Master passed us a different hostname to use; was=" +
rpcServices.isa.getHostName() + ", but now=" + hostnameFromMasterPOV;
LOG.error(msg);
} }
continue; continue;
} }
@ -2203,6 +2231,9 @@ public class HRegionServer extends HasThread implements
long now = EnvironmentEdgeManager.currentTime(); long now = EnvironmentEdgeManager.currentTime();
int port = rpcServices.isa.getPort(); int port = rpcServices.isa.getPort();
RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder(); RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
if (shouldUseThisHostnameInstead()) {
request.setUseThisHostnameInstead(useThisHostnameInstead);
}
request.setPort(port); request.setPort(port);
request.setServerStartCode(this.startcode); request.setServerStartCode(this.startcode);
request.setServerCurrentTime(now); request.setServerCurrentTime(now);

View File

@ -830,9 +830,15 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
} }
public static String getHostname(Configuration conf) throws UnknownHostException { public static String getHostname(Configuration conf) throws UnknownHostException {
String hostname = conf.get(HRegionServer.HOSTNAME_KEY);
if (hostname == null || hostname.isEmpty()) {
return Strings.domainNamePointerToHostName(DNS.getDefaultHost( return Strings.domainNamePointerToHostName(DNS.getDefaultHost(
conf.get("hbase.regionserver.dns.interface", "default"), conf.get("hbase.regionserver.dns.interface", "default"),
conf.get("hbase.regionserver.dns.nameserver", "default"))); conf.get("hbase.regionserver.dns.nameserver", "default")));
} else {
LOG.info("hostname is configured to be " + hostname);
return hostname;
}
} }
RegionScanner getScanner(long scannerId) { RegionScanner getScanner(long scannerId) {

View File

@ -32,6 +32,7 @@ import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.Server;
import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.client.ClusterConnection; import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
import org.apache.hadoop.hbase.testclassification.MasterTests; import org.apache.hadoop.hbase.testclassification.MasterTests;
import org.apache.hadoop.hbase.testclassification.SmallTests; import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
@ -103,7 +104,11 @@ public class TestClockSkewDetection {
LOG.debug("regionServerStartup 1"); LOG.debug("regionServerStartup 1");
InetAddress ia1 = InetAddress.getLocalHost(); InetAddress ia1 = InetAddress.getLocalHost();
sm.regionServerStartup(ia1, 1234, -1, System.currentTimeMillis()); RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
request.setPort(1234);
request.setServerStartCode(-1);
request.setServerCurrentTime(System.currentTimeMillis());
sm.regionServerStartup(request.build(), ia1);
final Configuration c = HBaseConfiguration.create(); final Configuration c = HBaseConfiguration.create();
long maxSkew = c.getLong("hbase.master.maxclockskew", 30000); long maxSkew = c.getLong("hbase.master.maxclockskew", 30000);
@ -114,7 +119,11 @@ public class TestClockSkewDetection {
LOG.debug("Test: Master Time > Region Server Time"); LOG.debug("Test: Master Time > Region Server Time");
LOG.debug("regionServerStartup 2"); LOG.debug("regionServerStartup 2");
InetAddress ia2 = InetAddress.getLocalHost(); InetAddress ia2 = InetAddress.getLocalHost();
sm.regionServerStartup(ia2, 1235, -1, System.currentTimeMillis() - maxSkew * 2); request = RegionServerStartupRequest.newBuilder();
request.setPort(1235);
request.setServerStartCode(-1);
request.setServerCurrentTime(System.currentTimeMillis() - maxSkew * 2);
sm.regionServerStartup(request.build(), ia2);
fail("HMaster should have thrown a ClockOutOfSyncException but didn't."); fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
} catch(ClockOutOfSyncException e) { } catch(ClockOutOfSyncException e) {
//we want an exception //we want an exception
@ -126,7 +135,11 @@ public class TestClockSkewDetection {
LOG.debug("Test: Master Time < Region Server Time"); LOG.debug("Test: Master Time < Region Server Time");
LOG.debug("regionServerStartup 3"); LOG.debug("regionServerStartup 3");
InetAddress ia3 = InetAddress.getLocalHost(); InetAddress ia3 = InetAddress.getLocalHost();
sm.regionServerStartup(ia3, 1236, -1, System.currentTimeMillis() + maxSkew * 2); request = RegionServerStartupRequest.newBuilder();
request.setPort(1236);
request.setServerStartCode(-1);
request.setServerCurrentTime(System.currentTimeMillis() + maxSkew * 2);
sm.regionServerStartup(request.build(), ia3);
fail("HMaster should have thrown a ClockOutOfSyncException but didn't."); fail("HMaster should have thrown a ClockOutOfSyncException but didn't.");
} catch (ClockOutOfSyncException e) { } catch (ClockOutOfSyncException e) {
// we want an exception // we want an exception
@ -136,12 +149,20 @@ public class TestClockSkewDetection {
// make sure values above warning threshold but below max threshold don't kill // make sure values above warning threshold but below max threshold don't kill
LOG.debug("regionServerStartup 4"); LOG.debug("regionServerStartup 4");
InetAddress ia4 = InetAddress.getLocalHost(); InetAddress ia4 = InetAddress.getLocalHost();
sm.regionServerStartup(ia4, 1237, -1, System.currentTimeMillis() - warningSkew * 2); request = RegionServerStartupRequest.newBuilder();
request.setPort(1237);
request.setServerStartCode(-1);
request.setServerCurrentTime(System.currentTimeMillis() - warningSkew * 2);
sm.regionServerStartup(request.build(), ia4);
// make sure values above warning threshold but below max threshold don't kill // make sure values above warning threshold but below max threshold don't kill
LOG.debug("regionServerStartup 5"); LOG.debug("regionServerStartup 5");
InetAddress ia5 = InetAddress.getLocalHost(); InetAddress ia5 = InetAddress.getLocalHost();
sm.regionServerStartup(ia5, 1238, -1, System.currentTimeMillis() + warningSkew * 2); request = RegionServerStartupRequest.newBuilder();
request.setPort(1238);
request.setServerStartCode(-1);
request.setServerCurrentTime(System.currentTimeMillis() + warningSkew * 2);
sm.regionServerStartup(request.build(), ia5);
} }

View File

@ -0,0 +1,108 @@
/**
* 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.
*/
package org.apache.hadoop.hbase.regionserver;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.CoordinatedStateManager;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.MiniHBaseCluster.MiniHBaseClusterRegionServer;
import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
import org.apache.hadoop.hbase.util.Threads;
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Tests for the hostname specification by region server
*/
@Category({RegionServerTests.class, MediumTests.class})
public class TestRegionServerHostname {
private static final Log LOG = LogFactory.getLog(TestRegionServerHostname.class);
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
@Test (timeout=30000)
public void testInvalidRegionServerHostnameAbortsServer() throws Exception {
final int NUM_MASTERS = 1;
final int NUM_RS = 1;
String invalidHostname = "hostAddr";
TEST_UTIL.getConfiguration().set(HRegionServer.HOSTNAME_KEY, invalidHostname);
try {
TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
} catch (IOException ioe) {
Throwable t1 = ioe.getCause();
Throwable t2 = t1.getCause();
assertTrue(t2.getMessage().contains("Failed resolve of " + invalidHostname));
return;
} finally {
TEST_UTIL.shutdownMiniCluster();
}
assertTrue("Failed to validate against invalid hostname", false);
}
@Test(timeout=120000)
public void testRegionServerHostname() throws Exception {
final int NUM_MASTERS = 1;
final int NUM_RS = 1;
Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
while (netInterfaceList.hasMoreElements()) {
NetworkInterface ni = netInterfaceList.nextElement();
Enumeration<InetAddress> addrList = ni.getInetAddresses();
// iterate through host addresses and use each as hostname
while (addrList.hasMoreElements()) {
InetAddress addr = addrList.nextElement();
if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
continue;
}
String hostName = addr.getHostName();
LOG.info("Found " + hostName + " on " + ni);
TEST_UTIL.getConfiguration().set(HRegionServer.HOSTNAME_KEY, hostName);
TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
try {
ZooKeeperWatcher zkw = TEST_UTIL.getZooKeeperWatcher();
List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.rsZNode);
// there would be NUM_RS+1 children - one for the master
assertTrue(servers.size() == NUM_RS+1);
for (String server : servers) {
assertTrue(server.startsWith(hostName+","));
}
zkw.close();
} finally {
TEST_UTIL.shutdownMiniCluster();
}
}
}
}
}