先说调测程序中遇到的问题:

1、以纯java脚本连接Redis,可以实现增删查等操作,程序如下:

import com.huawei.jredis.client.KerberosUtil;
import redis.clients.jedis.*;
import www.hebei.huawei.utils.JedisClusterPool;

/**
 * Step1:对Redis进行安全认证,keytab文件和krb5文件均在BDI主机,Redis集群认证过程在BDI主机完成,与Hadoop集群结点没有关系
 * Step2:设置Redis连接参数,修改Jedis连接池最大空闲连接数、最大连接数和最小空闲连接数
 * Step3:通过JedisCluster连接Redis,获得连接对象
 * Step4:对Redis进行增、查、删操作。
 * step5:关闭Redis连接
 */

public class SecureJedisClusterDemo {

    public static void main(String[] args) {

        System.out.println("正在获取redis客户端....");
        String redisuser_keytab= "/tmp/redis/redisuser.keytab";
        String krb5 = "/tmp/redis/krb5.conf";
        JedisClusterPool jedisClusterPool = new JedisClusterPool();
        JedisCluster client = jedisClusterPool.getJedisCluster(redisuser_keytab,krb5);
        System.out.println("redis客户端连接成功!");
        System.out.println(client.getClusterNodes());

        client.set("test","我是测试数据1,看到我你就成功了!");
        System.out.println("获取test值:" + client.get("test"));
        client.del("test");
        System.out.println("test键值对应的数据已删除!");

        try {
            System.out.println("正在关闭redis客户端...");
            client.close();
            System.out.println("redis客户端关闭成功!");
        }catch(Exception e){
            e.printStackTrace();
        }
    }

}
import com.huawei.jredis.client.GlobalConfig
import com.huawei.jredis.client.auth.AuthConfiguration
import org.apache.commons.pool2.impl.GenericObjectPoolConfig
import redis.clients.jedis.{HostAndPort, JedisCluster}

import java.io.File
import java.util

/**
 * @Author: 
 * @Email: 
 * @Version: 2022/6/14 15:22
 * @Describe: 连接Redis
 * */
class JedisClusterPool{

  def getJedisCluster(keytab:String,krb5:String): JedisCluster = {

    System.setProperty("java.security.krb5.conf", krb5)
    System.setProperty("sun.security.krb5.debug", "true")
    System.setProperty("java.security.krb5.realm", "HADOOP.COM")
    val authConfiguration = new AuthConfiguration(keytab, "xxxxxxx")
    GlobalConfig.setAuthConfiguration(authConfiguration)
    val hosts = new util.HashSet[HostAndPort]
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    hosts.add(new HostAndPort("10.xxx.xxx.xxx", xxxxx))
    // Jedis连接池配置
    val jedisPoolConfig = new GenericObjectPoolConfig()
    // 最大空闲连接数, 默认8个
    jedisPoolConfig.setMaxIdle(8)
    // 最大连接数, 默认8个
    jedisPoolConfig.setMaxTotal(8)
    //最小空闲连接数, 默认0
    jedisPoolConfig.setMinIdle(0)
    // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
    jedisPoolConfig.setMaxWaitMillis(2000); // 设置2秒
    //对拿到的connection进行validateObject校验
    jedisPoolConfig.setTestOnBorrow(true)
    // 连接
    val client: JedisCluster = new JedisCluster(hosts,2000,100,100, jedisPoolConfig)
    client
  }
}

2、使用生产环境Spark通过local模式连接Redis,通过以下命令进行鉴权,鉴权过程不报错,但是通过JedisCluster类去连接Redis时报错No Reachable node in cluster

System.setProperty("java.security.krb5.conf", krb5)
System.setProperty("sun.security.krb5.debug", "true")
System.setProperty("java.security.krb5.realm", "HADOOP.COM")
val authConfiguration = new AuthConfiguration(keytab, "XXXXXXX")
GlobalConfig.setAuthConfiguration(authConfiguration)

3、以Client模式运行Spark程序连接Redis,此时Driver端为运行程序的主机Executor为集群中的节点,使用和local模式同样的鉴权命令和鉴权文件,可以在客户端连接Redis实现增、删、查等操作,但是在集群节点中运行的程序无法连接Redis,报错类型为No Reachable node in cluster

4、以cluster模式运行Spark程序连接Redis,此时NameNode和DataNode均为集群中的虚机,使用同样的鉴权程序和鉴权文件,无法连接Redis,报错类型为No Reachable node in cluster

可以发现只能在本地主机完成Redis集群的Kerberos鉴权和连接,无法在集群中连接Redis!

再说一下我是怎么解决的:

主要原因出在鉴权文件上,krb5文件中必须添加Redis集群的节点信息,才能通过Kerberos鉴权,由于Executor与Redis创建连接需要使用鉴权文件,所以将keytab文件和krb5文件均需要添加到容器中,添加到容器的方法可以是sc.addfile("文件绝对路径")也可以在submit命令中通过--files添加,然后利用SparkFile.get("xxxx.conf")获取鉴权文件,最终可以连接Redis解决No Reachable node in cluster问题。

最后,同样的报错可能会由很多不同的情况导致,其他的解决问题的方法请自行百度吧,我这里就不进行总结了。我当初为了解决该问题也走了很多弯路,比如去研究Kerberos鉴权的过程,通过hadoop的kerberos鉴权进行对比,但就是没有怀疑过krb5.conf文件的问题,希望对大家有帮助。

与君共勉