当前位置: 首页 > news >正文

mysql架构

网站访问量日pv量级在1w以下
mysql主从
主从复制是Mysql内建的复制功能,它是构建高性能应用程序的基础,技术成熟,应用也很广泛。其原理就是通过将Mysql主库的sql语句复制到从库上,并重新执行一遍来实现的。复制过程中主库将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从库的更新。每次从库连接主库时,它会通知主库最后一次成功更新的位置。从库接收从那时起发生的任何更新。在进行主从复制时,所有命令都必须在主库上进行,从库不做操作。否则,会引起主从库之间的数据不同步,复制会中断。
错误及解决办法
问题: 从数据库无法同步
Slave_SQL_Running 值为 NO,或 Seconds_Bebind_Master 值为 Null
原因:

  1. 程序有可能在 slave 上进行了写操作
  2. 也有可能是 slave 机器重启后,事务回滚造成的
    解决方法一:
    msyql> stop slave;
    msyql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
    msyql> start slave;
    解决方法二:
    msyql> stop slave;
    #查看主服务器上当前的 bin-log 日志名和偏移量
    msyql> show master status;
    #获取到如下内容:
    +------------------+----------+--------------+------------------+
    | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +------------------+----------+--------------+------------------+
    | mysql-bin.000005 | 286 | | |
    +------------------+----------+--------------+------------------+
    #然后到从服务器上执行手动同步
    msyql> change master to
    ->master_host="192.168.10.1",
    ->master_user="user",
    ->master_password="123456",
    ->master_post=3306,
    ->master_log_file="mysql-bin.000005",
    ->master_log_pos=286;

msyql> start slave;
第二阶段
网站访问量日pv达到几万。此时单台机器已经有点负载,需要我们把web和db分开需要搭建memcached服务作为缓存。
memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性
本文通过 Tomcat Session Replication Cluster(tomcat自带)和tomcat结合memcat及第三方组件实现Tomcat Memcache Session Server高可用会话缓存服务;
实现的效果:
同一客户端访问业务网站,经过调度器负载调度到达后端,不管选择的是那个后端,session ID都不变,都保存在两台或多台的memcached缓存中(负载冗余);以保持持会话;

架构图:
Nginx+Tomcat+memcached高可用会话保持
说明:客户端请求时nginx通过负载调度算法将请求调度至某一后端服务器;tomcat 把会话通过组播的方式复制到集群各节点;所有节点共享会话;

Nginx+Tomcat+memcached高可用会话保持
说明:客户端请求时nginx通过负载调度算法将请求调度至某一后端服务器;并把session存储到两台memcached中;客户端刷新(不换浏览器)时,请求换成另一个后端服务器响应时session ID保持不变;

测试环境:
nginx: CentOS7 epel 安装nginx WAN:172.16.3.152 LAN:192.168.10.254
tomcat A: CentOS7 node1.san.com epel 安装 tomcat 7 openjdk-1.8.0 memcached(现实环境中单独服务器)
tomcat B: CentOS7 nodde2.san.com epel 安装 tomcat 7 openjdk-1.8.0 memcached 现实环境中单独服务器)
测试客户端ubuntu 16.04

cat /etc/hosts
172.16.3.152 www.san.com
二、安装配置集群
nginx安装
[root@nginx ~]# yum install epel-release -y
[root@nginx ~]# yum install nginx -y
nginx配置
在/etc/nginx/nginx.conf http段添加如下行

upstream tcsrvs {
    server 192.168.10.11:8080;
    server 192.168.10.12:8080;
    }

cat /etc/nginx/conf.d/san.com.conf

[root@nginx ~]# cat /etc/nginx/conf.d/san.com.conf
server {
listen 80;
server_name www.san.com;
location / {
proxy_pass http://tcsrvs;
}
}
Tomcat配置:
两台均需要安装

#yum install epel-release -y
#yum install java-1.8.0 java-1.8.0-openjdk-devel tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp -y
说明:也可以通过oracle官方下载jdk 下载tomcat 解压到指定目录并添加环境变量;一般企业推荐此种方式;为了快捷,我们用epel仓库中的稳定版本;

添加测试页
yum 安装的tomcat工作目录在/var/lib/tomcat/webapps 分别在node1与node2上,此目录下创建测试项目,title 分别叫Tomcat A与Tomcat B 颜色分别为green与red;以示区别;生产环境node1 与node2内容一致;这里为了测试区别node1与node2内容;

#mkdir -pv /var/lib/tomcat/webapps/test/{WEB-INF,META-INF,classes,lib}
#cat /var/lib/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
<html>
<head><title>Tomcat A</title></head>
<body>
<h1><font color="red">TomcatA.san.com</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("san.com","san.com"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
配置管理页密码
tomcat与管理程序安装好后配置访问密码
修改注释/etc/tomcat/tomcat-users.xml文件

<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/>
备份默认/etc/tomcat/server.xml文件

cd /etc/tomcat
cp server.xml server.xml_def
测试页访问
http://www.san.com/test 如图:出现Tomcat A
Nginx+Tomcat+memcached高可用会话保持
Ctrl+F5强制刷新 又出现Tomcat B
Nginx+Tomcat+memcached高可用会话保持

引发问题:如果是两台内容一样的配置,客户端访问刷新一下就换到另一个后端处理;类似通过session保留信息的服务(购买物车)如何保留?换句话说,如何保持会话不中断,无论请求被分配到那一个后端?

解决方案
1)会话sticky(粘性):分为source_ip 基于源ip和cookie
source_ip在不同的调度器上有不同的实现方式:
lvs:sh算法;
nginx:ip_hash或hash $request_uri consistent(一致性哈希算法)
haproxy: source

cookie:
nginx:hash 或 hash $cookie_name consistent;
haproxy:cookie

2)会话集群(session cluster):delta session manager
3)session server: redis(store),memcached(cache)

以下基于tomcat自带会话集群与memcached实现会话保持 功能;

三、Tomcat Session Replication Cluster配置

Tomcat Session Replication Cluster中文又叫 tomcat 会话复制集群,即会话通过组播方式复制到每一个后端tomcat节点;
可参考自带帮助文档:http://www.san.com/docs/cluster-howto.html
两台node1 node2节点/etc/hosts中添加如下:

#cat /etc/hosts
192.168.10.11 node1.san.com node1
192.168.10.12 node2.san.com node2
两台tomcat 节点sever.xml的Host字段中添加如下内容:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">

      <Manager className="org.apache.catalina.ha.session.DeltaManager"
               expireSessionsOnShutdown="false"
               notifyListenersOnReplication="true"/>

      <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        <Membership className="org.apache.catalina.tribes.membership.McastService"
                    address="228.10.0.4"
                    port="45564"
                    frequency="500"
                    dropTime="3000"/>
        <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                  address="auto"           <!--   如果没有/etc/hosts解析则需要本机ip   -->
                  port="4000"
                  autoBind="100"
                  selectorTimeout="5000"
                  maxThreads="6"/>

        <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
          <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
        </Sender>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
      </Channel>

      <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
             filter=""/>
      <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

      <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                tempDir="/tmp/war-temp/"
                deployDir="/tmp/war-deploy/"
                watchDir="/tmp/war-listen/"
                watchEnabled="false"/>

      <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
      <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
    </Cluster>

复制 /etc/tomcat/web.xml /var/lib/tomcat/webapps/test/WEB-INF/ 下并在web.xml的"<web-app >"字段下添加 "<distributable/>";
重启tomcat 并再次访问http://www.san.com/test 如图:
Nginx+Tomcat+memcached高可用会话保持
Ctrl + F5强制刷新如图:
Nginx+Tomcat+memcached高可用会话保持
可以可出会话得到保持,只要是从同一个客户端中请求,刷新或关闭重新打开(基于同一个浏览器) 只要会话没有过期,会话(session id) 无论来自那个后端,均是一样;

缺点:
tomcat自带支持会话集群(能过多播方式发送各节点);但有一个缺点;后端tomcat节点过多时效率低下,不适用大规模;

四、Tomcat Memcache Session Server高可用配置

原理说明:
客户端请求到达前端nginx调度器并分配到后端某tomcat节点时,tomcat会优先使用本机内存保存session,当一个请求结束后,tomcat会通过第三方组件(kryo,javolution,xstream,flexjson)把session序列化并发送到memcached节点上存放作备份,第二次请求时,如果本地有session就直接返回,第二次请求结束,把session修改后的信息更新到后端的memcached服务器,以这样的方式来保持本地的session与memcached上的session同步。当这个tomcat节点宕机时,那么用户的下一次请求就会被前端的负载均衡器路由到另一个tomcat节点上,而这个节点上并没有这个用户的session信息,这个节点就从memcached服务器上去读取session,并把session保存到本地的内存,当请求结束,session又被修改,再送回到memcached进行存放备份
当后端配置了多台memcached时,tomcat在更新session信息时会同时向多个memcached节点更新session,当一个memcached节点故障时,tomcat可以从选择一个正常工作的memcached节点读取session信息来发送给用户的浏览器,让其重置session信息,这样,memcached也达到了高可用的目的;
以下操作均在两台node上操作
还原默认配置文件

#cd /etc/tomcat/
#cp server.xml server.xml_cluster
#cp server.xml_def server.xml
#systemctl stop tomcat
安装memcached服务

#yum install memcached -y
#systemctl start memcached
memcache配置(默认即可,生产环境时需要加大内存与并发连接数)

cat /etc/sysconfig/memcached

PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""
两台/etc/tomcat/server.xml Host段中添加如下内容:

<Context path="/test" docBase="test" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="m1:192.168.10.11:11211,m2:192.168.10.12:11211"
failoverNodes="m1"
requestUriIgnorePattern=".*.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"/>
</Context>
说明:
添加两个冗余备份memcached节点分别叫m1,m2 failoverNodes="m1" 表示m1作为备份;当m2失败时连接;即使用m2;

安装对应版本组件

下载以下JAR包到tomcat库目录;
cd /usr/share/tomcat/lib
wget http://www.java2s.com/Code/JarDownload/javolution/javolution-5.5.1.jar.zip
#需要解压 unzip javolution-5.5.1.jar.zip
wget http://repo1.maven.org/maven2/net/spy/spymemcached/2.12.1/spymemcached-2.12.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/msm-javolution-serializer/2.1.1/msm-javolution-serializer-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager-tc7/2.1.1/memcached-session-manager-tc7-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager/2.1.1/memcached-session-manager-2.1.1.jar
注意:epel安装的tomcat 和openjdk版本如下:
openjdk: "1.8.0_161"
tomcat : "7.0.76"
以上第三方插件须和对应的版本是兼容的;如发现tomcat启动有问题;无法访问或如下类似错误

#tail -fn 100 /var/log/tomcat/catalina.xxxx.log
三月 23, 2018 4:12:52 下午 org.apache.catalina.core.StandardContext startInternal
严重: The session manager failed to start
org.apache.catalina.LifecycleException: Failed to start component [de.javakaffee.web.msm.MemcachedBackupSessionManager[/test]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5643)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
则表示第三方组件与tomcat不兼容!请重新下载版本;

测试:
浏览器访问http://www.san.com/test 如图:
Nginx+Tomcat+memcached高可用会话保持
Ctrl+F5强刷新 如图:
Nginx+Tomcat+memcached高可用会话保持
从测试上可以看出目前已经通过memcache存储session等缓存信息;并同步到两台memcache上;当前只使用m2节点;
总结:
通过nginx快速实现负载tomcat应用;引用session不可保持问题;通过自带的Tomcat Session Replication Cluster和结合memcached及第三方组件实现高可用会话缓存服务来保持会话;前者不适合大规模应用;
第三阶段
网站访问量日pv达到几十万。 可以增加更高的硬件配置 但是有瓶颈 考虑
所以,此阶段,我们会想到做mysql服务的集群,也就是说我们可以拿多台机器跑mysql。但,mysql的集群和web集群是不一样的,我们需要考虑数据的一致性,所以不能简单套用做web集群的方式(lvs,nginx代理)。可以做的架构是,mysql主从,一主多从。为了保证架构的健壮和数据完整,主只能是一个,从可以是多个。
还有一个问题,我们需要想到,就是在前端web层,我们的程序里面指定了mysql机器的ip,那么当mysql机器有多台时,程序里面如何去配置?discuz,其实有一个功能,支持mysql读写分离。即,我们可以拿多台机器跑mysql,其中一台写,其他多台是读,我们只需要把读和写的ip分别配置到程序中,程序自动会去区分机器。当然,如果不使用discuz自带的配置,我们还可以引用一个软件叫做 mysql-proxy, 使用他来实现读写分离。它支持一主多从的模式。
目前较为常见的mysql读写分离分为两种:

  1. 基于程序代码内部实现:在代码中对select操作分发到从库;其它操作由主库执行;这类方法也是目前生产环境应用最广泛,知名的如DISCUZ X2。优点是性能较好,因为在程序代码中实现,不需要增加额外的设备作为硬件开支。缺点是需要开发人员来实现,运维人员无从下手。
    2、 基于中间代理层实现:我们都知道代理一般是位于客户端和服务器之间,代理服务器接到客户端请求后通过判断然后转发到后端数据库。在这有两个代表性程序
    mysql-proxy:mysql-proxy为mysql开源项目,通过其自带的lua脚本进行sql判断,虽然是mysql官方产品,但是mysql官方并不建议将mysql-proxy用到生产环境。
    amoeba:由陈思儒开发,作者曾就职于阿里巴巴,现就职于盛大。该程序由java语言进行开发,目前只听说阿里巴巴将其用于生产环境。另外,此项目严重缺少维护和推广(作者有个官方博客,很多用户反馈的问题发现作者不理睬)

经过上述简单的比较,通过程序代码实现mysql读写分离自然是一个不错的选择。但是并不是所有的应用都适合在程序代码中实现读写分离,像大型SNS、B2C这类应用可以在代码中实现,因为这样对程序代码本身改动较小;像一些大型复杂的java应用,这种类型的应用在代码中实现对代码改动就较大了。所以,像这种应用一般就会考虑使用代理层来实现。
第四阶段
网站访问量日pv到几百万。之前的一主多从模式已经遇到瓶颈,因为当网站访问量变大,读数据库的量也会越来越大,我们需要多加一些从进来,但是从的数量增加到数十台时,由于主需要把bin-log全部分发到所有从上,那么这个过程本身就是一件很繁琐的事情,再加上频繁读取,势必会造成从上同步过来的数据有很大延迟。所以,我们可以做一个优化,把mysql原来的一主多从变为一主一从,然后从作为其他从的主,而前面的主只负责网站业务的写入,而后面的从不负责网站任何业务,只负责给其他从同步bin-log。这样还可以继续多叠加几个从库。

转载于:https://blog.51cto.com/13492528/2095496

相关文章:

  • 详解node.js中的可读流(Readable)和可写流(Writeable)
  • 一文看懂JeffDean等提出的ENAS到底好在哪?
  • MXNet 作者李沐:用深度学习做图像分类,教程+代码
  • Map集合、散列表、红黑树介绍
  • centos7.4系统的虚拟机网络配置教程
  • win10 php安装redis 扩展
  • 6、通过Appium Desktop 实现录制功能
  • 文件上传漏洞攻击
  • Micropython TPYBoard V10X拼插编程实践之定时器 代码不精通?...
  • 从抖音关闭评论,看服务治理的重要性
  • diango-团队介绍
  • ModeBusRtu概述
  • Project中最常用的注意点
  • 云时代,ERP选型莫走入低价、免费误区
  • 以太坊智能合约开发第六篇:truffle开发框架
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • avalon2.2的VM生成过程
  • idea + plantuml 画流程图
  • Java,console输出实时的转向GUI textbox
  • JavaScript函数式编程(一)
  • Java精华积累:初学者都应该搞懂的问题
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 搞机器学习要哪些技能
  • 坑!为什么View.startAnimation不起作用?
  • 力扣(LeetCode)965
  • 如何编写一个可升级的智能合约
  • 入门到放弃node系列之Hello Word篇
  • 我是如何设计 Upload 上传组件的
  • 在weex里面使用chart图表
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​flutter 代码混淆
  • ​一些不规范的GTID使用场景
  • # 数论-逆元
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $forceUpdate()函数
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (arch)linux 转换文件编码格式
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (六)vue-router+UI组件库
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)Neo4j下载安装以及初次使用
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • .chm格式文件如何阅读
  • .Net - 类的介绍
  • .net 提取注释生成API文档 帮助文档
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • /etc/shadow字段详解
  • @ 代码随想录算法训练营第8周(C语言)|Day57(动态规划)
  • @property python知乎_Python3基础之:property
  • [ 网络基础篇 ] MAP 迈普交换机常用命令详解