在dubbox的rest接口中使用表单提交对象

dubbox使用resteasy作为rest的实现方式,所以这篇文章的标题也可以称作:在resteasy的接口中使用表单来提交对象。

我们都知道,在resteasy中,假如接口参数是对象,那么参数定义的时候,什么注解都不需要写,直接就可以在前端用requestbody的形式提交json即可,非常方便。

但是需求来了,前端需要用 form 表单的形式来提交对象。

首先我参考了 resteasy 的官方文档 http://docs.jboss.org/resteasy/docs/3.0.7.Final/userguide/html/_Form.html

然后我查了资料,查到的是这样的一篇博文,RESTEasy数据自动装配之@FormParam,写得非常不错,我的解决就是参考这篇博文。但是在这篇文章中有2个疑问:
1,@Mapped这个是个什么鬼,不用这个也没有任何问题。
2,@Consumes(MediaType.APPLICATION_FORM_URLENCODED),这个我在postman中直接用 Content-Type:application/x-www-form-urlencoded 是没有任何问题的,也就是说 @Consumes(MediaType.APPLICATION_FORM_URLENCODED) 完全可以去掉。

在实现的时候,我们用得包和类如下:
@Form 是 org.jboss.resteasy.annotations.Form,属于resteasy-jaxrs-xxx.jar
@FormParam 是 javax.ws.rs.FormParam,属于javax.ws.rs-api-xx.jar

这个示例工程就不举了,因为还牵扯 springboot 和 dubbox 的细节,不举这个工程的例子了,大家参照上面的那篇博文,完全能写出来。

在junit中如何assert一个对象是null或者空字符串

在junit测试中,我们对某个对象需要判断是否为null,但是有时候在一些情况下,该对象可能是””(也就是空字符串),这个时候我们以前写得那个Assert.assertNull()就不行了。其实这种情况在现实中也是大量存在的,比如页面表单提交后的action获取表单中的字段,假如是字符串,那么往往是空字符串的存在。

那么,在junit中如何assert一个对象是null或者空字符串,我查了下资料,可以见这里:https://www.baeldung.com/java-assert-string-not-empty,我们可以用 Apache Commons Lang 来完成这个需求:
Assert.assertTrue(StringUtils.isEmpty(someObject));
不再用Assert.assertNull(),改用Assert.assertTrue()

这里有个小小的工程,可以看看 Assert.assertTrue(StringUtils.isEmpty(someObject)); 的使用:
https://github.com/champbay/springboot-test.git

SpringBootTest中启用不同的profiles

在springboot中,我们的工程常常有下面的配置文件:

application.properties
application-prod.properties
application-dev.properties

其中,application.properties是默认就加载的,prod和dev是需要在application.properties中指定spring.profiles.active=xxx来确定。

在测试的时候,需要测试环境,不管是prod还是dev都不适用的,所以在测试的时候,需要有个地方来设定配置文件。

查了资料,首先查到一篇文章:如何在@SpringBootTest中动态地启用不同的profiles,这篇文章讲了一大堆,我也没有全部看全,可能场景不适合我吧,总觉得这个需求应该非常普遍简单的,总不至于这么复杂的来解决吧。

继续查资料,看到这一篇文章:https://stackoverflow.com/questions/41985262/spring-boot-test-overriding-bootstrap-properties,这里有个人回答了几种办法,其中使用 Add @ActiveProfiles(‘test’),大家 test class 这种方式我觉得应该是最最正确的解决办法。

为此,我做了一个很小的测试工程放在 github 上,用来验证@ActiveProfiles(‘test’),大家可以去下来junit测试看看,看了后就能明白了。

工程地址:
https://github.com/champbay/springboot-test.git

JAVA字符串前补零和后补零的方法

字符串的前补零,往往用在排序上,比如:某个表id是字符串类型,a记录的id是“2”,b记录的id是“11”,从我们看来,因为是a排在b的前面,但是用字符串去排序的话,那么b将是在a的前面,所以这个时候需要进行前补零,其实入库之前就应该前补零就使得a的id就是“02”这样的格式。

字符串的后补零,往往用在财务统计报表上,需要对小数点进行统一,从而使得在界面的排版上数字的排列清晰。

前后补零的文章,我这里转载自一篇博文,JAVA字符串前补零和后补零的快速方法,例子举得很明白。

String fileName = "130181";
System.out.println("================  前补零方法一   =================");
DecimalFormat g1=new DecimalFormat("0000000");
String startZeroStr = g1.format(Integer.valueOf(fileName));
System.out.println("前补零方法一:"+startZeroStr);

System.out.println("================  前补零方法二   =================");
startZeroStr = String.format("%07d",Integer.valueOf(fileName));
System.out.println("前补零方法二:"+startZeroStr);

System.out.println("================  后补零方法一   =================");
DecimalFormat g2=new DecimalFormat("0.000000");
String endZeroStr = g2.format(Integer.valueOf(fileName));
System.out.println("后补零:"+endZeroStr);
System.out.println("虽然后补零出现这种情况,带有小数点");
System.out.println("比如你要长度要在7位以内,可以这么做");
System.out.println("后补零转变后:"+endZeroStr.replace(".","").substring(0,7));

输出结果如下:

================  前补零方法一   =================
前补零方法一:0130181
================  前补零方法二   =================
前补零方法二:0130181
================  后补零方法一   =================
后补零:130181.000000
虽然后补零出现这种情况,带有小数点
比如你要长度要在7位以内,可以这么做
后补零转变后:1301810

对于String.format()方法,可以查看jdk文档,里面有关于 formatter 的详细说明,:anguished:,太详细了以至于看得眼花缭乱,这里有一篇博文 JAVA字符串格式化-String.format()的使用,写得简单明了,大家可以上去看看前补零为什么是这样的格式。

用showdoc来编写网关接口文档

最近在工作上做了一个网关对外暴露接口,做好后要需要提供接口的文档,然后上网去查找有没有好用的编写接口文档的工具。

接口文档的编写分在线、自己部署2种。在线的网上大家可以搜一下,好多都是提供几个免费的文档,多了后需要付费。自己部署的分为:免费、开源、商业的。这里有一篇文章罗列了一些工具网站:接口文档工具,我就是从这里找到了 showdoc 这个比较满意的工具。

showdoc的官网地址:https://www.showdoc.cc/ 里面有一个示例工程,可以看到一些最终的效果;同时假如你不想搭建一套私有的,你可以进行注册后创建项目,同时拉人进来查看文档。

如何搭建一套showdoc的应用,showdoc的帮助文档写得比较仔细,我因为偷懒,采用了他的docker来进行安装,安装的时候,因为没有严格按照他的步骤,导致了出现一些文件写权限的问题,注意:必须要严格按照文档上的步骤来进行部署 docker 。

部署好首次登录,用户名和密码为:showdoc/123456,进去后别忘记修改密码。

我这里大致罗列一下功能点,这些功能点对于接口文档的编写挺有用的,说明作者是用心了:
1,左侧可以做成树形结构,可以用单独的页面来描述全局性的说明、流程等,用个目录来包含业务接口的页面。
2,有人员权限的划分,基本上对于我们来说,编写、查看这样简单的权限足矣。
3,页面采用markdown,基本上可以满足各种格式的书写;作者特别有心,考虑到一些人对markdown的语法不熟悉,就弄了一些常用的模板,很贴心。

对于其他的一些功能,比如接口测试这样的功能,我个人觉得倒没有这个必要了,术业有专攻,可以用postman来测试的,没有必要这里那么复杂的再实现一个。

最后,提醒一下用 showdoc 的人,别忘记备份了,docker 的备份是 /showdoc_data 这个目录。

mysql的时间字段如何设置为支持毫秒

mysql的时间字段类型,datetime,timestamp,我用的都是精确到秒,格式为 yyyy-MM-dd HH:mm:ss ,但是如何让这2个字段支持毫秒呢, 也就是格式为:yyyy-MM-dd HH:mm:ss.SSS。

这篇文章 https://blog.csdn.net/mchdba/article/details/75259947 写得挺好的,但是他给的那个官方文档没有链接,我这里给出:Fractional Seconds in Time Values,可以看到mysql从 5.6 开始支持毫秒,而在 mysql 5.5 是不支持毫秒的。可以从官方的文档上有个下拉框可以选择 5.5 的版本,看到是不支持毫秒的,那么5.5对于毫秒该怎么办?只能将时间转为long型后存储,存取的时候需要进行转换。

DATETIME(3),TIMESTAMP(3) 括号中的数字是表示小数位取几位,一般我们取得是 3位,所以写3 即可。

socketio中的关于acknowledgement的进一步解释

websocket中对于消息的确认(acknowledgement)是没有实现的,需要我们自己在收到消息后回复一遍,如此增加了程序的复杂度。

socketio是对websocket的一些封装,提供了很多有价值的方法,其中就是确认(acknowledgement)的实现,非常棒的封装。

首先让我们来描述一下场景,然后从场景中知道一些定义:
1,网页发出一个websocket请求,发给服务器,服务器收到后,对网页来个确认消息。我们称网页为client,服务端为server。这个非常好理解。
2,服务器发一个websocket请求给网页,网页收到后,对服务器来个确认消息。我们还是称网页为client,服务端为server。这个也是容易理解的。

但是websocket非常特殊,因为服务器端能主动给网页端发消息,假如我们从消息的发送方(sender)和消息的接收方(receiver)来看,我们可以这么称消息的发送方为client,消息的接收方为server。那么从这个方面来看,当服务器端能主动给网页端发消息,服务器端为client,而网页端为server。

为了避免混淆,我们统统称网页端为client,服务器端为server。

我们来看一下 socketio 的文档:Sometimes, you might want to get a callback when the client confirmed the message reception. #有时候,在客户端发送消息后,客户端对服务端收到消息后,客户端需要有个回调来进行一些处理(确认)

下面这个例子就举了客户端发送消息给服务端,然后服务端对该消息进行了确认,这个确认能在客户端得到响应:


Server (app.js)
var io = require('socket.io')(80);

io.on('connection', function (socket) {
  socket.on('ferret', function (name, word, fn) {
    fn(name + ' says ' + word);
  });
});
--------------------------------------------------
Client (index.html)
<script>
  var socket = io(); // TIP: io() with no args does auto-discovery
  socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
    socket.emit('ferret', 'tobi', 'woot', function (data) { // args are sent in order to acknowledgement function
      console.log(data); // data will be 'tobi says woot'
    });
  });
</script>

socketio的文档关于acknowledgement只讲了上面这个例子,其实从websocket来看,还有服务端发消息给客户端,然后客户端进行确认,从而服务端能得到回调这样的流程。

所以,从上面2个流程的意义上来看,那么这句话改成如下的就更加能明白了:
Sometimes, you might want to get a callback when the sender confirmed the message reception.

嗯,最好的例子我找了个,写得非常好:
https://github.com/mrniko/netty-socketio-demo ,大家可以去看看
另外,http://www.cnblogs.com/lightsong/p/10226940.html, 这篇文章解释了确认(acknowledgement)的实现机理,感兴趣的同学可以去看看。

参考资料

socketio文档
netty-socketio例子
acknowledgement的实现机理

在docker中搭建redis集群以及哨兵sentinel

在上一篇文章《在一台centos7服务器上搭建redis集群以及哨兵sentinel》中,我们提到了一个很重要的知识点,大家可以去看看。
在这里,我们会反复提到这个知识点,对于docker下部署redis sentinel非常重要。

部署环境

  1. 假设该宿主机服务器的ip是:192.168.1.100,docker0的ip是:172.17.0.1
  2. 使用redis的镜像是:docker pull redis:5.0.4
  3. redis只搭建1主1从(网上很多都是1主2从,没有这个必要),3个sentinel(3个是必须的,否则在failover的时候就会出现一些不必要的问题)
  4. 6379:redis server,docker的volume目录在 /data/redis-6379
    6380: redis server,docker的volume目录在 /data/redis-6380
    26379:redis sentinel,docker的volume目录在 /data/redis-26379
    26380:redis sentinel,docker的volume目录在 /data/redis-26380
    26381:redis sentinel,docker的volume目录在 /data/redis-26381

部署过程

部署redis-6379

1,mkdir -p /data/redis-6379/conf && mkdir -p /data/redis-6379/data && chmod 666 -r /data/redis-6379 && cd /data/redis-6379/conf
这里的chmod 666 非常重要,原因有下面2个:
我们从redis Dockerfile中可以看到,docker中的redis用户和用户组是 redis,

RUN mkdir /data && chown redis:redis /data

redis在进行sentinel,failover的时候会改写配置文件,redis的用户是redis,而宿主机的目录是另外的人,所以需要改变目录权限
2,vi redis.conf,内容如下:
requirepass “123456”
masterauth “123456”
slave-announce-ip “192.168.1.100”
slave-announce-port 6379
重点来了,这里的masterauth,已经从上一篇文章中解释了。
还有2个配置:slave-announce-ip,slave-announce-port这2个呢?原因和masterauth一样的,当发生failover的时候,这个原先是主的redis就会成为从,所以这2个配置是给主在成为从的时候使用的。但是为什么要在docker环境中用这2个配置,在上一篇文章中为什么不用呢?因为在docker环境下,假如不用这2个配置,那么在连接到主服务器上后,ip地址会变成172.17.0.1这个docker0地址,同时端口始终是6379。等下我们可以看看。
3,加入 docker-compose.yml 以下内容

redis-6379:
  image: redis:5.0.4
  container_name: redis-6379
  volumes:
    - /data/redis-6379/conf/redis.conf:/usr/local/etc/redis/redis.conf
    - /data/redis-6379/data:/data
  ports:
    - 6379:6379
  command: redis-server /usr/local/etc/redis/redis.conf

4,运行docker-compose
docker-compose up -d redis-6379
5,登录redis控制台
docker exec -it redis-6379 /bin/bash
redis-cli
auth 123456
info
可以看到role: master
exit
exit

部署redis-6380

1,mkdir -p /data/redis-6380/conf && mkdir -p /data/redis-6380/data && chmod 666 -r /data/redis-6380 && cd /data/redis-6380/conf
2,vi redis.conf,内容如下:
requirepass “123456”
masterauth “123456”
slaveof 192.168.1.100 6379
slave-announce-ip “192.168.1.100”
slave-announce-port 6380
3,加入 docker-compose.yml 以下内容

redis-6380:
  image: redis:5.0.4
  container_name: redis-6380
  volumes:
    - /data/redis-6380/conf/redis.conf:/usr/local/etc/redis/redis.conf
    - /data/redis-6380/data:/data
  ports:
    - 6380:6379
  command: redis-server /usr/local/etc/redis/redis.conf

4,运行docker-compose
docker-compose up -d redis-6380
5,登录redis控制台
docker exec -it redis-6379 /bin/bash #注意这里是登录6379这个主redis容器
redis-cli
auth 123456
info
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.100,port=6380,state=online,offset=561,lag=1
这里可以看到 slave的ip是正确的。假如我们在 6380 的配置中没有设置slave-announce-ip “192.168.1.100” 和 slave-announce-port 6380的话,那么将在这里看到的是 slave0:ip=172.17.0.1,port=6379,state=online,offset=561,lag=1,如此的设置当然会在failover的时候发生异常了。所以从这里能很清楚明白这2个配置的重要性。
exit
exit

部署redis-26379

1,mkdir -p /data/redis-26379/conf && mkdir -p /data/redis-26379/data && chmod 666 -r /data/redis-26379 && cd /data/redis-26379/conf
2,vi sentinel.conf,内容如下:
protected-mode no
port 26379
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel auth-pass mymaster 123456
sentinel announce-ip “192.168.1.100”
sentinel announce-port 26379
这里的2个配置 sentinel announce-ip 和 sentinel announce-port 和 上面的那2个意思大致差不多,假如不这么设置的话,那么在 sentinel 的ip通信中就会出现 172.17.0.1:26379 这样错误的值。下面会进一步说到。
3,加入 docker-compose.yml 以下内容

redis-26379:
  image: redis:5.0.4
  container_name: redis-26379
  volumes:
    - /data/redis-26379/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    - /data/redis-26379/data:/data
  ports:
    - 26379:6379
  command: redis-server /usr/local/etc/redis/sentinel.conf

4,运行docker-compose
docker-compose up -d redis-26379

部署redis-26380

1,mkdir -p /data/redis-26380/conf && mkdir -p /data/redis-26380/data && chmod 666 -r /data/redis-26380 && cd /data/redis-26380/conf
2,vi sentinel.conf,内容如下:
protected-mode no
port 26379
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel auth-pass mymaster 123456
sentinel announce-ip “192.168.1.100”
sentinel announce-port 26380
3,加入 docker-compose.yml 以下内容

redis-26380:
  image: redis:5.0.4
  container_name: redis-26380
  volumes:
    - /data/redis-26380/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    - /data/redis-26380/data:/data
  ports:
    - 26380:6379
  command: redis-server /usr/local/etc/redis/sentinel.conf

4,运行docker-compose
docker-compose up -d redis-26380
5,cat /data/redis-26379/conf/sentinel.conf #注意这里查看 redis-26379
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 192.168.1.100 6380
sentinel known-sentinel mymaster 192.168.1.100 26380 75f969e584d6cae9f23a6f9da6069d8c69873452
从这里能注意到2件事情:
a,看到“Generated by CONFIG REWRITE”这句注释,说明redis对配置文件进行了修改。这就是为什么我们一开始就把配置文件所在的volumn的权限设置为666的原因:chmod 666 -r /data/redis-xxx,假如上面没有修改,那么就会报错:CONFIG REWRITE failed: Permission denied,这个错误不影响启动,但是会影响发生failover后的一些问题,所以一定要事先设置好权限。
b,看到 192.168.1.100 26380 这个配置,这就是前面所讲到的 sentinel announce-ip, sentinel announce-port 的作用,假如没有设置,那么这里将是 172.17.0.1 26379 这个错误的ip。
cat /data/redis-26380/conf/sentinel.conf,也能看到如此的情况,不多说

部署redis-26381

这里不多说,和 redis-26380类似。

测试

咱们用 https://github.com/champbay/redis-sentinel 这个工程来进行测试
启动这个工程后,可以看到不断的往 redis 中插入 test-i 这样的值
然后,docker stop redis-6379,马上可以看到这个工程开始报错,大概过了5秒钟(因为我上面设置的是5秒钟),又恢复正常了,说明 redis sentinel已经起效了。
我们查看一下 6380 的配置文件,cat /data/redis-6380/conf/redis.conf,看到 slaveof 已经不见了,间接说明成为了主。通过进入redis-6380容器,redis-cli看一下info,可以看到确实成为了master。这里也说明需要事先修改一下配置文件的权限,否则这里就会报错。
我们再次启动 docker start redis-6379,稍等一会,查看6379的配置文件,发现最后多了一行 slaveof 192.168.1.100 6380,(slaveof == replicaof),说明已经成为了从,从 redis-cli也能看出。

一些js的加密混淆工具

在线

比较好的js加密解密网站:https://tool.lu/js, 这个工具中可以使用美化、净化、加密、混淆这几种方法。这些方法都是网站前台发到后台去处理的。通过美化、净化、加密、混淆后的js代码,就算通过解密也难以恢复那些变量的命名,增加了查看的难度,当然了,最终还是能够破解一些核心点的,只不过增加了难度而已。

这里提一下,有比较多的在线js加密解密混淆网站,打着免费使用的目的,在加密的文件中加入自己使用的软件名称,原因就是让破解者花钱找他们,让他们破解,这里大家在使用的时候要小心点。

uglifyjs

这个是目前js开源界中最有名的一个,在github上的地址:https://github.com/mishoo/UglifyJS2, 已经被 webpack 整合。中文文档在这里:https://segmentfault.com/a/1190000010874406。如何使用:
npm install uglify-js -g
uglifyjs aaa.js –compress –mangle -o aaa.min.js
通过uglifyjs出来的最终文件,可看性是还可以大致能看清一些核心代码的,通过解密后那些变量的命名也不能恢复。效果比上面提到的在线工具要差一些。

jsfuck

https://github.com/aemkei/jsfuck, 这个看上去很美,其实有2个致命问题:
1,可以被 http://codertab.com/JsUnFuck 顺利解开。
2,不兼容IE。
所以大家不要考虑了。

decent-messup

https://github.com/blackmiaool/decent-messup,是国人写的,这个也看上去不错,但是不兼容IE。

到现在为止还没有找到一个特别厉害的,所以一些涉及安全的js,还是尽量放在后台处理吧,前台目前只能将就一下了。

大家有好的,可以给我推荐,收费的尽量不要推荐了。

在一台centos7服务器上搭建redis集群以及哨兵sentinel

很早很早以前,具体时间有点忘记了,那个时候redis还没有高可用的方案,但是线上的又希望有redis的高可用,于是参考资料,搭建了一套基于haproxy和keepalived的方案,但是这套方案在测试的时候就发现了很大很大的问题,于是没有最终上线,只能等着redis官方的高可用版本。现在我们来看一下那个时候我写的一段内容:

当redis master宕机后,HaProxy会马上切换到redis slave上。
假如redis master再次启动后,这个时候问题出来了:
1)  HaProxy会自作聪明的再次将redis请求路由到redis master上。
2)  redis slave将会从redis master上再次同步数据,结果导致redis slave上的数据丢失。
为了应付这个问题,假设有redis master为r1,redis slave为r2,这个时候r1宕掉了,需要如下处理:
1)  千万不要马上重新启动r1,切记。
2)  用redis-cli 连接r2,发送命令。如:./redis-cli  SLAVEOF no one
3)  修改r1的配置文件,把r1设置为slave。如:slaveof  ip:port
4)  热配置HaProxy,将r2设置为主要路由,r1设置为failover路由。具体参见HaProxy的architecture.txt中的4.3 Hot Configuration
5)  启动r1。
上述步骤次序关键,不能搞错,搞错后就有可能导致redis上的数据完全丢失。

上述这段文字大家不用仔细看,只需要知道没有redis的哨兵模式时代是多少的痛苦。

重要知识点,很多同学因为下面这个知识点不明白,导致了出现问题

一开始,比如6379是主,6380是从,redis在进行设置的时候,是有主从设置的,那么在6380的配置文件中需要设置masterauth和slaveof这2个配置,而6379是不需要设置这2个配置的。
后来发生了failover,那6380就成了主,而6379就成了从。这个时候,sentinel会修改6379和6380的配置文件,slaveof还好说,sentinel会自动修改,但是6379要去访问6380,因为一开始在6379中是没有masterauth这个配置的,所以就会出现同步失败。
那为什么sentinel一开始不把6380这个从上设置的masterauth配置给记录下来?原因我没有去进一步探索,是不是涉及安全问题?

结论是:只有一开始的时候对某个redis来说是有主从固定配置的,后续一旦发生了failover,这些配置就会被自动改写。所以对于一开始的主并不能永远是主,那么在设置的时候,还需要参考从的一些配置,事先做好(这一点也会在我的后一篇文章《在docker中搭建redis集群以及哨兵sentinel》讲道),对于6379主,也需要设置好masterauth这个本应该是从的配置。

部署环境

  1. redis的哨兵模式和网络环境很有关系,当在docker、nat等环境下,需要进行额外的处理,详细见我的后一篇文章《在docker中搭建redis集群以及哨兵sentinel
  2. 本文只描述在一台服务器上部署,对于多台服务器结合我后面的那篇文章《在docker中搭建redis集群以及哨兵sentinel》(其实就是网络环境),过程也是同样的
  3. 假设该服务器的ip是:192.168.1.100,已经安装了 redis,版本比如是 5 以上的,其实 3.x.x 也是可以的,这个只需要查看一下redis官方文档即可。
  4. redis只搭建1主1从(网上很多都是1主2从,没有这个必要),3个sentinel(3个是必须的,否则在failover的时候就会出现一些不必要的问题)
  5. 该服务器已经开放了防火墙的端口给客户端来调用:6379,6380,26379,26380,26381
  6. 6379:redis server
    6380: redis server
    26379:redis sentinel
    26380:redis sentinel
    26381:redis sentinel

部署过程

部署redis-6379

1,mkdir -p /usr/local/redis-6379/data && cd /usr/local/redis-6379
2, vi redis.conf,内容如下:
requirepass “123456”
port 6379
daemonize yes
pidfile “/var/run/redis-6379.pid”
logfile “/usr/local/redis-6379/redis.log”
dir “/usr/local/redis-6379/data”
masterauth “123456” #这里是主,为什么还要设置从的配置,原因见上
3,redis-server redis.conf
4, redis-cli -p 6379
> auth 123456
> info
可以看到:
# Replication
role:master
connected_slaves:0
> exit

部署redis-6380

1,mkdir -p /usr/local/redis-6380/data && cd /usr/local/redis-6380
2, vi redis.conf,内容如下:
requirepass “123456”
port 6380
daemonize yes
pidfile “/var/run/redis-6380.pid”
logfile “/usr/local/redis-6380/redis.log”
dir “/usr/local/redis-6380/data”
masterauth “123456”
replicaof 192.168.1.100 6379 #replicaof == slaveof,在3.x.x中用 slaveof
3,redis-server redis.conf
4, redis-cli -p 6379
> auth 123456
> info
可以看到:
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.100,port=6380,state=online,offset=15680,lag=0
假如上面的slave0的ip不是192.168.1.100,而是另外一个ip,而这个ip又不是redis的客户端所能访问到的,那么就需要额外进行设置,详细见我的后一篇文章《》
> exit
5, redis-cli -p 6380
> auth 123456
> info
可以看到:
# Replication
role:slave
master_host:192.168.1.100
master_port:6379
可以看到6379是master,6380是slave,各自的配置都是正确的

部署redis-26379

1,mkdir -p /usr/local/redis-26379 && cd /usr/local/redis-26379
2, vi sentinel.conf,内容如下:
protected-mode no #允许外网访问
port 26379
daemonize yes
pidfile “/var/run/sentinel-26379.pid”
logfile “/usr/local/redis-26379/sentinel.log”
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel auth-pass mymaster 123456
3,redis-sentinel sentinel.conf
4, redis-cli -p 26379
> info
可以看到:
# Sentinel
sentinel_masters:1
master0:name=mymaster,status=ok,address=192.168.1.100:6379,slaves=1,sentinels=3
> exit

部署redis-26380

1,mkdir -p /usr/local/redis-26380 && cd /usr/local/redis-26380
2, vi sentinel.conf,内容如下:
protected-mode no #允许外网访问
port 26380
daemonize yes
pidfile “/var/run/sentinel-26380.pid”
logfile “/usr/local/redis-26380/sentinel.log”
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel auth-pass mymaster 123456
3,redis-sentinel sentinel.conf
4, redis-cli -p 26380
> info
可以看到:
# Sentinel
sentinel_masters:1
master0:name=mymaster,status=ok,address=192.168.1.100:6379,slaves=1,sentinels=3
# SENTINEL sentinels mymaster
可以看到到目前为止的2个sentinel,可以看到 sentinel 的ip,假如ip不是192.168.1.100,而是另外一个ip,而这个ip又不是redis的客户端所能访问到的,那么就需要额外进行设置,详细见我的后一篇文章《在docker中搭建redis集群以及哨兵sentinel
> exit

部署redis-26381

和redis-26380的一样,只需要把 26380 改成 26381

测试

咱们用 https://github.com/champbay/redis-sentinel 这个工程来进行测试
启动这个工程后,可以看到不断的往 redis 中插入 test-i 这样的值
然后,kill 掉 6379 这个 redis 进程,可以看到这个工程开始报错,大概过了5秒钟(因为我上面设置的是5秒钟),又恢复正常了,说明 redis sentinel已经起效了。
我们查看一下 6380 的配置文件,cat /usr/local/redis-6380/redis.conf,看到 slaveof 已经不见了,间接说明成为了主。通过redis-cli -p 6380看一下info,可以看到确实成为了master。
我们再次启动 6379,稍等一会,查看6379的配置文件,发现最后多了一行 slaveof 192.168.1.100 6380,(slaveof == replicaof),说明已经成为了从,从 redis-cli也能看出。