PHP集群session共享

集群的概念没有多复杂,其实就是多台电脑为了同一个目标在一起工作。在Web应用中,就是多个服务器提供一个站点的服务。

搭建PHP集群的第一步就是设置负载均衡。首先我们需要三台主机:

Nginx负载:192.166.5.111
PHP应用1:192.168.5.112
PHP应用2:192.168.5.113

1

先前,在PHP应用所在的主机,我们需要安装Nginx或者apache等这类web服务器,然后再在前面使用Nginx作为负载。Nginx 负载和php应用之间的通信是在应用层的,Nginx负载其实就相当于一个代理。但是,现在情况不同了。Fastcgi技术的应用允许在php应用层可以不用再安装web服务器。现在PHP5.5版本已经将fpm作为内部模块支持了。在这种情况下,Nginx 负载和php应用之间的通信是在传输层的,二者之间使用socket进行通信。当然了,这需要fpm服务的支持。

2

Nginx设置

首先对Nginx(192.168.5.111)进行设置,编辑nginx.conf配置文件

http{
         ……
         upstream onmpw_phpApps{
            server 192.168.18.88:9000;
            server 192.168.18.191:9000;
        }
        ……
       Server{
         listen        80;
         server_name   load.onmpw.com   ##这里是域名
         root           /www/onmpw         
         ……
         location ~ \.php$ {
                   root         /www/onmpw   ##这里是PHP应用所在目录
                   fastcgi_pass   onmpw_phpApps;
                   ……
         }
      }
}

以上是对Nginx进行的设置。其中只是包含了关键的部分,其余的和平常我们使用Nginx+PHP作为web服务的时候进行的设置相同。

PHP所在主机设置

这里的设置就比较简单了。

首先编辑php-fpm.conf文件,修改监听的ip和端口,然后启动fpm服务

主机192.168.5.112

Listen = 192.168.5.112:9000   //这里的端口可以自行设置。保存退出
# /usr/local/php/sbin/php-fpm   //开启服务

主机192.168.5.113

Listen = 192.168.5.113:9000
# /usr/local/php/sbin/php-fpm

到这里就对PHP的主机设置完成了。当然了,代码需要在两台主机上各上传一份儿。

好了,经过上面的设置,一个基本的PHP集群就已经搭建完成了。但是有一个问题,这种情况如果只是访问静态资源或者不进行交互的话是没有问题的。如果需要交互,那就涉及到一个session共享的问题。默认情况下PHP是将session存在本地磁盘上的。那这两台主机之间如何共享session呢,接下来我们就来解决这个问题。

PHP主机之间Session共享

之前在网上看到过一种解决方式。由于PHP是将session存储在文件中,那我们可以在Nginx负载主机上面搭建一个分布式文件系统(NFS),让两台PHP主机的session都存放在此文件系统中。以此来达到共享session的目的。

3

我个人比较倾向于将session存储到数据库中。因此这里我介绍的是将session存储到redis中。所以我们需要增加一台Redis服务器

Redis服务器:192.168.5.114

4

PHP默认情况下是不支持对Redis的操作的。所以这里我们需要自己手动安装第三方的扩展,使其支持对Redis的操作。关于如何使PHP支持Redis,我们可以参考《PHP操作Redis的两种方式》

在这里我就认为我们的PHP已经支持Redis了。接下来是将session存储到Redis中,有两种方式:一种是直接修改PHP的配置文件php.ini;另一种是重写session机制。

修改PHP配置文件php.ini将session存储到Redis

使用vim打开php.ini,需要修改的有这两项:session.save_handler和session.save_path。

session.save_handler = Redis

//不需要密码验证
session.save_path = “tcp://192.168.5.114:6379”

//Redis 需要密码验证
session.save_path = “tcp://192.168.5.114:6379?auth=password”

修改完成,保存退出。然后重启php-fpm服务

# kill -INT `cat /usr/local/php/var/run/php-fpm.pid`
# /usr/local/php/sbin/php-fpm

两台PHP主机都做按照以上步骤操作。经过以上步骤,对于session的所有信息都保存到了Redis中。从而实现了session的共享。

通过重写session机制将session存储到Redis

通常,在很多情况下我们是没有权限修改php.ini文件的。这时候我们可以通过重写session机制来修改session信息的存储。

对于重写session,php已经为我们提供了SessionHandlerInterface 接口。我们只要实现这个接口就可以了。关于如何重写session机制,大家可以参考《PHP重写session机制》这篇文章。该类的完整代码在github上,大家有兴趣的和可以点此查看

总结

PHP集群的架构方式有很多种,但是其原理都大同小异。关键是找出最适合自己项目的最佳方案。例如:对于session存储方式的选择,你也可以选择使用memcache或者mysql数据库等。总之最适合自己的就是最优的。希望本文对大家有所帮助。

如何架构高可用的Web站点

一、什么是高可用

高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

假设系统一直能够提供服务,我们说系统的可用性是100%。

如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。

很多公司的高可用目标是4个9,也就是99.99%,这就意味着,系统的年停机时间为8.76个小时。

百度的搜索首页,是业内公认高可用保障非常出色的系统,甚至人们会通过www.baidu.com 能不能访问来判断“网络的连通性”,百度高可用的服务让人留下啦“网络通畅,百度就能访问”,“百度打不开,应该是网络连不上”的印象,这其实是对百度HA最高的褒奖。

 

二、如何保障系统的高可用

我们都知道,单点是系统高可用的大敌,单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。方法论上,高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响;如果有冗余备份,挂了还有其他backup能够顶上。

保证系统高可用,架构设计的核心准则是:冗余。

有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的不可服务实践。所以,又往往是通过“自动故障转移”来实现系统的高可用。

接下来我们看下典型互联网架构中,如何通过冗余+自动故障转移来保证系统的高可用特性。

 

三、常见的互联网分层架构

常见互联网分布式架构如上,分为:

(1)客户端层:典型调用方是浏览器browser或者手机应用APP

(2)反向代理层:系统入口,反向代理

(3)站点应用层:实现核心应用逻辑,返回html或者json

(4)服务层:如果实现了服务化,就有这一层

(5)数据-缓存层:缓存加速访问存储

(6)数据-数据库层:数据库固化数据存储

整个系统的高可用,又是通过每一层的冗余+自动故障转移来综合实现的。

四、分层高可用架构实践

【客户端层->反向代理层】的高可用

20170305211812759
【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余来实现的。以nginx为例:有两台nginx,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。

20170305211812759
自动故障转移:当nginx挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-nginx,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

 

【反向代理层->站点层】的高可用

20170305211812759
【反向代理层】到【站点层】的高可用,是通过站点层的冗余来实现的。假设反向代理层是nginx,nginx.conf里能够配置多个web后端,并且nginx能够探测到多个后端的存活性。

20170305211812759
自动故障转移:当web-server挂了的时候,nginx能够探测到,会自动的进行故障转移,将流量自动迁移到其他的web-server,整个过程由nginx自动完成,对调用方是透明的。

 

【站点层->服务层】的高可用

20170305211812759
【站点层】到【服务层】的高可用,是通过服务层的冗余来实现的。“服务连接池”会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。

20170305211812759
自动故障转移:当service挂了的时候,service-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的service,整个过程由连接池自动完成,对调用方是透明的(所以说RPC-client中的服务连接池是很重要的基础组件)。

 

【服务层>缓存层】的高可用

20170305211812759
【服务层】到【缓存层】的高可用,是通过缓存数据的冗余来实现的。

缓存层的数据冗余又有几种方式:第一种是利用客户端的封装,service对cache进行双读或者双写。

 

20170305211812759
缓存层也可以通过支持主从同步的缓存集群来解决缓存层的高可用问题。

以redis为例,redis天然支持主从同步,redis官方也有sentinel哨兵机制,来做redis的存活性检测。

20170305211812759
自动故障转移:当redis主挂了的时候,sentinel能够探测到,会通知调用方访问新的redis,整个过程由sentinel和redis集群配合完成,对调用方是透明的。

 

说完缓存的高可用,这里要多说一句,业务对缓存并不一定有“高可用”要求,更多的对缓存的使用场景,是用来“加速数据访问”:把一部分数据放到缓存里,如果缓存挂了或者缓存没有命中,是可以去后端的数据库中再取数据的。

这类允许“cache miss”的业务场景,缓存架构的建议是:

20170305211812759
将kv缓存封装成服务集群,上游设置一个代理(代理可以用集群冗余的方式保证高可用),代理的后端根据缓存访问的key水平切分成若干个实例,每个实例的访问并不做高可用。

20170305211812759
缓存实例挂了屏蔽:当有水平切分的实例挂掉时,代理层直接返回cache miss,此时缓存挂掉对调用方也是透明的。key水平切分实例减少,不建议做re-hash,这样容易引发缓存数据的不一致。

 

【服务层>数据库层】的高可用

大部分互联网技术,数据库层都用了“主从同步,读写分离”架构,所以数据库层的高可用,又分为“读库高可用”与“写库高可用”两类。

 

【服务层>数据库层“读”】的高可用

20170305211812759
【服务层】到【数据库读】的高可用,是通过读库的冗余来实现的。

既然冗余了读库,一般来说就至少有2个从库,“数据库连接池”会建立与读库多个连接,每次请求会路由到这些读库。

20170305211812759
自动故障转移:当读库挂了的时候,db-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的读库,整个过程由连接池自动完成,对调用方是透明的(所以说DAO中的数据库连接池是很重要的基础组件)。

 

【服务层>数据库层“写”】的高可用

20170305211812759
【服务层】到【数据库写】的高可用,是通过写库的冗余来实现的。

以mysql为例,可以设置两个mysql双主同步,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。

20170305211812759
自动故障转移:当写库挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-db-master,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

 

五、总结

高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

方法论上,高可用是通过冗余+自动故障转移来实现的。

整个互联网分层系统架构的高可用,又是通过每一层的冗余+自动故障转移来综合实现的,具体的:

(1)【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

(2)【反向代理层】到【站点层】的高可用,是通过站点层的冗余实现的,常见实践是nginx与web-server之间的存活性探测与自动故障转移

(3)【站点层】到【服务层】的高可用,是通过服务层的冗余实现的,常见实践是通过service-connection-pool来保证自动故障转移

(4)【服务层】到【缓存层】的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与sentinel保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性

(5)【服务层】到【数据库“读”】的高可用,是通过读库的冗余实现的,常见实践是通过db-connection-pool来保证自动故障转移

(6)【服务层】到【数据库“写”】的高可用,是通过写库的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

原文:http://lib.csdn.net/article/architecture/65600

 

Nginx负载均衡配置

负载均衡,将用户的所有HTTP请求均衡的分配到每一台机器上,充分发挥所有机器的性能,提高服务的质量和用户体验。负载均衡可以通过负载均衡网络硬件设备和Web服务器软件来实现,前者设备成本较高,小公司通常负担不起,所以后者一般是我们的首选。实现负载均衡常用的Web服务器软件有Nginx、HAProxy、LVS、Apache,本文主要介绍Nginx的负载均衡策略:

一、内置负载策略

Nginx负载均衡是通过upstream模块来实现的,内置实现了三种负载策略,配置还是比较简单的。官网负载均衡配置说明:http://nginx.org/en/docs/http/load_balancing.html

  • 1.轮循(默认) 
    
    Nginx根据请求次数,将每个请求均匀分配到每台服务器
  • 2.最少连接 
    
    将请求分配给连接数最少的服务器。Nginx会统计哪些服务器的连接数最少。
  • 3.IP Hash 
    
    绑定处理请求的服务器。第一次请求时,根据该客户端的IP算出一个HASH值,将请求分配到集群中的某一台服务器上。后面该客户端的所有请求,都将通过HASH算法,找到之前处理这台客户端请求的服务器,然后将请求交给它来处理。

1> 轮循

http { 
# ... 省略其它配置 
upstream backserver { 
    server 192.168.0.100:8080; 
    server 192.168.0.101:8080; 
    server example.com:8080; 
} 
server { 
    listen 80; 
    location / { 
       proxy_pass http://tomcats; 
    } 
} 
# ... 省略其它配置 
}
  • proxy_pass http://tomcats:表示将所有请求转发到tomcats服务器组中配置的某一台服务器上。
  • upstream模块:配置反向代理服务器组,Nginx会根据配置,将请求分发给组里的某一台服务器。tomcats是服务器组的名称。
  • upstream模块下的server指令:配置处理请求的服务器IP或域名,端口可选,不配置默认使用80端口。通过上面的配置,Nginx默认将请求依次分配给100,101,102来处理,可以通过修改下面这些参数来改变默认的分配策略:
    • weight
      默认为1,将请求平均分配给每台server

      upstream backserver {
          server 192.168.0.100:8080 weight=2;  # 2/6次
          server 192.168.0.101:8080 weight=3;  # 3/6次
          server 192.168.0.102:8080 weight=1;  # 1/6次
      }

      上例配置,表示6次请求中,100分配2次,101分配3次,102分配1次

    • max_fails
      默认为1。某台Server允许请求失败的次数,超过最大次数后,在fail_timeout时间内,新的请求将不会分配给这台机器。如果设置为0,Nginx会将这台Server置为永久无效状态,然后将请求发给定义了proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, and memcached_next_upstream指令来处理这次错误的请求。
    • fail_timeout
      默认为10秒。某台Server达到max_fails次失败请求后,在fail_timeout期间内,nginx会认为这台Server暂时不可用,不会将请求分配给它

      upstream backserver {
          server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15;
          server 192.168.0.101:8080 weight=3;
          server 192.168.0.102:8080 weight=1;
      }

      192.168.0.100这台机器,如果有3次请求失败,nginx在15秒内,不会将新的请求分配给它。

    • backup
      备份机,所有服务器挂了之后才会生效

      upstream backserver {
          server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15;
          server 192.168.0.101:8080 weight=3;
      
          server 192.168.0.102:8080 backup;
      }

      在100和101都挂了之前,102为不可用状态,不会将请求分配给它。只有当100和101都挂了,102才会被启用。

    • down
      标识某一台server不可用。可能能通过某些参数动态的激活它吧,要不真没啥用。

      upstream backserver {
          server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15;
      
          server 192.168.0.101:8080 down;
      
          server 192.168.0.102:8080 backup;
      }

      表示101这台Server为无效状态,不会将请求分配给它。

    • max_conns
      限制分配给某台Server处理的最大连接数量,超过这个数量,将不会分配新的连接给它。默认为0,表示不限制。注意:1.5.9之后的版本才有这个配置

      upstream tomcats {
          server 192.168.0.100:8080 max_conns=1000;
      }

      表示最多给100这台Server分配1000个请求,如果这台Server正在处理1000个请求,nginx将不会分配新的请求给到它。假如有一个请求处理完了,还剩下999个请求在处理,这时nginx也会将新的请求分配给它。

    • resolve
      将server指令配置的域名,指定域名解析服务器。需要在http模块下配置resolver指令,指定域名解析服务

      http {
          resolver 10.0.0.1;
      
          upstream u {
              zone ...;
              ...
              server example.com resolve;
          }
      }

      表示example.com域名,由10.0.0.1服务器来负责解析。
      upstream模块server指令的其它参数和详细配置说明,请参考官方文档

      2> IP Hash

      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

    • upstream backserver { 
      
      ip_hash; 
      
      server 192.168.0.14:88; 
      
      server 192.168.0.15:80; 
      
      }

二、第三方负载策略

1> fair

根据服务器的响应时间来分配请求,响应时间短的优先分配,即负载压力小的优先会分配。

由于fair模块是第三方提供的,所以在编译nginx源码的时候,需要将fair添加到nginx模块中。

假设我的nginx是通过源码安装的,安装在/opt/nginx目录下,而且安装时没有添加fair模块

1> 下载fair模块源码
下载地址:https://github.com/xyang0917/nginx-upstream-fair

cd /opt
wget https://github.com/xyang0917/nginx-upstream-fair/archive/master.zip
unzip master.zip

解压后的目录名为:nginx-upstream-fair-master

2> 重新编译nginx,将fair模块添加到编译参数
我的nginx源码目录在/opt/nginx-1.10.0

cd /opt/nginx-nginx-1.10.0
./configure --prefix=/opt/nginx --add-module=/opt/nginx-upstream-fair-master
make

注意:不要执行make install,这样会覆盖之前nginx的配置
3> 将新编译的nginx可执行程序拷贝到/opt/nginx/sbin/目录下,覆盖之前安装的nginx
编译后的nginx执行程序,放在nginx源码的objs目录下

ps -aux | grep nginx
kill -9 nginx进程ID  # 停止nginx服务
cp /opt/nginx-1.10.0/objs/nginx /opt/nginx/sbin/  # 覆盖旧的nginx
nginx # 启动服务

配置使用fair负载策略模块:

upstream backserver {
    fair;
    server 192.168.0.100:8080;
    server 192.168.0.101:8080;
    server 192.168.0.102:8080;
}

由于采用fair负载策略,配置weigth参数改变负载权重将无效。

2> url_hash

按请求url的hash结果来分配请求,使每个url定向到同一个后端服务器,服务器做缓存时比较有效。

1.7.2版本以后,url_hash模块已经集成到了nginx源码当中,不需要单独安装。之前的版本仍需要单独安装,下载地址:https://github.com/evanmiller/nginx_upstream_hash
安装方法和fair模块一样,先下载url_hash源码,然后重新编译nginx源码,将url_hash模块添加到编译配置参数当中,最后将编译后生成的nginx二进制文件替换之前安装的nginx二进制文件即可。

upstream backserver { 
    server 192.168.0.100:8080; 
    server 192.168.0.101:8080; 
    server 192.168.0.102:8080; 
    hash $request_uri; 
}

Nginx性能优化

优化nginx包括两方面:

1.是自己重写nginx代码(比如tengine)、本身nginx的代码已经足够优秀,如果不是每秒几千的请求,就忽略这个部分吧;

2.另一个就是和优化nginx的配置,这是中小型网站可以重点优化的部分。

nginx的配置文件是一种声明式定义,控制nginx的每一个细节。

所谓负载调优,就是提高单台机器处理效率,降低单台机器的负载。

为了提高单台机器的处理效率,cpu的处理速度是足够快的,我们能解决的就是降低磁盘I/O、网络I/O,减少内存使用。

降低单台机器的负载我们能做的就是负载均衡,把流量打到多台机器处理。

nginx推荐优化内容:

1.open files数量优化
ulimit -a查看系统参数
其中
open files (-n) 1024
表示系统同时最多能打开的文件数,linux下的所有设备都可以认为是文件,包括网络连接,如果同时超过1024个连接,那么nginx的日志就会报“24: Too many open files”

多以优化的第一步就是设置open files为ulimit

修改/etc/profile,增加
ulimit -n 65535
2.Worker Processes数量优化
通常来说设置一个cpu核心对应一个worker processer,最多不超过4个,提高worker process的值是为了提高计算能力,但一般在越到cpu瓶颈前,你会遇到别的瓶颈(如网络问题)。

只有当你要处理大量静态文件的磁盘I/O时,worker进程是单线程的,所以这个读取文件的阻塞IO会降低CPU的处理速度,这是可以增加worker进程数量,其它情况是不需要的。
3.worker进程连接数优化(Worker Connections)
默认情况下这个值是worker_connections 1024,也就是说考虑到keep-alive超时65秒,每个浏览器平均消耗两个链接(chrome会同时打开多个连接来提到加载速度)。

那么默认情况下nginx平均每秒能处理1024/65/2=8,那么8*86440=64w,差不多相当于每天有60万ip。

多以普通网站默认值就可以了,如果你的流量一直提升,可以考虑增加这个值为2048或者更高。
3. CPU Affinity
用来设置worker进程使用哪个cpu核心处理请求并且一直使用这个cpu核心。如果你不知道cpu调度,最好别碰这个,操作系统比你更懂如何调度。
4. Keep Alive
Keep alive 没有数据传输的情况下保持客户端和服务端的连接,也就是保持空连接一段时间,避免重现建立链接的时间消耗。nginx处理空连接的效率非常高,1万个空连接大约消耗2.5M内存。如果流量非常大的网站,减少建立连接的时间开销是非常客观的。keep alive的值设置在10-20s之间比较合理。
5. tcp_nodelay 和 tcp_nopush优化
这两个指令影响nginx的底层网络,它们决定操作系统如何处理网络层buffer和什么时候把buffer内容刷新给终端用户。如果你不懂,就可以保持这两个指令默认不变,对nginx性能影响不明显。
6. access日志优化
默认情况下,access日志会记录所有请求到日志文件,写操作会增加IO操作,如果不需要统计信息,可以使用百度统计或者cnzz统计,完全可以关闭日志,来减少磁盘写,或者写入内存文件,提高IO效率。
7. Error日志优化
错误日志会记录运行中的错误,如果设置的太低,会记录的信息太多,会产生大量IO,推荐设置为warn,这样可以记录大部分信息,而不会有太多IO
8. Open File Cache
nginx会读文件系统的许多文件,如果这些文件的描述符能够缓存起来,那么会提高处理效率。详见http://wiki.nginx.org/HttpCoreModule#open_file_cache
9. Buffers size优化
buffer的大小是你需要调优最重要参数。如果buffer size太小就会到导致nginx使用临时文件存储response,这会引起磁盘读写IO,流量越大问题越明显。

client_body_buffer_size 处理客户端请求体buffer大小。用来处理POST提交数据,上传文件等。client_body_buffer_size 需要足够大以容纳如果需要上传POST数据。

fastcgi_buffers,proxy_buffers 处理后端响应。如果这个buffer不够大,同样会引起磁盘都系IO。需要注意的是它们有一个上限值,这个上限值受 fastcgi_max_temp_file_size 、 proxy_max_temp_file_size控制。
10.磁盘IO
如果能把数据全放到内存,不使用磁盘就可以完全去掉磁盘IO。 默认情况下操作系统也会缓存频繁访问的数据以降低IO。所以预算足够的情况加,加大内存。
11.网络IO
假设我们没有了磁盘IO,所有数据都在内存,那么我们的读IO大概有3-6gbps。这种情况下,如果你网络差,一样会很慢。所以尽可能提高网络带宽,压缩传输数据。

网络带宽买你能买的起的最大带宽,nginx的gzip模块可以用来压缩传输数据,通常gzip_comp_level 设为 4-5,再高就是浪费cpu了。同时也可以采用css,js压缩技术,当然这些技术就与nginx优化无关了。。
绝招
如果你还想提高nginx处理能力,只能祭出大杀器了。别优化了,加机器吧。一点点优化是没有用的,不如扩展机器来的快些。

redis持久化存储

redis支持两种方式的持久化,可以单独使用或者结合起来使用
第一种:RDB方式,redis默认的持久化方式,

第二种:AOF方式,需要手动修改配置。下面我们来看一下两种持久化方式以及持久化中所注意的一些问题。

持久化之RDB

rdb方式的持久化是通过快照完成的,当符合一定条件时redis会自动将内存中的所有数据执行快照操作并存储到硬盘上。默认存储在dump.rdb文件中(文件名在配置文件中dbfilename),默认打开可以到启动的目录去查看,注意: dump.rdb是在哪儿启动redis,就会在哪儿生成rdb文件。

  • dump.rdb
    [root@momo1 ~]# cd /usr/local/redis/
    [root@momo1 redis]# ll
    总用量 156
    -rw-rw-r--. 1 root root 34339 12月 18 23:19 00-RELEASENOTES
    -rw-rw-r--. 1 root root 53 12月 18 23:19 BUGS
    -rw-rw-r--. 1 root root 1805 12月 18 23:19 CONTRIBUTING
    -rw-rw-r--. 1 root root 1487 12月 18 23:19 COPYING
    drwxrwxr-x. 6 root root 4096 4月 27 19:40 deps
    -rw-r--r--. 1 root root 36 4月 29 01:20 dump.rdb ##dump.rdb
    -rw-rw-r--. 1 root root 11 12月 18 23:19 INSTALL
    -rw-rw-r--. 1 root root 151 12月 18 23:19 Makefile
    -rw-rw-r--. 1 root root 4223 12月 18 23:19 MANIFESTO
    -rw-rw-r--. 1 root root 5201 12月 18 23:19 README
    -rw-rw-r--. 1 root root 41561 4月 27 19:53 redis.conf
    -rwxrwxr-x. 1 root root 271 12月 18 23:19 runtest
    -rwxrwxr-x. 1 root root 280 12月 18 23:19 runtest-cluster
    -rwxrwxr-x. 1 root root 281 12月 18 23:19 runtest-sentinel
    -rw-rw-r--. 1 root root 7113 4月 29 00:26 sentinel.conf
    drwxrwxr-x. 2 root root 4096 4月 27 19:41 src
    drwxrwxr-x. 10 root root 4096 12月 18 23:19 tests
    drwxrwxr-x. 5 root root 4096 12月 18 23:19 utils
  1. redis进行快照的时机(在配置文件redis.conf中)
    1. save 900 1:表示900秒内至少一个键被更改则进行快照。
    2. save 300 10
    3. save 60 10000
  2. redis实现快照的过程
    1. redis使用fork函数复制一份当前进程的副本(子进程)
    2. 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件
    3. 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。
  3. 手动执行save或者bgsave命令让redis执行快照
    1. save是由主进程进行快照操作,会阻塞其它请求。
    2. bgsave是由redis执行fork函数复制出一个子进程来进行快照操作。
  4. 文件恢复:redis-check-dump
    [root@iZ94r8hgrjcZ /]# redis-check-dump dump.rdb 
    ==== Processed 5 valid opcodes (in 45 bytes) ===================================
    CRC64 checksum is OK
  • rdb的优缺点
    优点:由于存储的有数据快照文件,恢复数据很方便。
    缺点:会丢失最后一次快照以后更改的所有数据。
  • 注意
  1. redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的
  2. 我们可以通过定时备份RDB文件来实现redis数据库的备份。
  3. RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。
  • 示例代码:
    127.0.0.1:6379> set a 123
    OK
    127.0.0.1:6379> set b 456
    OK
    127.0.0.1:6379> keys *
    1) "b"
    2) "a"
    127.0.0.1:6379> shutdown
    not connected> exit
    ###注意此时有值,关掉退出然后我们切换一下目录后再启动,就会是一个新的rdb文件,无值
    
    [root@momo1 redis]# cd /home/up/
    [root@momo1 up]# redis-server /etc/redis.conf 
    [root@momo1 up]# redis-cli 
    127.0.0.1:6379> keys *
    (empty list or set)
    127.0.0.1:6379> shutdown
    not connected> exit
    [root@momo1 up]# ll
    总用量 1348
    -rw-r--r--. 1 root root 18 4月 29 04:04 dump.rdb

持久化之AOF

aof方式的持久化是通过日志文件的方式。默认情况下redis没有开启aof,可以通过参数appendonly参数开启。appendonly yes
aof文件的保存位置和rdb文件的位置相同,都是dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof

appendonly.aofappendonly.aof
aof同步的时机aof同步的时机
  1. redis写命令同步的时机
    1. appendfsync always 每次都会执行
    2. appendfsync everysec 默认 每秒执行一次同步操作(推荐,默认)
    3. appendfsync no不主动进行同步,由操作系统来做,30秒一次
  2. aof日志文件重写
    1. auto-aof-rewrite-percentage 100(当目前aof文件大小超过上一次重写时的aof文件大小的百分之多少时会再次进行重写,如果之前没有重写,则以启动时的aof文件大小为依据)
    2. auto-aof-rewrite-min-size 64mb
  3. 手动执行bgrewriteaof进行重写

    重写的过程只和内存中的数据有关,和之前的aof文件无关。即针对数据库中当前数据进行重新整理成redis语句

  4. 文件恢复:redis-check-aof
  • 示例代码:
    ## 在rdb是持久化下游三个keys
    [root@momo1 redis]# redis-cli
    127.0.0.1:6379> keys *
    1) "d"
    2) "a"
    3) "b"
    
    ## 
    [root@momo1 redis]# vim redis.conf #修改appendonly yes
    [root@momo1 redis]# redis-server ./redis.conf 
    [root@momo1 redis]# redis-cli
    127.0.0.1:6379> keys *
    (empty list or set)

动态切换redis持久方式

RDB 切换到 AOF支持Redis 2.2及以上

  • 问题: 在很多情况下,默认使用了rdb持久化方式,如果我们再开启aof持久化方式,就会发现一个问题 : 原先的redis数据丢失了!
  • 主要原因: redis的aof持久化方式是最安全的,如果开启aof之后,redis会优先选择aof的方式,而appendonly.aof文件此时还是空文件于是之前的数据就丢失了。
  • 解决办法: 使用config命令,首先动态修改配置,然后再修改配置文件!
    1. cinfig set appendonly yes
    2. config set save “”(可选,如果开启了aof可以选择关闭rdb)
  • 总结:
  1. 当redis启动时,如果rdb持久化和aof持久化都打开了,那么程序会优先使用aof方式来恢复数据集,因为aof方式所保存的数据通常是最完整的。如果aof文件丢失了,则启动之后数据库内容为空。
  2. 如果想把正在运行的redis数据库,从RDB切换到AOF,先使用动态切换方式,再修改配置文件,重启数据库。(不能自己修改配置文件,重启数据库,否则数据库中数据就为空了。)
  3. 如果我们失误操作,没有动态切换数据为空了,我们应该尽快手动kill掉redis进程,然后删掉aof备份文件改掉配置后重新动态切换。
  • 示例代码:动态切换
    127.0.0.1:6379> config set appendonly yes
    OK
    127.0.0.1:6379> mget a b d
    1) "123"
    2) "123"
    3) "999"
    
    ####然后我们来看一下appendonly.aof文件内容
    [root@momo1 redis]# vim appendonly.aof 
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    SET
    $1
    d ##d的值
    $3 ##长度为3
    999 ##值为999
    *3
    $3
    SET
    $1
    b
    $3
    123
    *3
    $3
    SET
    $1
    a
    $3
    123
  • 示例代码:如果我们失误操作,没有动态切换数据为空了
    [root@momo1 redis]# vim redis.conf #修改appendonly yes此时没有动态切换
    [root@momo1 redis]# redis-server ./redis.conf ##启动
    [root@momo1 redis]# redis-cli ##此时有数据
    127.0.0.1:6379> keys *
    (empty list or set)
    
    [root@momo1 redis]# ps -ef|grep redis ##重开一个端口kill进程
    root 6399 1 0 04:20 ? 00:00:00 redis-server *:6379 
    root 6402 5794 0 04:20 pts/2 00:00:00 redis-cli
    root 6413 6113 0 04:21 pts/3 00:00:00 grep redis
    [root@momo1 redis]# kill -9 6399 
    [root@momo1 redis]# rm -rf appendonly.aof ##删掉appendonly.aof
    [root@momo1 redis]# vim redis.conf ##再次改回no
    [root@momo1 redis]# redis-server ./redis.conf ##启动
    [root@momo1 redis]# redis-cli
    127.0.0.1:6379> keys * ##数据还在,万幸
    1) "d"
    2) "b"
    3) "a"

config命令

  • 1、使用config set可以动态设置参数信息,服务器重启之后就失效了。
    config set appendonly yes
    config set save "90 1 30 10 60 100"
  • 2、使用config get可以查看所有可以使用config set命令设置的参数
    127.0.0.1:6379> config get * ##这里我省略了很多
     1) "dbfilename" ##rdb存储文件
     2) "dump.rdb"
     9) "logfile" ##日志文件
     10) "" ##可重新配置
     11) "pidfile" ##pid文件
     12) "/var/run/redis.pid"
     13) "maxmemory"
     14) "0"
     15) "maxmemory-samples"
     16) "5"
     17) "timeout"
     18) "0"
     40) "3000"
     41) "lua-time-limit"
     42) "5000"
     43) "slowlog-log-slower-than" 
     44) "10000"
     45) "latency-monitor-threshold"
     46) "0"
     47) "slowlog-max-len"
     48) "128"
     49) "port" ##端口
     50) "6379"
     51) "tcp-backlog"
     52) "511"
     53) "databases" ##支持数据库
     54) "16"
     75) "cluster-node-timeout" ##集群的一些信息
     76) "15000"
     77) "cluster-migration-barrier"
     78) "1"
     79) "cluster-slave-validity-factor"
     80) "10"
     81) "repl-diskless-sync-delay"
     82) "5"
     83) "cluster-require-full-coverage"
     84) "yes"
     85) "no-appendfsync-on-rewrite"
     86) "no"
     87) "slave-serve-stale-data"
     88) "yes"
     89) "slave-read-only"
     90) "yes"
     91) "stop-writes-on-bgsave-error"
     92) "yes"
     93) "daemonize" ##是否开启daemonize
     94) "yes"
     95) "rdbcompression"
     96) "yes"
     97) "rdbchecksum"
     98) "yes"
     99) "activerehashing"
    100) "yes"
    101) "repl-disable-tcp-nodelay"
    102) "no"
    103) "repl-diskless-sync"
    104) "no"
    105) "aof-rewrite-incremental-fsync"
    106) "yes"
    107) "aof-load-truncated"
    108) "yes"
    109) "appendonly" ##
    110) "no"
    111) "dir" ##dir 目录,可修改
    112) "/root"
    117) "save" ##rdb持久化点
    118) "900 1 300 10 60 10000"
    119) "loglevel" ##日志级别
    120) "notice"
    124) "0"
    125) "slaveof"  ##主从
    129) "bind"  ##bind ip
    130) ""
  • 3、 使用config rewrite命令对启动 Redis 服务器时所指定的 redis.conf 文件进行改写(Redis 2.8 及以上版本才可以使用),主要是把使用
    config set动态指定的命令保存到配置文件中。
    config rewrite
  • 注意:

config rewrite命令对 redis.conf 文件的重写是原子性的, 并且是一致的:如果重写出错或重写期间服务器崩溃, 那么重写失败, 原有 redis.conf 文件不会被修改。 如果重写成功, 那么 redis.conf 文件为重写后的新文件

修改持久化、日志路径:

###########1、创建目录存储redis,博主在/data/创建redis目录来存放数据###
mkdir /data/redis 
kill -9 redis进程号或shutdown redis#关掉redis进程

###########2、修改日志文件、dump文件路径###########
logfile "/data/redis/redis.log"
dir /data/redis/

###########3、移动之前dump文件到新目录##########
mv /dump.rdb /data/redis/ #我这里之前dump文件在根目录下

###########4、启动redis、查看数据正常##########
[root@iZ94r8hgrjcZ usr]# service redis start ##启动redis
Starting Redis server...
[root@iZ94r8hgrjcZ redis]# pwd  
/data/redis
[root@iZ94r8hgrjcZ redis]# ll         ##以生成日志文件
total 8
-rw-r--r-- 1 root root   62 Apr 30 11:51 dump.rdb
-rw-r--r-- 1 root root 2206 Apr 30 13:04 redis.log
[root@iZ94r8hgrjcZ redis]# redis-cli  ##数据正常
127.0.0.1:6379> keys *
//......

////////##########如果还想测试aof#############
127.0.0.1:6379> config set appendonly yes ##1、动态修改持久化
OK

[root@iZ94r8hgrjcZ redis]# vim /etc/redis/6379.conf ##2、修改配置appendonly yes
[root@iZ94r8hgrjcZ redis]# ll   ##3、查看数据正常
total 12
-rw-r--r-- 1 root root  132 Apr 30 13:20 appendonly.aof
-rw-r--r-- 1 root root   62 Apr 30 11:51 dump.rdb
-rw-r--r-- 1 root root 2937 Apr 30 13:20 redis.log
参考:
http://redisbook.readthedocs.io/en/latest/internal/aof.html

https://lanjingling.github.io/2015/11/16/redis-chijiuhua/

MongoDB分片实验

下面来实战一下如何搭建高可用的mongodb集群:

首先确定各个组件的数量,mongos 3个, config server 3个,数据分3片 shard server 3个,每个shard 有一个副本一个仲裁也就是 3 * 2 = 6 个,总共需要部署15个实例。这些实例可以部署在独立机器也可以部署在一台机器,我们这里测试资源有限,只准备了 3台机器,在同一台机器只要端口不同就可以,看一下物理部署图:

5

实验环境:

Vmware 10 + 32位CentOS_6.5 + mongodb-3.2(32位)
3台虚拟机:192.168.192.132、192.168.192.133、192.168.192.134

1.创建如下目录:

/data/mongodbtest/mongos/log #mongos日志目录
/data/mongodbtest/config/data #config server数据目录
/data/mongodbtest/config/log #config server日志目录
/data/mongodbtest/shard1|2|3/data #分片1|2|3数据目录
/data/mongodbtest/shard1|2|3/log #分片1|2|3日志目录

2.启动配置服务器:

mongod --configsvr --dbpath /data/mongodbtest/config/data --port 21000 --logpath /data/mongodbtest/config/log/config.log --storageEngine=mmapv1 --fork

说明:测试机上加上这个参数【因为32位系统不支持默认的引擎】:--storageEngine=mmapv1

3. 启动mongos服务器:

mongos --configdb 192.168.192.132:21000,192.168.192.133:21000,192.168.192.134:21000 --port 20000 --logpath  /data/mongodbtest/mongos/log/mongos.log  --fork

4. 配置各分片的副本集:

mongod --shardsvr --replSet shard1 --port 22001 --dbpath /data/mongodbtest/shard1/data --storageEngine=mmapv1 --logpath /data/mongodbtest/shard1/log/shard1.log --fork --nojournal  --oplogSize 10
mongod --shardsvr --replSet shard2 --port 22002 --dbpath /data/mongodbtest/shard2/data --storageEngine=mmapv1 --logpath /data/mongodbtest/shard2/log/shard2.log --fork --nojournal  --oplogSize 10
mongod --shardsvr --replSet shard3 --port 22003 --dbpath /data/mongodbtest/shard3/data --storageEngine=mmapv1 --logpath /data/mongodbtest/shard3/log/shard3.log --fork --nojournal  --oplogSize 10
说明:测试机上加上这个参数【因为32位系统不支持默认的引擎】:--storageEngine=mmapv1

5. 登陆任意一台分片机配置副本集:[如:登陆192.168.192.132]

> mongo 127.0.0.1:22001

> use admin

> config = { _id:"shard1", members:[
{_id:0,host:"192.168.192.132:22001"},
{_id:1,host:"192.168.192.133:22001"},                      {_id:2,host:"192.168.192.134:22001",arbiterOnly:true}
]}

> rs.initiate(config);

> exit;

> mongo 127.0.0.1:22002

> use admin

> config = { _id:"shard2", members:[
{_id:0,host:"192.168.192.132:22002"},
{_id:1,host:"192.168.192.133:22002"},
{_id:2,host:"192.168.192.134:22002",arbiterOnly:true}
]}

> rs.initiate(config);

> exit;

> mongo 127.0.0.1:22003

> use admin

> config = { _id:"shard3", members:[
{_id:0,host:"192.168.192.132:22003"},{_id:1,host:"192.168.192.133:22003"},
{_id:2,host:"192.168.192.134:22003",arbiterOnly:true}
]}

> rs.initiate(config);

> exit;

6. 建立mongos与分片之间的联系:

mongo  127.0.0.1:20000

mongos > use admin

mongos> db.runCommand( { addshard : "shard1/192.168.192.132:22001,192.168.192.133:22001,192.168.192.134:22001"});

mongos> db.runCommand( { addshard : "shard2/192.168.192.132:22002,192.168.192.133:22002,192.168.192.134:22002"}); 

mongos > db.runCommand( { addshard : "shard3/192.168.192.132:22003,192.168.192.133:22003,192.168.192.134:22003"});   

mongos > db.runCommand( { listshards : 1 } );//查看分片列表

mongos > db.runCommand({enablesharding:"testdb"});//测试,设置要分片的库testdb

mongos > db.runCommand({shardcollection:"testdb.table1",key:{id:1}});//设置要分片的集合testdb.table1

7. 实践中遇到的问题:

mongos启动失败:

(1)报错:

Error initializing sharding system: ConfigServersInconsistent: hash from 192.168.192.132:21000: { chunks: "d41d8cd98f00b204e9800998ecf8427e", shards: "d41d8cd98f00b204e9800998ecf8427e", version: "34eb51f63387b033ac38ec27ab15aba4" } vs hash from 192.168.192.133:21000: {}

原因:

各配置服初始配置不一致,需要删除初始化配置文件重新启动,以保持多个配置服的一致性。

对策:

删除所有配置服务器data中的config.*,然后kill -9掉配置服启动进程重新启动,此时查看mongos.log发现报错消失,出现新的报错(2)

(2)报错:

Error initializing sharding system: DistributedClockSkewed: clock skew of the cluster 192.168.192.132:21000,192.168.192.133:21000,192.168.192.134:21000 is too far out of bounds to allow distributed locking.

原因:各配置服的linux时间不一致。

对策:使用ntpdate同步时间,使各配置服的linux时间保持一致:ntpdate  202.108.6.95

8.参考:

http://www.lanceyan.com/tech/arch/mongodb_shard1.html

MongoDB分片原理

在系统早期,数据量还小的时候不会引起太大的问题,但是随着数据量持续增多,后续迟早会出现一台机器硬件瓶颈问题的。而mongodb主打的就是海量数据架构,他不能解决海量数据怎么行!不行!“分片”就用这个来解决这个问题。

传统数据库怎么做海量数据读写?其实一句话概括:分而治之。上图看看就清楚了,如下 taobao岳旭强在infoq中提到的 架构图:

1

上图中有个TDDL,是taobao的一个数据访问层组件,他主要的作用是SQL解析、路由处理。根据应用的请求的功能解析当前访问的sql判断是在哪个业务数据库、哪个表访问查询并返回数据结果。具体如图:

2

说了这么多传统数据库的架构,那Nosql怎么去做到了这些呢?mysql要做到自动扩展需要加一个数据访问层用程序去扩展,数据库的增加、删除、备份还需要程序去控制。一但数据库的节点一多,要维护起来也是非常头疼的。不过mongodb所有的这一切通过他自己的内部机制就可以搞定!顿时石化了,这么牛X!还是上图看看mongodb通过哪些机制实现路由、分片:

3

从图中可以看到有四个组件:mongos、config server、shard、replica set。

mongos,数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。

config server,顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,这个可不能丢失!就算挂掉其中一台,只要还有存货, mongodb集群就不会挂掉。

shard,这就是传说中的分片了。上面提到一个机器就算能力再大也有天花板,就像军队打仗一样,一个人再厉害喝血瓶也拼不过对方的一个师。俗话说三个臭皮匠顶个诸葛亮,这个时候团队的力量就凸显出来了。在互联网也是这样,一台普通的机器做不了的多台机器来做,如下图:

4

一台机器的一个数据表 Collection1 存储了 1T 数据,压力太大了!在分给4个机器后,每个机器都是256G,则分摊了集中在一台机器的压力。也许有人问一台机器硬盘加大一点不就可以了,为什么要分给四台机器呢?不要光想到存储空间,实际运行的数据库还有硬盘的读写、网络的IO、CPU和内存的瓶颈。在mongodb集群只要设置好了分片规则,通过mongos操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。在生产环境中分片的片键可要好好设置,这个影响到了怎么把数据均匀分到多个分片机器上,不要出现其中一台机器分了1T,其他机器没有分到的情况,这样还不如不分片!

replica set,上两节已经详细讲过了这个东东,怎么这里又来凑热闹!其实上图4个分片如果没有 replica set 是个不完整架构,假设其中的一个分片挂掉那四分之一的数据就丢失了,所以在高可用性的分片架构还需要对于每一个分片构建 replica set 副本集保证分片的可靠性。生产环境通常是 2个副本 + 1个仲裁。

 

MongoDB副本集实验

一、实验环境:

Vmware 10 + 32位CentOS_6.5 + mongodb-3.2(32位)
1

二、下载并安装mongodb:

1.下载:
mongodb-3.2:百度云盘下载

也可以根据自己的环境,到官网上下载

2.安装:
分别创建:/usr/local/mongodb /data/db目录及文件/var/log/mongodb.log
解压mongodb-linux-i686-3.2.11.tgz,将其文件拷贝到/usr/local/mongodb/

3.加入环境变量:
vi /etc/profile
export PATH=/usr/local/mongodb/bin:$PATH
执行:source /etc/profile使其立即生效

三、搭建副本集:

介绍一下mongod启动涉及到的参数

--dbpath           数据文件路径

--logpath           日志文件路径

--port        端口号,默认是27017.我这里使用的也是这个端口号.

--replSet          复制集的名字,一个replica sets中的每个节点的这个参                       数都要用一个复制集名字,这里是mvbox.

--maxConns        最大连接数

--fork       后台运行

--logappend       日志文件循环使用,如果日志文件已满,那么新日志覆盖最久日志。
1.分别在1,2,3机器上启动mongod:

 mongod --dbpath=/data/db --logpath=/var/log/mongodb.log --port 27017 --replSet mvbox --maxConns=2000 --logappend --fork
说明:启动前如果已有mongod.lock先删除:rm -rf /data/db/mongod.lock

2.在1,2,3任意节点上登陆mongo:
> mongo
> config = { _id:"mvbox", members:[
{_id:0,host:"192.168.1.1:27017"},
{_id:1,host:"192.168.1.2:27017"},
{_id:2,host:"192.168.1.3:27017"}]
}
rs.initiate(config);

2


可以使用rs.status()查看集群状态,或者rs.isMaster()
3

四、同步验证:

1.在主节点的机器上,插入一条数据:

> use test;
> db.my.insert({'name':zrp,'age':28});

2.在副本集的节点上,先开启同步:

> rs.slaveOk(true);

3.查看副本集节点是否已同步数据:

> use test;
> db.my.find();

ok,数据同步成功,实验宣告成功!

五、变更节点:

1.变更192.168.1.3为仲裁节点: 

(1)在主节点上执行:
PRIMARY> rs.remove("192.168.1.3:27017");//先删除其副节点的角色
PRIMARY> rs.addArb("192.168.1.3:27017");//再追加其仲裁节点的角色
PRIMARY> rs.status();//查看状态
(2)登陆192.168.1.3的mongo查看其角色是否变化

2.更改节点优先级:

修改节点的优先级可以触发重新选举,这样可以人工指定主节点。
使用如下命令,在主节点登录,将192.168.1.3提升为Master。
rs.conf();
cfg=rs.conf();
cfg.members[0].priority=1
cfg.members[1].priority=1
cfg.members[2].priority=10
rs.reconfig(cfg);
需要注意的是,修改节点优先级需要登录Master节点运行。否则报错。
4

再次查看集群状态,可以看到192.168.1.3已经作为Master运行
5

 

LVS与Nginx作负载均衡对比

搭建负载均衡高可用环境相对简单,主要是要理解其中原理。此文描述了两种负载均衡器的优缺点,以便在实际的生产应用中,按需求取舍。
目前,在线上环境中应用较多的负载均衡器硬件有F5 BIG-IP,软件有LVS及Nginx,高可用软件有Heartbeat、Keepalived,成熟的架构有LVS+Keepalived、LVS+Heartbeat及Nginx+Keepalived。

两种负载均衡器的优缺点说明如下:

LVS的优点:

1、抗负载能力强、工作在第4层【传输层】仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的;无流量,同时保证了均衡器IO的性能不会受到大流量的影响;在我手里的 lvs,仅仅出过一次问题:在并发最高的一小段时间内均衡器出现丢包现象,据分析为网络问题,即网卡或linux2.4内核的承载能力已到上限,内存和 cpu方面基本无消耗;
2、工作稳定,自身有完整的双机热备方案,如LVS+Keepalived和LVS+Heartbeat;
3、应用工作在第4层,所以应用范围比较广,可以对所有应用做负载均衡;包括http、数据库、聊天室等;
4、配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率。

LVS的缺点:

 1、软件本身不支持正则处理,不能做动静分离,这就凸显了Nginx+Keepalived的优势。
 2、如果网站应用比较庞大,LVS+Keepalived就比较复杂了,特别是后面有Windows Server应用的机器,实施及配置还有维护过程就比较麻烦,相对而言,Nginx+Keepalived就简单多了。

Nginx的优点:

 1、工作在OSI第7层【应用层】,可以针对http应用做一些分流的策略。比如针对域名、目录结构。它的正则比较强大和灵活;相比之下lvs并不具备这样的功能,所以 nginx单凭这点可利用的场合就远多于lvs了;

 2、Nginx对网络的依赖非常小,理论上能ping通就就能进行负载功能,nginx就能连得通,nginx同时还能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;lvs就比较依赖于网络环境,这个也是它的优势所在;

 3、Nginx安装和配置比较简单,测试起来比较方便;因为它基本能把错误用日志打印出来。lvs的安装和配置、测试就要花比较长的时间了,因为同上所述,lvs对网络依赖比较大,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦得多。

 4、可以承担高的负载压力且稳定,一般能支撑超过几万次的并发量;

 5、Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点;

 6、Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP现在也是非常流行的web环境,大有和LAMP环境分庭抗礼之势,Nginx在处理静态页面、特别是抗高并发方面相对apache有优势;

 7、Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,有需求的朋友可以考虑用其作为反向代理加速器;

 8、nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。

Nginx的缺点:

 1、服务器的健康状态只支持通过端口来检测,不支持通过url来检测;

 2、Nginx对big request header的支持不是很好,如果client_header_buffer_size设置的比较小,就会返回400bad request页面;

 3、不支持session保持;

 4.nginx配置文件可调整,所以经常要去触碰触碰,触碰多了,人为出问题的几率也就会大。

建议

因为LVS忒牛了,配置也最麻烦了,而Nginx自己就有,而且配置超级简单。所以建议,如果网站访问量不是门户级别的用NGINX就OK了,到了门户级别在用LVS吧。

参考:https://yq.aliyun.com/articles/49042

高并发场景-01

问:现在有这样一个需求,在一秒中有3万的支付订单请求,有什么比较好的解决方案吗?

1. 首先要解决掉数据库的压力,3万qps对应的磁盘 iops 很大,不过现在好的 SSD 能提供很好的 iops, 比如这款: ARK | Intel® SSD DC P3700 Series (800GB, 2.5in PCIe 3.0, 20nm, MLC) 单盘 90000 IOPS,应该能撑住你的数据库,考虑到主备,以及你的sharding需求,3-9 台数据库机器,高内存,高CPU,SSD磁盘应该能抗住

2. 业务逻辑这一层: Java 系,用线程来抗并发的,如果业务逻辑不太复杂,那么基本能做到 100ms 内响应,那么 30000qps, 对应的是 3000并发线程,这部分设计的时候记得保持无状态,单台支撑 300-1000 并发没问题,加上一倍的冗余,那么 6~20 台业务型机器可以抗住。

3. 缓存层: 支付订单一般对缓存需求不高,但缓存层一般都会有,避免把查询压力压到数据库,简单两台缓存,或者缓存平行部署在业务型机器上都可以解决,具体看你的情况了。

4. 接入层: nginx 做LVS就可以了,记得 backlog 配大点就可以了, 3万qps, 假设单个请求的数据在 10KB 左右,那么是 300MB/s,如果是千兆机,每台4网卡,两内两外,加上冗余,我会部署4台入口机,如果是万兆机,两台做主备(心跳或者LVS)即可。

当然,魔鬼在细节,做好机器的监控,慢请求的监控,日志的汇聚与分析。然后逐步推进服务的 SOA 化来降低复杂度。留一台业务机打小流量来做线上测试。优化JVM运行参数,等等,要做的事情还很多。