这是个一般性问题,参见这篇文章的描述:
先讲解一下FastDFS文件上传的执行流程:
获取trackerServer连接;
向trackerServer发送请求,获取一个可用的storageServer的IP;
(请求指令为104,参见TrackerClient.getStoreStorage方法)
注意,每次上传请求,都要重新获取storageServer(以便达到负载均衡等目的)。
另外,每次上传请求,可以重新获取trackerServer,也可以指定固定的trackerServer。
获取storageServer的逻辑,是由trackerServer服务器后端决定的,应用程序没有干预。
但是获取trackerServer的逻辑,是应用自己决定的。fastdfs-java-client获取trackerServer的逻辑如下:
public TrackerServer getConnection() throws IOException { return this.tracker_group.getConnection(); } public TrackerServer getConnection() throws IOException { int current_index; synchronized (this.lock) { this.tracker_server_index++; if (this.tracker_server_index >= this.tracker_servers.length) { this.tracker_server_index = 0; } current_index = this.tracker_server_index; } return this.getConnection(current_index); } public TrackerServer getConnection(int serverIndex) throws IOException { InetSocketAddress address = this.tracker_servers[serverIndex]; Socket sock = new SocketPool(pool, getConnection(address), address); return new TrackerServer(sock, address); }
以上代码的意思是:首先从用户配置的trackerServer地址里面去轮询、选择其中一个作为连接地址,然后跟这个地址建立网络连接(换句话说,客户端自己实现了一个简单的负载均衡机制)。这个设计主要是为 IP地址考虑的。如果trackerServer地址不是IP,而是域名,则存在问题:InetSocketAddress的来源是:
public InetSocketAddress(String hostname, int port) { checkHost(hostname); InetAddress addr = null; String host = null; try { addr = InetAddress.getByName(hostname); } catch(UnknownHostException e) { host = hostname; } holder = new InetSocketAddressHolder(host, addr, checkPort(port)); }
这段代码的关键是:InetAddress.getByName(hostname)。这个Java方法就是用来做域名解析的。
参见这篇文章:https://blog.csdn.net/weixin_34379433/article/details/93762404
所以,如果trackerServer配置的不是IP,而是域名,则该域名只会在第一次解析,后续程序永远不会再次解析这个域名了。当然,如果要配置域名,也不是不可以,但是应该配置多个域名,且每个域名对应一个唯一的IP,例如:
fdfs01.inner.zollty.com,fdfs02.inner.zollty.com,fdfs03.inner.zollty.com
像这样配置是正确的。但是配置成这样:fdfs.inner.zollty.com,然后DNS解析到3个IP,这就是错误的做法。
另外,我们从上面的代码也可以看到,如果使用了网络连接池,那其实最好是每次都重新获取trackerServer和storageServer,因为获取trackerServer成本很低,只需要new一个TrackerServer即可,它没有网络连接的开销。但是,获取storageServer是有网络开销的,开销来源于 客户端程序会通过trackerServer去查询可用的storageServer的IP。
相对于上传文件的开销成本,连接一次trackerServer的开销并不大,所以我认为这种逻辑是可以接受的。
如果不去查询,每次都复用storageServer可不可以?看下面的代码:
public StorageServer getStorageServer(String ip_addr, int port, int store_path) throws IOException { InetSocketAddress address = new InetSocketAddress(ip_addr, port); Socket sock = new SocketPool(pool, getConnection(address), address); return new StorageServer(sock, address, store_path); } private Connection getConnection(InetSocketAddress address) { Connection conn; try { // 从连接池中获取连接 conn = pool.borrowObject(address); } catch (Exception e) { throw new NestedRuntimeException(e, "从连接池中获取连接异常"); } return conn; }
StorageServer有一个socket类属性,它持有一个Connection连接。其实没必要一直占用这个连接。用完直接归还就是。
其实真正的复用,是复用StorageServer的InetSocketAddress,而非StorageServer本身。