LocalFirstPolicy是一个优先返回本地主机的定位策略,如果本地worker没有足够的容量,那么就会从活跃有效的workers列表随机选择一个worker用于每个块写入。在其内部,有一个关键的成员变量mLocalHostName,即本地主机名,它是用于选择本地本机worker的关键变量。其定义如下:
// 本地主机名,用于选择本地本机worker的关键变量
private String mLocalHostName = null;
而在LocalFirstPolicy的唯一无参构造函数内,它所做的唯一一件事就是初始化这个本地主机名mLocalHostName,如下:
/**
* 构造函数
* Constructs a {@link LocalFirstPolicy}.
*/
public LocalFirstPolicy() {
// 通过NetworkAddressUtils的getLocalHostName()方法,从客户端上下文的配置信息中获取本地主机名mLocalHostName
mLocalHostName = NetworkAddressUtils.getLocalHostName(ClientContext.getConf());
}
既然是一个定位策略,那么它是如何对外提供选择服务的呢?答案就在核心方法getWorkerForNextBlock()中,它为下一个数据块选择一个Worker,返回Worker的网络地址WorkerNetAddress。代码如下;
// 核心方法,为下一个数据块选择一个Worker,返回Worker的网络地址WorkerNetAddress
@Override
public WorkerNetAddress getWorkerForNextBlock(List<BlockWorkerInfo> workerInfoList,
long blockSizeBytes) {
// first try the local host
// 首先尝试从本地主机中选择
// 遍历BlockWorkerInfo列表workerInfoList,获取每个BlockWorkerInfo,即workerInfo
for (BlockWorkerInfo workerInfo : workerInfoList) {
// 判断workerInfo所在主机名是否与mLocalHostName,且workerInfo的总字节数是否满足块需要的大小blockSizeBytes
if (workerInfo.getNetAddress().getHost().equals(mLocalHostName)
&& workerInfo.getCapacityBytes() >= blockSizeBytes) {
// 满足条件则返回
return workerInfo.getNetAddress();
}
}
// otherwise randomly pick a worker that has enough availability
// 否则随机挑选一个容量足够满足要求的worker
// 先对workerInfoList进行shuffle,避免热点问题
Collections.shuffle(workerInfoList);
// 遍历BlockWorkerInfo列表workerInfoList,获取每个BlockWorkerInfo,即workerInfo
for (BlockWorkerInfo workerInfo : workerInfoList) {
// 只要workerInfo的总字节数是否满足块需要的大小blockSizeBytes,就是我们需要的worker啦
if (workerInfo.getCapacityBytes() >= blockSizeBytes) {
return workerInfo.getNetAddress();
}
}
return null;
}
它的逻辑很简单,总共分为两大步骤,如下:
1、首先尝试从本地主机中选择:
1.1、遍历BlockWorkerInfo列表workerInfoList,获取每个BlockWorkerInfo,即workerInfo:
1.1.1、判断workerInfo所在主机名是否与mLocalHostName,且workerInfo的总字节数是否满足块需要的大小blockSizeBytes,满足条件则返回,否则继续遍历;
2、如果1未选择到满足条件的worker,则随机挑选一个容量足够满足要求的worker:
2.1、先对workerInfoList进行shuffle,避免热点问题;
2.2、遍历BlockWorkerInfo列表workerInfoList,获取每个BlockWorkerInfo,即workerInfo:
2.2.1、只要workerInfo的总字节数是否满足块需要的大小blockSizeBytes,就是我们需要的worker啦,否则继续遍历吧;
3、再选不到就直接返回null喽!