使用树莓派部署nginx服务器提供dns负载

2017/08/22 00:27:42 No Comments

之前买了一个小小的树莓派,一直在吃灰. 本来自己也有一个对外的博客域名,就想怎么样将此机器用起来.(本来就长年24小时开机,当简单的闹钟用)
本文章的目的是让树莓派工作起来,并没有一定技术上的特定优势,仅作技术验证以及耗电技术验证.
先说一下我这边的硬件和网络环境
1 linode云主机,cpu 1核,内存 1g,对外公网ip,地址新加坡(备案你懂的), nginx,mysql,php程序,之前是独立wordpress应用
2 树莓派3代,没部任何程序 上海电信家庭宽带 封80端口(后来发现的) 路由器可作内网转发

做负载均衡有很多种做法,根据当前的网络环境,以及硬件设备.对于像wordpress这种博客应用来说,有以下两种

1 后端应用负载
即使用一个前端nginx,后端通过挂一个upstream,将相应的请求代理到2个后端应用中.
这样的好处在于,应用始终访问一个对外地址,由统一的代理程序决定如何访问后端应用,并且也可以根据后端的实际情况设置权重.nginx上设置代理也简单.
不足之处,也有许多,主要是后端应用需要部署多套,并且相应的底层存储数据需要共享或者是复制.
1.1 在树莓派上就需要安装mysql,php这种应用,同时要开始公网数据同步,开销可能有点大.树莓派本身能不能支持mysql这种不算小型的数据库,内存和cpu占用都是未知问题.
1.2 前端代理访问,nginx之前安装在linode主机,当前也不准备更换,如果代理到树莓派,就意味着访问先从国内访问到linode,然后linode再内部访问到树莓派,中间的延时肯定会有问题
1.3 当然也可以将nginx放在树莓派国内电信上,不过鉴于电信宽带本身的稳定性(ip变化,断电,或者临时被封等),肯定比不上固定的云主机,而且树莓派一挂,整个博客即挂掉

2 访问前端负载
更往前一点就可以作dns负载, 通过dns解析域名时产生多个ip,让访问者随机选择1个进行访问.
好像在于,原linode应用不作任何调整,接下来就工作就是让访问树莓派时能够输出相应的内容即可
不足之处,在于当前的dns解析(使用的dnspod)当前还不能作权重,不能设置权重信息. 树莓派不用后端处理,那么就需要加速访问才能达到效果.

最后的方案就是dns负载,树莓派加速网络访问,整个步骤如下

  1. 搭建支持https以及lua脚本支持的nginx
  2. 加速GET请求处理
  3. 反向代理POST请求
  4. 反向代理wp-admin后台管理
  5. dns负载配置,ip动态更新
  6. 树莓派小尾巴

(more…)

排查redisson中订阅connection无故消失的问题

2016/12/13 20:52:41 No Comments

最近在项目中使用了redis结合spring cache一起作了一个缓存,并使用了订阅功能来达到进程间的数据同步。但在测试使用过程中,发现第二天一来,本来应该工作的订阅同步并不能进行。当时没在意,简单重启了事。但后来发现,每天早上相应的同步都不能进行,并且经测试。每个进程的同步都不进行,感觉是redis的订阅出问题了。

1. 验证问题

表现出来就是A程序修改了数据,B程序并没有识别到这次更新。那么就先尝试手动在redis中进行相应的set操作,因为订阅的是redis的空间事件,即key space event. 在控制台单独连接redis,执行相应的set 命令,在B程序中并没有任何表示。
怀疑是不是redis的发布订阅出问题了,就另开终端,手动地进行订阅,一切正常。
初步确定是程序出问题了。

2. 查看程序

把进程的stack打印一份,查看里面的线程信息,发现并没有redisson的线程信息。一般来说,没收到消息也可能是线程内阻塞了,但是直接就没有相应的线程,这就有问题了。
怀疑是不是相应的连接被断开之后就没有再连,也可能是redis server被重启了。

重新连接redis,使用status查看相应的状态,显示server端并没有重启过,其运行时间长达X天,即没有间断过。

回过来再看相应的redisson程序,里面有一个watch dog,是负责连接断开重连的。即如果连接被断掉了,它会尝试重连,但每一次的重连都会迟后一定时间,如 1 2 4 8 秒这样。这也是为什么要看stack的原因。简单看了下watchdog的实现,表示并没有明显的问题(或者就没问题)。

进一步怀疑是不是出现了某个异常,导致相应的watchdog重连直接被中断了。比如Error级错误。将相应的日志拉下来一份,因为一晚上都没人操作,日志信息本身也很少。直接在里面使用grep Exception查找日志信息,但一切也很正常,甚至没有异常发生。

再重新查看了redisson的源码,里面使用netty的channelInActive来进行重连尝试。在本地测试了一下这个机制,redis重启或者断开连接,它都能检测到。开始怀疑是不是日志信息不全,被吞掉了。重新调整日志级别,将redisson和netty的级别调到TRACE级别,结果中午过去一会,再回来看。相应的连接又不见了,订阅又不能正常工作。查看了日志,里面也没有任何信息,因为这期间无任何操作。

(more…)

redis中aof备份策略中的配置参数

2015/12/15 11:31:36 No Comments

在使用redis时,都会配置相应的存储策略,以保证redis并不会由于意外挂掉,在短时间内重启时数据不会消失。在当前的版本中,redis提供了bgsave和aof两种策略,本文主要描述了aof中的相关参数以及为什么这样是可以足够安全的。
本文的描述主要参考redis的conf文件以及各项网络

appendonly

开启aof特性,这个控制是否启用aof.

appendfilename

写入文件的文件名。开启aof之后,每条命令(除读之外的命令),均会写入到文件中,这里即实际写入的文件.

appendfsync

写入策略,默认值everysec,每秒写一次(调用flush)。另外两个值,always | no,分别表示每次redis写命令之外就写文件,和由操作系统保证。always对硬盘压力大,everysec是一个平衡值,no对硬盘压力最小,但调度由系统控制,丢失数据风险最大.

(more…)

redisson中连接对象创建及断线重连

2015/09/04 15:43:49 No Comments

在redisson中,由于使用了netty来封装对redis的协议访问,因此对于连接对象的创建和释放,也借由相应的connection来实现。由篇由masterSlave的角度,描述整个redisson中对于client的封装,以及在网络中断情况下,客户端会得到什么样的反馈,如何实现重连的情况。

本篇主要介绍master slave情况下各个对象的关系图信息,以及在具体创建时的一些处理问题.Redisson版本:2.1.1

1 对象关系图

整个关系如上所示,由下图进行描述

  1. 由MasterSlaveServersConfig负责配置连接的各项参数,比如master地址,slave地址,连接数大小等,这个对象是在redision创建时,由Config对象负责创建的
  2. 在调用Redission.create时,创建起相应的connectionManager对象,其持有相应的master连接信息,以及相应slave的连接信息
  3. 相应的connectionManager负责创建卢相应masterEntry以及slaveEntry信息,并且保存相应的映射信息
  4. connectionManager负责当前客户端对于具体服务器端的各项配置以下,比如转码器,连接池,使用的各项协议等,其根据这些信息,使用netty创建起相应的redisClient对象
  5. entry将已经创建好的redisClient交由connectionEntry负责持有,因此这里的client仅表示一个特有的客户端连接信息。在初始化时并不自动创建相应的连接
  6. entry因此持有相应的client,因此也自然根据当前的需要创建出相应的connection对象,这里entry的创建工作交由client负责,同时将创建好的connection管理起来

(more…)

基于redis的分布式锁 RedissonLock实现分析

2015/07/05 21:34:01 No Comments

在分布式锁的实现当中,都是通过另一个中央服务来存储相应的状态,来达到一个应用分布处理的目的。这里分析了一种通过redis来进行锁实现的细节,以描述在整个实现细节中的处理点。

通常在锁实现当中, 都要实现获取锁,等待锁,释放锁这几种关键的业务场景。然后在这几种场景的基础之上,还需要实现更多的语义,比如过期时间,等待时间等。通过redis的setNx可以达到获取锁的语义,因此大多数的实现均是采用这种手法来进行锁判断和处理(类似的手法还包括concurrentHashMap的putIfAbsent)

本文基于redission版本1.2.0,类RedissionLock.

线程间协作

1. 获取锁

获取锁即通过redis的setNx命令来实现,此命令的意义即仅当相应的值不存在时,才能设置成功。如果设置成功的话,即认为当前能够获取到相应的锁了。相应的主要代码如下所示:

Boolean res = connection.setnx(getName(), currentLock);

其中name即可认为是lock的一个内部表示名字,其中多个线程共享同一个lock,即在操作命令时会使用同一个name值。

(more…)

redisson的理解和使用-调用流程

2015/03/29 21:11:39 No Comments

redisson是一个用于连接redis的java客户端工作,相对于jedis,是一个采用异步模型,大量使用netty promise编程的客户端框架。

0     代码示例

        //创建配置信息
        Config config = new Config();
        config.useSingleServer().setAddress("localhost:6379").setConnectionPoolSize(5);

        Redisson redisson = Redisson.create(config);

        //测试 list
        List<String> strList = redisson.getList("strList");
        strList.clear(); //清除所有数据
        strList.add("测试中文1");
        strList.add("test2");

        redisson.shutdown();

从代码上来看,其基本的使用非常简单,在最后的使用当中。除与redisson打交道之外(获取各种数据结构),完全感觉不到与redis的信息连接。甚至于返回于上层直接不需要考虑下层的实现,一切均由redisson进行了封装。

(more…)