先说调测程序中遇到的问题:
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文件的问题,希望对大家有帮助。
与君共勉