springboo连接redis哨兵集群原理

springboo连接redis哨兵集群原理,第1张

Spring Boot连接Redis哨兵集群的原理如下:

1 Spring Boot使用Jedis客户端连接Redis哨兵集群。Jedis是一个Java Redis客户端,它支持连接Redis哨兵集群。

2 Jedis客户端会向Redis哨兵集群发送SENTINEL get-master-addr-by-name命令,获取当前Redis主节点的IP地址和端口号。

3 Jedis客户端会使用获取到的IP地址和端口号连接Redis主节点,并发送PING命令测试连接是否正常。

4 如果连接正常,Jedis客户端会将连接信息保存在连接池中,以便后续使用。

5 如果连接失败,Jedis客户端会向Redis哨兵集群发送SENTINEL get-master-addr-by-name命令,获取新的Redis主节点的IP地址和端口号,然后重复步骤2-4。

6 如果Redis主节点发生故障,Redis哨兵会自动将从节点升级为主节点,并通知Jedis客户端更新连接信息。

总之,Spring Boot连接Redis哨兵集群的原理是通过Jedis客户端向Redis哨兵集群发送命令获取当前Redis主节点的IP地址和端口号,然后使用获取到的信息连接Redis主节点。如果连接失败,Jedis客户端会重新获取新的Redis主节点的IP地址和端口号,直到连接成功为止。如果Redis主节点发生故障,Redis哨兵会自动将从节点升级为主节点,并通知Jedis客户端更新连接信息。

此外,我还讨论过较为常见的基于服务器的数据存储,比如MongoDB和CouchDB。每个数据存储都有其优势和劣势,特别是当应用于特定领域时。本期的Java开发20关注的是Redis,一种轻量级键值对数据存储。多数NoSQL实现本质上都是键值对,但是Redis支持非常丰富的值集,其中包括字符串、列表、集以及散列。因此,Redis通常被称为数据结构服务器。Redis也以异常快速而闻名,这使得它成为某一特定类型使用案例的最优选择。当我们想要了解一种新事物时,将其同熟知的事物进行比较可能会有所帮助,因此,我们将通过对比其与memcached的相似性以开启Redis探索之旅。接着我们将介绍Redis的主要功能,这些功能可以使其在某些应用场景可以胜过memcached。最后我将向您展示如何将Redis作为一个传统数据存储用于模型对象。Redis和memcachedMemcached是一个众所周知的内存对象缓存系统,通过将目标键和值导入内存缓存运行。因此,Memcached能回避读取磁盘时发生的I/O成本问题。在Web应用程序和数据库之间粘贴memcached时会产生更好的读取性能。因此,对于那些需要快速数据查询的应用程序,Memcached是一个不错的选择。其中的一个例子为股票查询服务,需要另外访问数据库获取相对静态数据,如股票名称或价格信息。MemcacheDB将Redis与memcached相比较并不公平,它与MemcacheDB相比要好的多,MemcacheDB是一个分布式键值对存储系统,专为数据持久化而设计。MemcacheDB与Redis较为相似,其新增优势可以使其轻松地与memcached实现的客户端进行通信。但是memcached也有其局限性,其中一个事实就是它所有的值均是简单的字符串。Redis作为memcached的替代者,支持更加丰富的功能集。一些基准(benchmarks)也表明Redis的速度要比memcached快很多。Redis提供的丰富数据类型使其可以在内存中存储更为复杂的数据,这是使用memcached无法实现的。同memcached不一样,Redis可以持久化其数据。Redis解决了一个重大的缓存问题,而其丰富的功能集又为其找到了其他用途。由于Redis能够在磁盘上存储数据以及跨节点复制数据,因而可以作为数据仓库用于传统数据模式(也就是说,您可以使用Redis,就像使用RDBMS一样)。Redis还经常被用作队列系统。在本用例中,Redis是备份和工作队列持久化存储(利用Redis的列表类型)的基础。GitHub是以此种方法使用Redis的大规模基础架构示例准备好Redis,立即开始!要开始使用Redis,您需要访问它,可以通过本地安装或者托管供应商来实现访问。如果您使用的MAC,安装过程可能就不那么简单。如果您使用的是Windows,您需要先安装Cygwin。如果您正在寻找一个托管供应商,Redis4You拥有一个免费计划。不管您以何种方式访问,您都能够根据本文下列示例进行 *** 作,但是我需要指出的是,使用一个托管供应商进行缓存可能并不是很好的缓存解决方案,因为网络延迟可能会抵消任何性能优势。您需要通过命令与Redis进行交互,这就是说,这里没有SQL类查询语言。使用Redis工作非常类似于使用传统map数据结构,即所有的一切都拥有一个键和一个值,每个值都有多种与之关联的数据类型。每个数据类型都有其自己的命令集。例如,如果您计划使用简单数据类型,比如某种缓存模式,您可以使用命令set和get。您可以通过命令行shell与一个Reids实例进行交互。还有多个客户端实现,可以以编程方式与Redis进行交互。清单1展示了一个使用基础命令的简单命令行shell交互:清单1使用基础的Redis命令redis127001:6379>setpageregistrationOKredis127001:6379>keys1)"foo"2)"page"redis127001:6379>getpage"registration"在这里,我通过set命令将键"page"与值"registration"相关联。接着,我发出keys命令(后缀表示我想看到所有可用的实例键。keys命令显示有一个page值和一个foo,我可以通过get命令检索到与一个键关联的值。请记住,使用get检索到的值只能是一个字符串。如果一个键的值是一个列表,那么您必须使用一个特定列表的命令来检索列表元素。(注意,有可以查询值类型的命令)。Java与Jedis集成对于那些想要将Redis集成到Java应用程序的编程人员,Redis团队建议使用一个名为Jedis的项目,Jedis是一个轻量级库,可以将本地Redis命令映射到Java方法。例如Jedis可以获取并设置简单值,如清单2所示:清单2Java代码中的基础Redis命令JedisPoolpool=newJedisPool(newJedisPoolConfig(),"localhost");Jedisjedis=poolgetResource();jedisset("foo","bar");Stringfoobar=jedisget("foo");assertfoobarequals("bar");poolreturnResource(jedis);pooldestroy();在清单2中,我配置了一个连接池并捕获连接,(与您在典型JDBC场景中的 *** 作非常相似)然后我在清单的底部设置了返回 *** 作。在连接池逻辑之间,我设置了值"bar"和键"foo",这是我通过get命令检索到的。与memcached类似,Redis允许您将过期(expiration)时间关联到一个值。因此我设置了这样一个值(比如,股票临时交易价格),最终将从Redis缓存中清除掉。如果我想在Jedis中设置一个过期时间,需要在发出set调用之后将其和一个过期时间关联。如清单3所示:清单3Redis值可以设置为终止jedisset("gone","daddy,gone");jedisexpire("gone",10);Stringthere=jedisget("gone");assertthereequals("daddy,gone");Threadsleep(4500);StringnotThere=jedisget("gone");assertnotThere==null;在清单3中,我使用了一个expire调用将"gone"的值设置为在10秒钟内终止。调用Threadsleep之后,"gone"的get调用会返回null。Redis中的数据类型使用Redis数据类型,比如列表和散列需要专用命令用法。例如,我可以通过为键附加值来创建列表。

Spring Boot是目前非常流行的Java Web开发框架,Redis是非关系型数据库的一种,以键值对的形式存储。Spring对Redis的支持是通过Spring Data Redis来实现的,给我们提供了RedisTemplate和StringRedisTemplate两种模板来 *** 作数据。Spring Boot框架也提供了对Redis的支持,下面我们来讲一下Spring Boot框架整合Redis的步骤。

工具/材料

IntelliJ IDEA

01

Spring Boot整合Redis我们需要添加依赖的jar包,spring-boot-starter-data-redis中包含spring和redis相关的jar包,jedis作为redis的客户端也需要添加到工程中,Spring Boot的版本信息在父pom中已指定,子模块中的spring相关的jar包无需另外指定。

<dependency>

<groupId>orgspringframeworkboot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

<dependency>

<groupId>redisclients</groupId>

<artifactId>jedis</artifactId>

<version>300-m1</version>

</dependency>

02

Spring Boot会根据applicationproperties中的配置对Redis的属性进行自动配置,并注入到RedisProperties类中。在applicationproperties配置文件中这些属性都是以springredis为前缀的,值得注意的是在Spring Boot 15x版本中默认的Redis客户端是jedis,因此在配置文件中无需指定,如下图所示。

03

Spring Boot 15x版本的整合配置网上可以搜索大量的文章,然而Spring Boot 2x版本的整合资料却非常少,甚至提供的配置不能正常使用,因此本文主要讲解Spring Boot 2x整合Redis以及Redis的使用情况。spring-boot 2x版本有jedis和lettuce两种客户端,因此我们必须要去指定使用哪一种客户端,两个客户端的配置如下图所示,本文使用的是Jedis客户端连接池,具体的配置如下。

# Redis数据库索引(默认为0)

springredisdatabase=0

# Redis服务器地址

springredishost=127001

# Redis服务器连接端口

springredisport=6379

# Redis服务器连接密码(默认为空)

springredispassword=xylx1t!@#

# 配置jedis连接池

# 连接池最大连接数(使用负值表示没有限制)

springredisjedispoolmax-active=8

# 连接池最大阻塞等待时间(使用负值表示没有限制)

springredisjedispoolmax-wait=-1ms

# 连接池中的最大空闲连接

springredisjedispoolmax-idle=8

# 连接池中的最小空闲连接

springredisjedispoolmin-idle=0

# 连接超时时间(毫秒)

springredistimeout=5000ms

由配置我们可以看到spring-boot 2x版本时间设置需要加单位ms,因为参数的类型为Duration。另外springredistimeout尽量不要配置0,否则可能会出现iolettucecoreRedisCommandTimeoutException: Command timed out超时错误。

04

配置文件编辑完成后,我们开始编写代码实现Redis数据的存储和读取。我们创建一个RedisUtil工具类,该类使用@Component注解表示交由Spring管理,StringRedisTemplate是Spring提供的,可以使用@Autowired注解直接注入,接下来便可以书写存和取的代码了。

@Component

public class RedisUtil {

@Autowired

private StringRedisTemplate redisTemplate;

/

存字符串

@param key 缓存键

@param value 缓存值

@param expireTime 过期时间(s)

/

public void setString(String key, String value, int expireTime){

ValueOperations<String, String> ops = redisTemplateopsForValue();

if (expireTime != 0) {

opsset(key, value, expireTime, TimeUnitSECONDS);

} else {

opsset(key,value);

}

}

/

取字符串

@param key 缓存键

@return 缓存值

/

public String getString(String key){

ValueOperations<String, String> ops = thisredisTemplateopsForValue();

return opsget(key);

}

05

接下来我们编写Controller层代码去调用RedisUtil工具类,实现数据的存储和读取,代码比较简单可以参考下图。若想验证Redis是否可用,还需要编写启动类,如下图所示。

06

由上图可看到我们编写了一个post请求用于存储字符串,get请求用于取出字符串。启动类通过main方法启动应用,接下来我们使用postman去模拟浏览器调用post和get请求,由下图可以看到Redis存储的数据成功被取出。

07

接下来我们介绍Jedis,这是一个封装了Redis的客户端,在Spring Boot整合Redis的基础上,可以提供更简单的API *** 作。因此我们需要配置JedisPool的Bean,代码如下,其中@Configuration注解表明这是一个配置类,我们在该类中注入RedisProperties,并且使用@Bean注解指定JedisPool。

@Configuration

public class RedisConfiguration {

@Autowired

private RedisProperties properties;

@Bean

public JedisPool getJedisPool(){

JedisPoolConfig config = new JedisPoolConfig();

configsetMaxIdle(propertiesgetJedis()getPool()getMaxIdle());

configsetMaxTotal(propertiesgetJedis()getPool()getMaxActive());

configsetMaxWaitMillis(propertiesgetJedis()getPool()getMaxWait()toMillis());

JedisPool pool = new JedisPool(config,propertiesgetHost(),

propertiesgetPort(),100,

propertiesgetPassword(), propertiesgetDatabase());

return pool;

}

}

08

接下来我们编辑JedisUtil工具类,通过SpringBoot容器的@Component注解来自动创建,并且注入JedisPool,使用jedisPoolgetResource()方法来获取Jedis,并最终实现 *** 作redis数据库,其代码如下。

@Component

public class JedisUtil {

@Autowired

JedisPool jedisPool;

//获取key的value值

public String get(String key) {

Jedis jedis = jedisPoolgetResource();

String str = "";

try {

str = jedisget(key);

} finally {

try {

jedisclose();

} catch (Exception e) {

eprintStackTrace();

}

}

return str;

}

public String set(String key, String value) {

Jedis jedis = jedisPoolgetResource();

String str = "";

try {

str = jedisset(key, value);

} finally {

try {

jedisclose();

} catch (Exception e) {

eprintStackTrace();

}

}

return str;

}

}

09

JedisUtil工具类编写完成后,我们修改之前的RedisController,并注入JedisUtil,代码如下图所示。然后再用postman分别调用post和get接口,我们可以看到成功取到了新的key的value值。

特别提示

在Spring Boot整合Redis前本机需安装Redis,另外可以使用RedisDesktopManager这个Redis这个桌面管理工具查看Redis中的数据。

item表示迭代的参数 比如你的这个数组通过requestsetAttribute("array",xxx)放入了这个里,迭代的内容就是${requestScopearray}

var 相当于一个引用

下面你就可以用

${arrayxxx1}

${arrayxxx2}

将数组里的值输出出来了

Caused by: orgspringframeworkdataredisRedisConnectionFailureException: Could not get a resource from the pool; nested exception is redisclientsjedisexceptionsJedisConnectionException: Could not get a resource from the pool

at orgspringframeworkdataredisconnectionjedisJedisExceptionConverterconvert(JedisExceptionConverterjava:67)

at orgspringframeworkdataredisconnectionjedisJedisExceptionConverterconvert(JedisExceptionConverterjava:41)

at orgspringframeworkdataredisPassThroughExceptionTranslationStrategytranslate(PassThroughExceptionTranslationStrategyjava:37)

at orgspringframeworkdataredisconnectionjedisJedisClusterConnectionconvertJedisAccessException(JedisClusterConnectionjava:3999)

at orgspringframeworkdataredisconnectionjedisJedisClusterConnectionsetEx(JedisClusterConnectionjava:717)

at orgspringframeworkdatarediscoreDefaultValueOperations 11doInRedis(DefaultValueOperationsjava:186)

at orgspringframeworkdatarediscoreRedisTemplateexecute(RedisTemplatejava:207)

at orgspringframeworkdatarediscoreRedisTemplateexecute(RedisTemplatejava:169)

at orgspringframeworkdatarediscoreAbstractOperationsexecute(AbstractOperationsjava:91)

at orgspringframeworkdatarediscoreDefaultValueOperationsset(DefaultValueOperationsjava:182)

at iorenrencommonutilsSuppleDataUtilsprovideIcc(SuppleDataUtilsjava:107)

at iorenrenmodulesjobtaskTaskIcctaskFour(TaskIccjava:242)

10 common frames omitted

Caused by: redisclientsjedisexceptionsJedisConnectionException: Could not get a resource from the pool

at redisclientsutilPoolgetResource(Pooljava:53)

at redisclientsjedisJedisPoolgetResource(JedisPooljava:226)

at redisclientsjedisJedisSlotBasedConnectionHandlergetConnectionFromSlot(JedisSlotBasedConnectionHandlerjava:66)

at redisclientsjedisJedisClusterCommandrunWithRetries(JedisClusterCommandjava:116)

at redisclientsjedisJedisClusterCommandrunWithRetries(JedisClusterCommandjava:141)

at redisclientsjedisJedisClusterCommandrunWithRetries(JedisClusterCommandjava:141)

at redisclientsjedisJedisClusterCommandrunWithRetries(JedisClusterCommandjava:141)

at redisclientsjedisJedisClusterCommandrunWithRetries(JedisClusterCommandjava:141)

at redisclientsjedisJedisClusterCommandrunBinary(JedisClusterCommandjava:60)

at redisclientsjedisBinaryJedisClustersetex(BinaryJedisClusterjava:268)

at orgspringframeworkdataredisconnectionjedisJedisClusterConnectionsetEx(JedisClusterConnectionjava:715)

18 common frames omitted

Caused by: redisclientsjedisexceptionsJedisConnectionException: javanetSocketTimeoutException: connect timed out

at redisclientsjedisConnectionconnect(Connectionjava:207)

at redisclientsjedisBinaryClientconnect(BinaryClientjava:93)

at redisclientsjedisBinaryJedisconnect(BinaryJedisjava:1767)

at redisclientsjedisJedisFactorymakeObject(JedisFactoryjava:106)

at orgapachecommonspool2implGenericObjectPoolcreate(GenericObjectPooljava:868)

at orgapachecommonspool2implGenericObjectPoolborrowObject(GenericObjectPooljava:435)

at orgapachecommonspool2implGenericObjectPoolborrowObject(GenericObjectPooljava:363)

at redisclientsutilPoolgetResource(Pooljava:49)

28 common frames omitted

Caused by: javanetSocketTimeoutException: connect timed out

at javanetDualStackPlainSocketImplwaitForConnect(Native Method)

at javanetDualStackPlainSocketImplsocketConnect(DualStackPlainSocketImpljava:85)

at javanetAbstractPlainSocketImpldoConnect(AbstractPlainSocketImpljava:350)

at javanetAbstractPlainSocketImplconnectToAddress(AbstractPlainSocketImpljava:206)

at javanetAbstractPlainSocketImplconnect(AbstractPlainSocketImpljava:188)

at javanetPlainSocketImplconnect(PlainSocketImpljava:172)

at javanetSocksSocketImplconnect(SocksSocketImpljava:392)

at javanetSocketconnect(Socketjava:589)

at redisclientsjedisConnectionconnect(Connectionjava:184)

35 common frames omitted

最近在本地测试通过springboot基础redis的方式连接redis集群,启动的时候没有报错。

到时当执行保存,查询到redis的 *** 作的时候,报上面的错误。

首先看到错误信息,先是connect timed out后,再出现的Could not get a resource from the pool错误。一开始排查这个错误,由于使用的是默认连接池,debug的时候,也看到有装载连接池,为啥报错呢。本地通过redis-manger工具,连接集群地址也可以连接访问。从日志也看不出还有其他的错误信息。

于是自己写了main方法直接 *** 作JedisCluster的方式来测试,出现的错误跟上面全文一样。用抓包工具wireshark过滤集群的地址,查看连接的消息也是正常的。

另外一个项目使用的reddison客户端,于是测试了deamo用reddison来连接集群地址,启动的时候,发现报如下错误

乖乖,恍然大悟;102871731地址是服务器的内网地址,本机是连不上内网地址的,只有通过外网地址连接。而我配置的是外网地址。然而,客户端在集群同步和心跳检查的时候,是拉取的集群信息,redis集群信息里面的节点的信息

配置的是内网地址。客户端就通过这个内网地址来同步信息了。

再次同wireshark过滤集群102871731,发现有大量的超时重传的包,也没有响应。

以上就是关于springboo连接redis哨兵集群原理全部的内容,包括:springboo连接redis哨兵集群原理、scala怎样创建redis集群连接池、Spring Boot如何整合Redis等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9712319.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存