应用集成mycat,实现mycat的高可用与mysql的读写分离

前言

  开心一刻html

    一个女人自朋友圈写道:我家老公昨天和别人家的老婆出去旅游,迄今未归,我则被别人家的老公折腾了一天,好累哦!java

    圈子下面,评论无数,老公在下面评论到:能不能好好说话,我只不过陪女儿去毕业旅游行,而你负责在家留守,照顾三岁儿子,要不要写的这么刺激、让人浮想联翩的? 你是否是有点虎?mysql

诺维斯基:你往哪射了?git

周子瑜:我只是个娱乐明星,射箭我不是专业的...github

  路漫漫其修远兮,吾将上下而求索!web

  github:https://github.com/youzhibingspring

  码云(gitee):https://gitee.com/youzhibingsql

前情回顾

  经过前面的两篇博文:Mycat - 实现数据库的读写分离与高可用Mycat - 高可用与负载均衡实现,满满的干货!,咱们完成了以下图所示的组件部署数据库

组件结构图一mybatis

  SQL请求发给VIP,keepalived完成VIP的映射,并经过lvs将请求转发mycat,mycat根据SQL请求类型(DML SQL仍是SELECT SQL,亦或是强制指定db节点)将SQL分发到具体的db,完成由具体的数据库服务完成SQL的执行。

  但这还只是停留在数据库层面的部署,还没集成咱们的应用,没有实际意义,那么咱们如何集成咱们的应用,实现mycat的使命呢?

应用集成

  若是mycat搭建好了,进行应用集成很是简单,下面咱们一步一步来实现各类状况下的应用集成

  Mysql的读写分离与高可用

    数据库的读写分离能够在代码层面实现(可参考:spring集成mybatis实现mysql读写分离),但不推荐,代码的核心职责应该是业务的实现,若是将大篇的代码用来实现数据库的读写分离与高可用,那就背离了本意、南辕北辙了。

    计算机领域有句名言:“计算机科学领域的任何问题均可以经过增长一个间接的中间层来解决”。既然咱们的代码直接对接数据库很差实现数据库的读写分离与高可用,那就在中间新增一层中间件来实现,从而产生了数据库中间件(mycat只是实现之一),应用代码直接与数据库中间对接,由数据库中间件来实现数据库的读写分离与高可用。此时的组件结构图以下

组件结构图二

    具体的部署过程可参考:Mycat - 实现数据库的读写分离与高可用,此时应用如何集成了?其实很是简单,只须要将咱们的链接池配置中的数据库地址改为mycat的地址便可(将mycat当作数据库),具体以下

    application.yml

server:
  port: 8886
spring:
  #链接池配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://192.168.1.212:8066/TESTDB?useSSL=false&useUnicode=true&characterEncoding=utf-8
      username: root
      password: 123456
      initial-size: 1                     #链接池初始大小
      max-active: 20                      #链接池中最大的活跃链接数
      min-idle: 1                         #链接池中最小的活跃链接数
      max-wait: 60000                     #配置获取链接等待超时的时间
      pool-prepared-statements: true    #打开PSCache,而且指定每一个链接上PSCache的大小
      max-pool-prepared-statement-per-connection-size: 20
      validation-query: SELECT 1 FROM DUAL
      validation-query-timeout: 30000
      test-on-borrow: false             #是否在得到链接后检测其可用性
      test-on-return: false             #是否在链接放回链接池后检测其可用性
      test-while-idle: true             #是否在链接空闲一段时间后检测其可用性
#mybatis配置
mybatis:
  type-aliases-package: com.lee.mycat.entity
  #config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/*.xml
# pagehelper配置
pagehelper:
  helperDialect: mysql
  #分页合理化,pageNum<=0则查询第一页的记录;pageNum大于总页数,则查询最后一页的记录
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql
logging:
  level:
    com.lee.mycat.mapper: DEBUG
View Code

    UserWeb.java

package com.lee.mycat.web;

import com.lee.mycat.entity.User;
import com.lee.mycat.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/mycat")
public class UserWeb {

    @Autowired
    private IUserService userService;

    @RequestMapping("/getUserByNameFromMasterDb")
    public User getUserByNameFromMasterDb(String name) {
        return userService.getUserByNameFromMasterDb(name);
    }

    @RequestMapping("/getUserByNameFromSlaveDb")
    public User getUserByNameFromSlaveDb(String name) {
        return userService.getUserByNameFromSlaveDb(name);
    }

    @RequestMapping("/getUserByName")
    public User getUserByName(String name) {
        return userService.getUserByName(name);
    }

    @RequestMapping("/addUser")
    public Integer addUser(String name, Integer age) {
        return userService.insertUser(new User(name, age));
    }
}
View Code

    UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lee.mycat.mapper.UserMapper">

    <sql id="Base_Column_List">
        id,name,age
    </sql>

    <select id="getUserByNameFromMasterDb" resultType="User" parameterType="String">
        /*!mycat:db_type=master*/ SELECT
          <include refid="Base_Column_List" />
        FROM
            tbl_user
        WHERE name=#{name}
    </select>
    <select id="getUserByNameFromSlaveDb" resultType="User" parameterType="String">
        /*!mycat:db_type=slave*/ SELECT
          <include refid="Base_Column_List" />
        FROM
          tbl_user
        WHERE name=#{name}
    </select>
    <select id="getUserByName" resultType="User" parameterType="String">
        SELECT
          <include refid="Base_Column_List" />
        FROM
          tbl_user
        WHERE name=#{name}
    </select>
    <insert id="insertUser" parameterType="User"  useGeneratedKeys="true" keyProperty="id">
        INSERT INTO
          tbl_user(name, age)
        VALUES
          (#{name}, #{age})
    </insert>
</mapper>
View Code

    UserMapper.xml文件中会与咱们平时的写法有些许不一样,有时候须要明确指定强制走master仍是slave节点。具体细节可查看:spring-boot-mycat

    测试结果

      如上图所示,咱们一开始新增了一个用户:Jiraiye,其年龄是50,咱们手动改了mysql slave中Jiraiye的年龄为52是为了更直观的验证SQL请求最终走的是mysql master仍是mysql slave。从上图可知,通常的Select SQL走的是从库(DML SQL走主库这个就不用说了),如在mapper.xml中强制指定了db节点,那么就会在指定的mysql节点上来执行SQL。

      mysql的高可用就没进行测试了,应用实际上是感知不到的;mysql master宕机了,mycat会按咱们配置好的进行mysql db的切换,正常服务于咱们的应用。

  Mycat的高可用

    mysql的读写分离与高可用咱们是实现了,可mycat却存在高可用问题,一旦mycat宕机了,整个数据库层就至关于宕机了。可想而知,咱们须要实现mycat的高可用。

    mycat的高可用搭建过程可参考:Mycat - 高可用与负载均衡实现,满满的干货!,此时的组件结构图以下

组件结构图三

    应用工程改动很是小,只须要将数据库链接配置的url改为VIP便可,以下

jdbc:mysql://192.168.1.212:8066/TESTDB?useSSL=false&useUnicode=true&characterEncoding=utf-8
改为
jdbc:mysql://192.168.1.200:8066/TESTDB?useSSL=false&useUnicode=true&characterEncoding=utf-8

    测试结果

      mysql的读写分离依然正常工做,当mycat master宕机后,mycat slave接管任务,进行sql的转发,实现了mycat的高可用;期间出现了很是短期的异常提示,这是由于数据库链接池中都是212上的mycat链接,212如今已经宕机了,因此会出现一次异常提示,但链接池立马作出了反应,从新创建数据库链接,此时链接池中的链接都是链接的110。

  Mycat的负载均衡

    上述mycat的高可用中,绝大多数状况下,mycat slave一直处于等待状态,未提供任何服务,由于咱们的mycat master通常而言是不会宕机的。那有没有什么作法可让slave也处理SQL请求,而又和master互备实现mycat高可用呢?那就是实现Mycat的负载均衡,此时mycat不存在主从关系,而是它俩两两互备,此时的组件结构图就是组件结构图一。应用工程不用变,数据库链接仍是配置VIP。具体就不演示了,你们自行去实践便可。

总结

  一、数据库中间件能够下降应用代码的复杂性,让其专职于业务代码的实现,而数据库层面的工做交给数据库中间件;mycat只是数据库中间件的一种实现,却也是比较优秀的实现,她是开源的。

  二、并发量不高的状况下,实现mycat的高可用便可,无需实现Mycat的负载均衡;实现mycat的负载均衡须要更多的硬件成本和维护成本,却没有带来质变的收益,就性价比而言,不升反降。

  三、具体须要部署成什么组件结构,须要看具体的需求,不少状况下根本用不到mycat中间件,若是用到了mycat中间件,我的认为最好仍是实现mycat的高可用,至于需不须要实现mycat的负载均衡,就看具体的并发量了,这个也没个标准,就要结合实际状况来排查是否是mycat的负载太高了,若是确实是mycat负载太高,那么就有必要实现mycat的负载均衡来下降单个mycat的负载了。没有绝对的最优部署,只有当下最合适的部署。

参考

  《Mycat权威指南》

相关文章
相关标签/搜索