百万PV网站架构

背景知识

网站架构一般人为是根据客户需求分析的结果,准确定位网站目标人群,设定网站的整体架构,规划,设计网站栏目及其内容,指定网站开发流程顺序,最大限度地进行高效资源分析与管理的设计。

PV(Page View,页面访问量)即点击量,通常是衡量一个网络新闻频道或者网站甚至一条网络新闻的主要指标。PV对于网站,就像收视率之余电视,从某种程度上已经成为投资者衡量商业网站表现的最重要尺度。

对于PV的解释就是一个访问者在24小时内到底看了网站的几个页面。这里需要注意的是,同一个人浏览网站的同一个页面,不重复计算PV量,点100次也只能算1次。

实验概述

本案例设计才有四层模型,主要分为前端反向代理层,Web层,数据库缓存层和数据库层。前端代理层采用主备模式,Web层采用集群模式,数据库缓存层采用主备模式,数据库采用主从模式。
百万PV网站架构_第1张图片

实验环境

由于本人电脑配置的局限,所以只在四台虚拟机上演示,具体配置如下:
主机名
IP地址 系统版本 用途
master 192.168.58.140 CentOS 7 Nginx代理主机、redis缓存主机、MySQL数据主库
backup 192.168.58.132 CentOS 7 Nginx代理备机、redis缓存备机、MySQL数据从库
tomcat1 192.168.58.133 CentOS 7 Web服务
tomcat2 192.168.58.130 CentOS 7 Web服务

实验部署

主从Nginx服务器上部署nginx和keepalived

通过安装nginx源,然后直接使用yum仓库安装nginx和keepalived,其中keepalived主要是提供虚拟IP,实现nginx代理层的HA(High Available:高可用)。

在192.168.58.140的主机上操作:
[root@localhost ~]# rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/\
> nginx-release-centos-7-0.el7.ngx.noarch.rpm
#安装epel源
[root@localhost ~]# yum install -y keepalived nginx
#安装nginx和keepalived
[root@localhost ~]# vim /etc/keepalived/keepalived.conf 
#修改keepalived配置文件,配置如下图

百万PV网站架构_第2张图片

下面去创建/opt/shell/nginx.sh这个脚本文件

[root@localhost ~]# mkdir /opt/shell
[root@localhost ~]# vim /opt/shell/nginx.sh

#!/bin/bash
k=`ps -ef | grep keepalived | grep -v grep | wc -l`
if [ $k -gt 0 ];then
        /bin/systemctl start nginx.service
else
/bin/systemctl stop nginx.service
fi
#这个脚本含义就是如果keepalived已经启动,那么每两秒钟检查并启动一次nginx服务
[root@localhost ~]# chmod +x /opt/shell/nginx.sh 
[root@localhost ~]# systemctl start keepalived.service 
#在主服务器上启动keepalived服务

百万PV网站架构_第3张图片
百万PV网站架构_第4张图片
百万PV网站架构
在从服务器上操作

[root@localhost ~]# rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/\
> nginx-release-centos-7-0.el7.ngx.noarch.rpm
#安装epel源
[root@localhost ~]# yum install -y keepalived nginx
#安装nginx和keepalived
[root@localhost ~]# scp 192.168.58.140:/etc/keepalived/keepalived.conf /etc/keepalived/
#将主服务器上的keepalived配置文件复制到本机上,然后进行修改
[root@localhost ~]# mkdir /opt/shell/
[root@localhost ~]# scp 192.168.58.40:/opt/shell/nginx.sh /opt/shell/
#将主服务上nginx脚本复制到本机上,两个脚本都一样,功能也一样
[root@localhost ~]# systemctl start keepalived.service 
#在从服务器上启动keepalived服务

百万PV网站架构_第5张图片
百万PV网站架构_第6张图片
百万PV网站架构
测试,访问192.168.58.188,可以看到下图,访问到的是主服务器

[root@localhost ~]# systemctl stop keepalived.service    #将主服务器的keepalived关闭

百万PV网站架构_第7张图片
百万PV网站架构_第8张图片

部署Web主从服务器

首先在web主从服务器上安装tomcat服务器。下列步骤在两台web服务器上都要执行,由于tomcat是基于java开发的,所以要搭建java环境

[root@localhost ~]# tar xf apache-tomcat-8.5.23.tar.gz
#解压tomcat到当前目录
[root@localhost ~]# tar xf jdk-8u144-linux-x64.tar.gz
#解压jdk到当前目录
[root@localhost ~]# cp -r jdk1.8.0_144/ /usr/local/java
#将jdk包复制到指定目录中并改名为java
vim /etc/profile
#修改系统环境变量文件,在最后一行加入下面几句,目的是让系统能够识别java

export JAVA_HOME=/usr/local/java
export JRE_HOME=/usr/local/java/jre
export PATH=$PATH:/usr/local/java/bin
export CLASSPATH=./:/usr/local/java/lib:/usr/local/java/jre/lib

[root@localhost ~]# source /etc/profile
#使/etc/profile文件刷新生效

[root@localhost ~]# java -version #验证能够识别java命令
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)

[root@localhost ~]# cp -r apache-tomcat-8.5.23 /usr/local/tomcat8
#将tomcat复制到指定目录中,并重命名为tomcat8
[root@localhost ~]# ln -s /usr/local/tomcat8/bin/startup.sh /usr/bin/tomcatup
#将tomcat开启命令建立软链接并重命名为到/usr/bin/tomcatup
[root@localhost ~]# ln -s /usr/local/tomcat8/bin/shutdown.sh /usr/bin/tomcatdown
#将tomcat关闭命令建立软链接并重命名为到/usr/bin/tomcatdown

下面返回nginx主从代理服务器中配置upstream模块。

[root@localhost ~]# vim /etc/nginx/nginx.conf
.....省略
#gzip  on;
 upstream tomcat_pool {
                server 192.168.58.133:8080 weight=1;  #配置web服务器池,并启用轮询
                server 192.168.58.130:8080 weight=1;
                ip_hash;           
        }       
        server {
                listen 80;
                server_name 192.168.58.188;   #配置主机名,为虚拟IP 
                location / {
                        proxy_pass http://tomcat_pool;  #启用反向代理功能
                        proxy_set_header X-Real-IP $remote_addr;
                }       
        }       
    include /etc/nginx/conf.d/*.conf;
}   

重启两台nginx代理服务器的nginx服务,这里直接kill掉nginx进程,然后nginx又会重新开启,这是因为有keepalived服务的存在,每两秒会检查并启动nginx脚本,另外我们修改两台tomcat服务器的主页,从而验证轮询机制。

#主服务器
[root@localhost ~]# netstat -ntap | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      65181/nginx: master 
[root@localhost ~]# kill 65181
[root@localhost ~]# netstat -ntap | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      126988/nginx: maste 
#从服务器
[root@localhost ~]# netstat -ntap | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      4012/nginx: master  
[root@localhost ~]# kill 4012
[root@localhost ~]# netstat -ntap | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      74342/nginx: master 

[root@localhost ~]# cat /usr/local/tomcat8/webapps/ROOT/index.jsp 

server 133!!

[root@localhost ~]# tomcatup #启动tomcat [root@localhost ~]# cat /usr/local/tomcat8/webapps/ROOT/index.jsp

server 130!!

以上步骤tomcat中都需要做,唯一不同的就是首页内容不一样。效果如下,每刷新一次,分别访问两台tomcat服务器。
百万PV网站架构_第9张图片
(实验结果并不能轮询,只有在其中一台tomcat服务器down了后,才会去访问两外一台tomcat,等待大佬解决。)
百万PV网站架构_第10张图片

部署MySQL服务器

这里使用的是mariadb数据库,这个数据库是centos7中自带的,在两台mysql服务器上都要执行下面的操作

[root@localhost ~]# rpm -q mariadb
mariadb-5.5.56-2.el7.x86_64
[root@localhost ~]# systemctl start mariadb.service
#开启mariadb数据库服务
[root@localhost ~]# netstat -anpt | grep 3306
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      28092/mysqld  
[root@localhost ~]# mysql_secure_installation    #常规安全设置,会出现下列选项
Enter current password for root (enter for none):    #输入当前root密码,默认为空
Set root password? [Y/n]                             #是否输入密码 Y
New password:                                        #设置密码为abc123
Re-enter new password:                               #重新输入密码
Password updated successfully!
Reloading privilege tables..
 ... Success!
Remove anonymous users? [Y/n]                        #移除匿名用户
Disallow root login remotely? [Y/n]                  #不允许远程登录,选择n
Remove test database and access to it? [Y/n]         #移除test数据库并且访问它
Reload privilege tables now? [Y/n]                   #现在重新加载权限表 Y
Thanks for using MariaDB!                            #设置成功

导入实验网站的数据库sql文件

[root@localhost mnt]# mysql -u root -p  < slsaledb-2014-4-10.sql
Enter password: 

将用于实验的一个网上商场的源码解压到两台tomcat服务器的指定目录中

[root@localhost ~]# tar xf SLSaleSystem.tar.gz -C /usr/local/tomcat8/webapps/
[root@localhost mnt]# vim /usr/local/tomcat8/webapps/SLSaleSystem/WEB-INF/classes/applicationContext-mybatis.xml

修改tomcat中用于连接数据库的文件中的账号和密码

[root@localhost ~]# cd /usr/local/tomcat8/webapps/SLSaleSystem/WEB-INF/classes
[root@localhost classes]# vim jdbc.properties 
driverClassName=com.mysql.jdbc.Driver
url=jdbc\:mysql\://192.168.58.188\:3306/slsaledb?useUnicode\=true&characterEncoding\=UTF-8      
#虚拟IP
uname=root
#用户名
password=abc123
#密码
minIdle=10
maxIdle=50
initialSize=5
maxActive=100
maxWait=100
removeAbandonedTimeout=180
removeAbandoned=true

百万PV网站架构_第11张图片
到数据库中给上面的访问用户授权

[root@localhost mnt]# mysql -u root -p
Enter password: 
MariaDB [(none)]> GRANT all ON slsaledb.* TO 'root'@'%' IDENTIFIED BY 'abc123';
Query OK, 0 rows affected (0.04 sec)

MariaDB [(none)]> flush privileges; 
Query OK, 0 rows affected (0.00 sec)

网站测试,访问http://192.168.58.133:8080、http://192.168.58.130:8080、http://192.168.58.188测试是否都能访问,用户名为root,密码为abc123,测试成功。
百万PV网站架构_第12张图片

部署redis主从缓存服务器

Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换.

主从服务器都先安装redis软件包
[root@localhost ~]# yum install -y epel-release
[root@localhost ~]# yum install redis -y
[root@localhost ~]# vim /etc/redis.conf

bind 127.0.0.1  
#默认的bind 接口是127.0.0.1,也就是本地回环地址。这样的话,访问redis服务只能通过本机的客户端连接,这里需要修改为
bind 0.0.0.0

[root@localhost ~]# systemctl start redis.service  #启动服务
[root@localhost ~]# netstat -anpt | grep 6379      #查看对应端口已经打开
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      6495/redis-server 0 

[root@localhost ~]# redis-cli -h 192.168.58.140 -p 6379   #测试连接
192.168.58.140:6379> set name test                        #创建数据
OK
192.168.58.140:6379> get name
"test"

在从服务器中的/etc/redis.conf文件要多修改一个配置

[root@localhost ~]# vim /etc/redis.conf 
slaveof 192.168.58.140 6379
#指定主redis服务器的ip及端口,重启服务

配置tomcat访问目录

 
                
                
                
            

百万PV网站架构
以下测试缓存效果

[root@localhost mnt]# redis-cli -h 192.168.58.188 -p 6379
keyspace_hits:5                     #访问缓存命中率,说明web都是从redis中取数据,并没有直接连接数据库
keyspace_misses:0

配置redis集群主从切换,只在主服务器是操作

[root@localhost mnt]# redis-cli -h  192.168.58.140 info Replication
#获取当前服务器的角色
# Replication
role:master                          #没有设置主从,所以两台都是master
connected_slaves:0
master_repl_offset:5279
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:5278

百万PV网站架构_第13张图片

[root@localhost mnt]# vim /etc/redis-sentinel.conf #设置sentinel进程配置文件
protected-mode no
sentinel monitor mymaster 192.168.58.140 6379 1    #1表示1台从服务器,改为主服务器IP
sentinel down-after-milliseconds mymaster 30000    #3000毫秒内一直返回无效回复才会被 Sentinel 标记为主观下线
[root@localhost mnt]# service redis-sentinel start
#启动sentinel模式
[root@localhost mnt]# netstat -anpt | grep 26379
tcp        0      0 0.0.0.0:26379           0.0.0.0:*               LISTEN      36677/redis-sentine 
[root@localhost mnt]# redis-cli -h 192.168.58.140 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.58.140:6379,slaves=0,sentinels=1
#目前主服务器为192.168.58.140

验证主从切换

[root@localhost mnt]# redis-cli -h 192.168.58.140 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.58.140:6379,slaves=1,sentinels=1
#这时候也192.168.58.140是主服务器
[root@localhost mnt]# service redis stop
#停止主服务器的redis服务
[root@localhost mnt]# redis-cli -h 192.168.58.140 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.58.132:6379,slaves=1,sentinels=1
#可以看到这时候主服务器的ip为192.168.58.132,这里一旦主服务器切换后,原来的master再恢复后,也不会切换了,直到192.168.58.132宕机,才会再进行切换

验证主从同步

[root@localhost mnt]# redis-cli -h 192.168.58.132 -p 6379
192.168.58.132:6379> set user yx
OK
192.168.58.132:6379> get user
"yx"

[root@localhost mnt]# redis-cli -h 192.168.58.140 -p 6379
192.168.58.140:6379> get user
"yx"
#可以看到同步成功

部署数据库主从同步

修改主服务器配置文件

[root@localhost mnt]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
binlog-ignore-db=mysql,information_schema
character_set_server=utf8
log_bin=mysql_bin
server_id=1
log_slave_updates=true
sync_binlog=1  

[root@localhost mnt]# systemctl restart mariadb.service
[root@localhost mnt]# mysql -u root -p
Enter password: 
MariaDB [(none)]> grant replication slave on *.* to 'rep'@'192.168.58.%' identified by '123456';
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> show master status;
+------------------+----------+--------------+--------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB         |
+------------------+----------+--------------+--------------------------+
| mysql_bin.000001 |      472 |              | mysql,information_schema |
+------------------+----------+--------------+--------------------------+
1 row in set (0.00 sec)

在从服务器上配置

[root@localhost mnt]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server_id=2         #server_id主从不能一样
[root@localhost mnt]# systemctl restart mariadb.service
MariaDB [(none)]> change master to master_host='192.168.58.140',master_user='rep',master_password='123456',master_log_file='mysql_bin.000001',master_log_pos=245;
#给rep用户授予同步权限
MariaDB [(none)]> start slave;
MariaDB [(none)]> show slave status\G;
....省略
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

百万PV网站架构_第14张图片
以下图片说明网站能正常访问
百万PV网站架构_第15张图片
百万PV网站架构_第16张图片