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

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文件的问题,希望对大家有帮助。

与君共勉

参考链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: