You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hbase.apache.org by "Ted Yu (JIRA)" <ji...@apache.org> on 2013/05/28 19:59:20 UTC

[jira] [Commented] (HBASE-8630) Share Socket Connections for different HConnectionImplementations

    [ https://issues.apache.org/jira/browse/HBASE-8630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13668493#comment-13668493 ] 

Ted Yu commented on HBASE-8630:
-------------------------------

Interesting.
How about calling ticket.getUGI().hashCode() ?
                
> Share Socket Connections for different HConnectionImplementations
> -----------------------------------------------------------------
>
>                 Key: HBASE-8630
>                 URL: https://issues.apache.org/jira/browse/HBASE-8630
>             Project: HBase
>          Issue Type: Improvement
>          Components: Client
>    Affects Versions: 0.94.3
>            Reporter: cuijianwei
>
> In org.apache.hadoop.hbase.ipc.HBaseClient.java, socket connections are pooled by map as:
> {code} protected final PoolMap<ConnectionId, Connection> connections; {code}
> The hashCode of ConnectionId is defined as:
> {code}     public int hashCode() {
>       return (address.hashCode() + PRIME * (
>                   PRIME * System.identityHashCode(protocol) ^
>              (ticket == null ? 0 : ticket.hashCode()) )) ^ rpcTimeout;
>     } {code}
> As we can see, ticket.hashCode() will contribute to hashCode of ConnectionId. For hbase without authentication, the ticket should be a HadoopUser; while for hbase with authentication, the ticket should be a SecureHadoopUser. Neither HadoopUser nor SecureHadoopUser override hashCode() method, therefore, two tickets have the same hashCode only when they refer to the same object.
>   On the other hand, when we use HTable to access hbase, firstly, we will invoke HBaseRPC.waitForProxy(...) to create a proxy for region server as follows:
> {code}              server = (HRegionInterface) HBaseRPC.waitForProxy(
>                   serverInterfaceClass, HRegionInterface.VERSION,
>                   address, this.conf,
>                   this.maxRPCAttempts, this.rpcTimeout, this.rpcTimeout); {code}
> Then HBaseRpc.getProxy(...) will be called as follows:
> {code}public static VersionedProtocol getProxy(Class<? extends VersionedProtocol> protocol,
>       long clientVersion, InetSocketAddress addr, Configuration conf,
>       SocketFactory factory, int rpcTimeout) throws IOException {
>     return getProxy(protocol, clientVersion, addr,
>         User.getCurrent(), conf, factory, rpcTimeout);
>   } {code}
> We can see, User.getCurrent() will be invoked to generate the ticket to build socket connection. User.getCurrent() is defined as:
> {code}
> public static User getCurrent() throws IOException {
>     User user;
>     if (IS_SECURE_HADOOP) {
>       user = new SecureHadoopUser();
>     } else {
>       user = new HadoopUser();
>     }
>     if (user.getUGI() == null) {
>       return null;
>     }
>     return user;
>   }
> {code}
> Therefore, we will get different tickets when we create different proxies for the same region server, so that these proxies can't share the created socket connections and will create new socket connections even if they have the same HBaseConfiguration.
> We can use the following case to validate the description above:
> {code}
> public static void main(String args[]) throws Exception {
>     Configuration conf = HBaseConfiguration.create();
>     for (int i = 0;; ++i) {
>       HTable table = new HTable(conf, TestTable.testTableName);
>       table.close();
>     }
> }
> {code}
> Each time we close the HTable, the created region server proxies will be closed as the underlying HConnectionImplementation will be closed. However, the created socket connections won't be closed and wait to be shared in future. Then, when we create HTable in the next turn, we will create server proxy again, get a new ticket and consequently create new socket connections. The created socket connections last turn can not be used any more. As the loop goes on, thousands of socket will be created to connect region servers until we get an exception to show no more sockets could be created.
> To fix the problem, maybe, we can use ticket.getName().hashCode() instead of ticket.hashCode()?

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira