Hadoop 服务安全授权说明

曾经我在Hadoop的历史版本上对UGI进行过代码更改,按照UGI,IP映射来确定哪些用户可以访问Hadoop的服务。最近在给一个客户看需求的时候,看到了Hadoop本身是提供这一个服务的,并且做得很细,不得不说Hadoop做得真是包罗万象,事无巨细。
这个需求是用户需要对自己的集群进行把控,防止一些无关的请求拉取数据,防止恶意攻击。
在Hadoop common模块是有专门模块https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/ServiceLevelAuth.html 来做这个事情。
首先需要设置 $HADOOP_CONF_DIR/core-site.xml设置hadoop.security.authorization 为true,打开hadoop 安全认证。随后配置$HADOOP_CONF_DIR/hadoop-policy.xml

这里面可以配置非常多的服务,对应了Hadoop的各种接口(protocol),加入我要设置Client访问HDFS的限制,只要设置

 <property>
    <name>security.client.protocol.acl</name>
    <value>test_user hadoop</value>
    <description>ACL for ClientProtocol, which is used by user code
    via the DistributedFileSystem.
    The ACL is a comma-separated list of user and group names. The user and
    group list is separated by a blank. For e.g. "alice,bob users,wheel".
    A special value of "*" means all users are allowed.</description>
  </property>

  <property>
    <name>security.client.protocol.hosts</name>
    <value>192.168.0.0/24</value>
  </property>

    <property>
    <name>security.client.protocol.hosts.blocked</name>
    <value>192.168.0.10</value>
  </property>

这里面我设置了允许user为test_user, group是hadoop的用户通过DFSClient访问HDFS。并且限定了IP范围是192.168.0网段,但是限制192.168.0.10不能访问。
其他的服务接口也是这么配置,只要设置好name,最后加入hosts和hosts.blocked就可以限制ip访问。

Capacity Scheduler Node Label在queue mapping情况下引起的提交stuck

为一个大客户启用Node Label功能,发现启用后,使用用户提交任务后,appmaster无法启动,导致了整个任务无法启动,集群无法提交任务。
集群的版本是Hadoop 2.7.2,Node Label 把整个集群分为两部分,一部分label为core,一部分label为vvp。在客户端提交任务的时候可以指定队列,这种情况下队列信息是在提交的context里面设置,而对于不显示的指定队列的应用,设置的是默认队列,即default,这段代码可以参考YARN Runner的实现。

appContext.setApplicationId(applicationId);                // ApplicationId
appContext.setQueue(                                       // Queue name
    jobConf.get(JobContext.QUEUE_NAME,
    YarnConfiguration.DEFAULT_QUEUE_NAME));

ResourceManager通过RMClientService接收到提交的请求后,会放置的状态机中,通过多次的异步处理,会生成RMAppAttempt对象,并生成AppMaster的request,相关代码在RMAppManager类中。
方法是validateAndCreateResourceRequest,在这里面提交的appmaster依然使用的是default队列,并没有通过queue mapping获取到他的实际映射队列,导致了无法获取label信息,从而无法调度。

    SchedulerUtils.normalizeAndValidateRequest(amReq,
        scheduler.getMaximumResourceCapability(),
        submissionContext.getQueue(), scheduler, isRecovery, rmContext);

在这段代码中,submissionContext的Queue依然是default,获取的是default对应的label,通常是默认的partition,而如果用户和组映射到了其他的Queue,而这个Queue需要到特定的Label运行,就会导致错误。
解决方法:

    String queueName = submissionContext.getQueue();
    if(scheduler instanceof CapacityScheduler) {
      queueName = ((CapacityScheduler)scheduler).getQueueMappings(queueName, user);
    }
    SchedulerUtils.normalizeAndValidateRequest(amReq,
        scheduler.getMaximumResourceCapability(),
        queueName, scheduler, isRecovery, rmContext);

在Capacity Scheduler中暴露出queue mapping的方法去获取mapping的queue,从而获取到实际的Label。

在Hadoop 2.8.5中这个问题已经被fix了,fix的方法如下:

  if (rmContext.getQueuePlacementManager() != null) {
    // We only do queue mapping when it's a new application
    rmContext.getQueuePlacementManager().placeApplication(
        submissionContext, user);
  }

在生成amReq之前,先根据QueueMapping重新设置queue的Name,从而获取到映射后的Queue,拿到最后的Label。
由于2.8.5这个改动远远大于2.7.3的改动,所以这次采用自己的fix方案解决这一问题。

一次扩容引发的ARP Cache问题

当某个EMR客户进行扩容时,机器接近上千台时,造成了网络通信问题,甚至有机器ping自己都平不通的情况。根据提示,原因是对于大集群来说,默认的centos arp cache配置不适合,需要调整相关参数。
现象是在给一个大客户进行扩容的时候,当机器接近千台的时候,NameNode主节点突然间通信变慢,请求堆积,最后zkfc直接将NameNode进行了failover了,另一台NameNode也是不定期的failover。
查看dmesg,发现了大量的异常日志:

[76391312.109413] net_ratelimit: 97 callbacks suppressed
[76391319.885189] net_ratelimit: 37 callbacks suppressed
[76391325.104167] net_ratelimit: 62 callbacks suppressed
[76391330.508496] net_ratelimit: 60 callbacks suppressed
[76391335.694525] net_ratelimit: 50 callbacks suppressed
[76391343.815606] net_ratelimit: 108 callbacks suppressed

dmesg报错

 

另外,NameNode的gmond metrics 收集也一直报错,无法发送metrics。对于gmond的metrics发送,其实对网络压力很小,如果依然无法发送,说明网络出现了较严重问题。
经过跟其他部门、兄弟团队合作,发现了是由于ARP Cache overflow造成的问题,从而严重的影响了网络性能。
ARP Cache的作用为,ARP表存储了IP地址和MAC地址的映射关系,ARP Cache有以下几个参数:
net.ipv4.neigh.default.gc_thresh1 ARP表小于该数值的时候不做垃圾回收
net.ipv4.neigh.default.gc_thresh2 ARP表大于该数值时,5s内进行垃圾回收
net.ipv4.neigh.default.gc_thresh3 ARP表的最大限额

再从我们系统中取得默认值发现:
net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh3 = 1024

默认配置偏小,导致了集群机器超过1000台后,网络丢包,不稳定现象,修改相关配置。

追加 /etc/sysctl.conf
net.ipv4.neigh.default.gc_thresh1 = 512
net.ipv4.neigh.default.gc_thresh2 = 2048
net.ipv4.neigh.default.gc_thresh3 = 10240
net.nf_conntrack_max = 524288

sysctl -p 更新配置