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喽!