草庐IT

Redis高可用知多少之DNS篇

数据库干货铺 2023-03-28 原文

1、背景

例如,存在一套redis主从(主从节点在不同的主机上),应用程序通过主库的ip进行读写操作。但是,主库一旦出现故障,虽然有从库,且从库提升为主库,但是应用程序如果想使用从库则必须修改配置,重启应用方可生效。如用此情况,则涉及的人员比较多,且应用程序恢复使用的时间比较长。对于此情况,可以采取以下2种解决方式解决:

配置VIP

在Redis主库服务器上配置vip,当主库出现问题时,配置脚本将vip自动切换至从节点,并将从节点提升为读写状态。应用程序中配置的是vip,主库异常时,从库自动提升为主库对外提供服务,应用程序无需做任何操作。

使用DNS

应用程序通过配置内网域名连接redis,DNS服务器对应域名映射到redis主库服务器IP。当redis主库异常时,将redis从节点提升为读写主库,修改DNS域名映射关系至redis从节点ip,此时应用程序也无需进行操作。

注:

以上2种方式均存在缺陷,例如:

  • vip方式存在问题: 当主从节点不在同一个机房或同一网段时,将无法使用相同的vip。
  • DNS方式:使用DNS方式将有DNS缓存问题,即修改域名映射后域名仍可能解析到原主库机器的ip。
vip配合哨兵的高可用方式将在后续介绍,本次先介绍DNS服务器配置及dns方式解决方案。

2、DNS服务配置

(1)安装DNS服务

# 安装bind相关工具
yum install bind bind-utils bind-devel bind-libs bind-chroot -y
2.2 修改配置文件
vim /etc/named.conf

## 编译对应内容
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS

// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.

//
options {

// listen-on port 53 { 127.0.0.1; }; // 此行注释

listen-on port 53 { any; }; // 添加此行

listen-on-v6 port 53 { ::1; };

directory "/var/named";

dump-file "/var/named/data/cache_dump.db";

statistics-file "/var/named/data/named_stats.txt";

memstatistics-file "/var/named/data/named_mem_stats.txt";

// allow-query { localhost; }; // 注释此行

allow-query { any; }; // 添加此行

forwarders {114.114.114.114; }; // 添加此行,这是在DNS服务器不知道域名解析的时候询问这个IP的主机,这个IP的主机必须联网
recursion yes;
dnssec-enable yes;
dnssec-validation yes;
/* Path to ISC DLV key */

bindkeys-file "/etc/named.iscdlv.key";
managed-keys-directory "/var/named/dynamic";

};
logging {

channel default_debug {

file "data/named.run";

severity dynamic;

};

};
zone "." IN {

type hint;

file "named.ca";
};
include "/etc/named.rfc1912.zones";

include "/etc/named.root.key";

(2)检查语法

named-checkconf

(3)启动DNS服务

/etc/init.d/named start

(4)配置DNS正向解析文件

在/etc/named.rfc1912.zones添加正向解析配置。

vim /etc/named.rfc1912.zones # 此文件名在上面步骤的/etc/named.conf文件末尾有指定
## 此文件末尾追加如下内容
zone "redis.com" IN { // redis.com 名自定义,即需要解析的域名
type master; // dns域类型为master
file "redis.com.zone"; // redis.com.zone 文件名自定义,后续文件名需与此一致
allow-update { none; };
};

根据上一步的情况,配置解析文件。

# 拷贝文件
cp -p named.localhost redis.com.zone # 拷贝文件,注意要连同权限一起拷贝,因权限不一致,启动会报错
vim redis.com.zone
$TTL 1D
@ IN SOA www.redis.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS www.redis.com.
dns IN A 192.168.56.208
www IN A 192.168.56.208

(5)配置DNS反向解析文件

在/etc/named.rfc1912.zones添加反向解析配置。

可以将正向解析与反向解析配置在一个文件里,即file配置为相同的文件名。本次分开配置来演示。

vim /etc/named.rfc1912.zones # 此文件名在上面步骤的/etc/named.conf文件末尾有指定
## 此文件末尾追加如下内容
zone "56.168.192.in-addr.arpa" IN {
type master;
file "redis.com.local";
allow-update { none; };
};

根据上一步的情况,配置解析文件。

# 拷贝文件
cp -p named.localhost redis.com.local # 拷贝文件,注意要连同权限一起拷贝,因权限不一致,启动会报错
vim redis.com.local
$TTL 1D
@ IN SOA www.redis.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 192.168.56.208
AAAA ::1
208 IN PTR www.redis.com.

(6)重启DNS服务

/etc/init.d/named restart

(7)测试DNS服务器

在另一台主机上测试DNS是否可用,操作步骤如下。

# 修改域名解析文件
vim /etc/resolv.conf
# 将创建的DNS服务器地址添加至此文件

nameserver 192.168.56.209

正向解析测试。

nslookup www.redis.com
# 结果如下
Server: 192.168.56.209
Address: 192.168.56.209#53
Name: www.redis.com
Address: 192.168.56.208

反向解析测试。

nslookup 192.168.56.208
# 结果如下:
Server: 192.168.56.209
Address: 192.168.56.209#53
208.56.168.192.in-addr.arpa name = www.redis.com.

ping 域名测试。

ping www.redis.com
# 结果如下
PING www.redis.com (192.168.56.208) 56(84) bytes of data.
64 bytes from www.redis.com (192.168.56.208): icmp_seq=1 ttl=64 time=0.229 ms
64 bytes from www.redis.com (192.168.56.208): icmp_seq=2 ttl=64 time=0.287 ms
64 bytes from www.redis.com (192.168.56.208): icmp_seq=3 ttl=64 time=0.276 ms
64 bytes from www.redis.com (192.168.56.208): icmp_seq=4 ttl=64 time=0.224 ms

至此,DNS服务器搭建并测试完毕,下面进入正题。

3、搭建Redis主从

关于redis搭建之前的文章已经介绍过,详细信息可参考历史文章
​https://www.cnblogs.com/gjc592/p/11098047.html。

1、搭建主、从节点redis实例,部署过程完全一致

依赖包安装。

yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tclb) 安装包准备

可以从官网 https://redis.io下载最新版redis。

wget http://download.redis.io/releases/redis-4.0.14.tar.gz
tar -zxvf redis-4.0.14.tar.gz

编译、安装。

cd redis-4.0.14
make
make install

创建目录、修改配置文件、启动redis。

建议创建单独的redis目录。

# 创建目录
mkdir -p /data/redis/redis6379
# 拷贝配置文件
cp redis.conf /data/redis/redis6379/
# 修改配置文件
vim redis.conf
修改如下部分
bind 0.0.0.0 可以指定所有地址均可访问,若指定对应网段或IP 修改此处即可
daemonize yes 放在后台执行,建议修改为yes
pidfile /data/redis/redis6379/redis_6379.pid 指定pid文件目录及文件名
logfile "/data/redis/redis6379/redis6379.log" 指定log文件目录及文件名
# 其他参数在生产环境中可适当调整
# 启动redis
redis-server redis.conf

2、配置主从

在从服务器执行如下命令配置主从。

127.0.0.1:6379> slaveof 192.168.56.208 6379 ## 即输入对应的redis主库的ip 即端口

查看主从状态。

127.0.0.1:6379> info Replication
## 结果如下
# Replication
role:slave
master_host:192.168.56.208
master_port:6379
master_link_status:up // up代表已正常同步
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:266
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:22830eb406e63f0a85d3d912a44e1b80dba6c860
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:266
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:266

至此,redis主从同步配置完成。

4、测试域名方式操作redis

编写程序,测试使用域名方式连接redis

注意:程序运行机器需添加对应的内网DNS服务器,即2.8中的操作。本次使用python进行测试

1、安装Python所需的包-- redis

python连接redis需安装redis包,关于Python升级,pip安装等历史文章里均有,如有需要可以参考操作

pip install redis

2、编写简单的Python操作redis的测试程序

vim test_redis.py
# 内容如下
#!/usr/bin/python
# coding=utf-8
import redis
v_ip ='www.redis.com'
v_port = 6379
v_passwd=''
r = redis.Redis(host=v_ip,port=v_port,password=v_passwd,db=0)
r.set('test_key1','test1')
result = r.get('test_key1')
print result ,"设置键成功并获取到values"
r.delete('test_key1')
print "删除键完毕"
result1 = r.get('test_key1')
print result1,"验证删除成功"

3、运行测试程序,看是否能通过域名操作成功

python test_redis.py
# 结果如下
test1 设置键成功并获取到values
删除键完毕
None 验证删除成功

有图有真相。

说明,使用域名操作redis正常。

5、模拟redis主库异常

1、关闭主库

127.0.0.1:6379> shutdown
not connected> exit

2、测试程序使用redis情况

python test_redis.py
## 报错
Traceback (most recent call last):
File "test_redis.py", line 9, in <module>
r.set('test_key1','test1')
File "/usr/local/python2.7/lib/python2.7/site-packages/redis/client.py", line 1451, in set
return self.execute_command('SET', *pieces)
File "/usr/local/python2.7/lib/python2.7/site-packages/redis/client.py", line 772, in execute_command
connection = pool.get_connection(command_name, **options)
File "/usr/local/python2.7/lib/python2.7/site-packages/redis/connection.py", line 994, in get_connection
connection.connect()
File "/usr/local/python2.7/lib/python2.7/site-packages/redis/connection.py", line 497, in connect
raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 111 connecting to www.redis.com:6379. Connection refused.

即,此时redis已无法使用。

3、提升从库为读写库

从库默认为只读,断开主从复制后将会变为读写库。

查看此时从库复制状态。

127.0.0.1:6379> info Replication
# Replication
role:slave
master_host:192.168.56.208
master_port:6379
master_link_status:down // 主从同步已断开
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:3215
master_link_down_since_seconds:98
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:22830eb406e63f0a85d3d912a44e1b80dba6c860
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:3215
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3215

断开主从同步。

127.0.0.1:6379> slaveof no one
OK
127.0.0.1:6379> info Replication
# Replication
role:master // 断开后,已变成主库
connected_slaves:0
master_replid:180df5fbdc8cf8999b27ad42e6c57eb3be31b6b2
master_replid2:22830eb406e63f0a85d3d912a44e1b80dba6c860
master_repl_offset:3215
second_repl_offset:3216
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3215

因此时域名仍指向原主库,所以程序依旧异常。

6、切换域名指向

1、修改配置文件

将DNS服务中对应域名的IP地址改为从库地址。

vim redis.com.zone
## 修改
$TTL 1D
@ IN SOA www.redis.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS www.redis.com.
dns IN A 192.168.56.207
www IN A 192.168.56.207
vim redis.com.local
# 修改后
$TTL 1D
@ IN SOA www.redis.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 192.168.56.207
AAAA ::1
207 IN PTR www.redis.com.

2、重启DNS服务或刷新缓存

本次测试直接重启DNS服务

/etc/init.d/named restart

3、简单测试域名解析情况

nslookup www.redis.com #正向测试DNS
# 结果如下
nslookup www.redis.com
Server: 192.168.56.209
Address: 192.168.56.209#53


Name: www.redis.com
Address: 192.168.56.207

说明已修改成功

7、最终测试

再次使用python 程序测试操作redis情况。

python test_redis.py
# 运行结果
test1 设置键成功并获取到values
删除键完毕
None 验证删除成功

此时应用程序未做任何修改,可以正常使用。

有关Redis高可用知多少之DNS篇的更多相关文章

  1. ruby-on-rails - 如何使辅助方法在 Rails 集成测试中可用? - 2

    我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel

  2. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

  3. ruby - 使用 Ruby,计算 n x m 数组的每一列中有多少个 true 的简单方法是什么? - 2

    给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in

  4. ruby-on-rails - self 在 Rails 模型中的值(value)是什么?为什么没有明显的实例方法可用? - 2

    我的rails3.1.6应用程序中有一个自定义访问器方法,它为一个属性分配一个值,即使该值不存在。my_attr属性是一个序列化的哈希,除非为空白,否则应与给定值合并指定了值,在这种情况下,它将当前值设置为空值。(添加了检查以确保值是它们应该的值,但为简洁起见被删除,因为它们不是我的问题的一部分。)我的setter定义为:defmy_attr=(new_val)cur_val=read_attribute(:my_attr)#storecurrentvalue#makesureweareworkingwithahash,andresetvalueifablankvalueisgiven

  5. ruby - 输出液体模板中的可用对象和属性 - 2

    有没有办法在liquidtemplate中输出(用于调试/信息目的)可用对象和对象属性??也就是说,假设我正在使用jekyll站点生成工具,并且我在我的index.html模板中(据我所知,这是一个液体模板)。它可能看起来像这样{%forpostinsite.posts%}{{post.date|date_to_string}}»{{post.title}}{%endfor%}是否有任何我可以使用的模板标签会告诉我/输出名为post的变量在此模板(以及其他模板)中可用。此外,是否有任何模板标签可以告诉我post对象具有键date、title、url、摘录、永久链接等

  6. ruby-on-rails - 是否有类似 'with_indifferent_access' 的数组可用于包含? - 2

    我尝试在我的应用中只使用:symbols作为关键词。我尝试在:symbol=>logic或string=>UI/languagespecific之间做出严格的决定但我也得到了每个JSON的一些“值”(即选项等),因为JSON中没有:symbols,所以我调用的所有哈希都具有“with_indifferent_access”属性。但是:数组是否有相同的东西?像那样a=['std','elliptic',:cubic].with_indifferent_accessa.include?:std=>true?编辑:将rails添加到标签 最佳答案

  7. ruby - 哪些 IDE 可用于 jRuby? - 2

    我进行了一些谷歌搜索,似乎缺少用于jRuby的IDE。我读过TextMate和Sublime,但它们不提供调试或代码完成功能。有人可以提出建议吗(或者这项技术还处于起步阶段)? 最佳答案 有几个选项;我更喜欢JetBrains'IntelliJ(RubyMine).AptanahasanEclipseplugin.NetBeansusedtohaveofficialsupport,不确定currentstate是什么是。 关于ruby-哪些IDE可用于jRuby?,我们在StackOve

  8. ruby - 正则表达式 - 这个用于素数检测的正则表达式的复杂性是多少? - 2

    这行ruby​​代码检测素数(太棒了!)。("1"*n)!~/^1?$|^(11+?)\1+$/#wherenisapositiveinteger详细信息在这篇博文中解释http://www.noulakaz.net/weblog/2007/03/18/a-regular-expression-to-check-for-prime-numbers/我很好奇它在BIG-O表示法中的表现。有人帮忙吗? 最佳答案 根据经验数据,它似乎是O(n2)。我对前10000个质数中的每100个运行Ruby代码。以下是结果:蓝点是记录的时间,橙色线是

  9. ruby-on-rails - 如果没有可用标签,则运行标记规范或全部 - 2

    我将guard与rspec和cucumber一起使用。要连续运行选定的规范,我只需使用focus标记来确定我要处理的内容。但问题是,如果没有带有该标签的规范,我想运行所有规范。我该怎么做?注意::我知道所有RSpec选项。因此,请仅在阅读问题后回复。 最佳答案 我通过以下配置实现了您描述的行为:#torunonlyspecificspecs,add:focustothespec#describe"foo",:focusdo#OR#it"shouldfoo",:focusdoconfig.treat_symbols_as_metada

  10. ruby-on-rails - Controller 中的实例变量如何可用于 Rails 中的 View - 2

    我从事Rails已有一段时间,并且刚刚开始深入研究Ruby元编程,Rails从中获得了强大的力量。我真的想不通这个,这让我发疯。Controller中的实例变量如何提供给Rails中的View(与View共享)?我知道它背后有一些元编程魔法,但我无法弄明白。在此先感谢您的所有帮助。 最佳答案 更新:原来接受的答案是错误的我现在将它留在下面以证明我错了。在获得足够多的反对票后,我决定研究这实际上是如何工作的。我最初的回答是在我对Rails还很陌生之后写的,并且是基于我使用过的其他MVC库(特别是:CodeIgniter)的工作方式的假

随机推荐