44.大数据之旅——java分布式项目05

架构图


44.大数据之旅——java分布式项目05
单机Mysql存在的问题及解决办法
1.如果只有一台数据库服务器,存在什么问题?如何解决?
如果这台服务器宕机,在故障时间内无法对外提供数据库服务,但更严重的情况是数据的丢失。
解决的办法是:做主从复制。主从复制本质上是一种数据冗余策略,属于容灾系统。
引入主从复制架构,可以提高DB层的robust。此外,主从复制架构并且也是数据库读写分离的架构基础。

2.Master既要提供读服务,又要提供写服务,这种架构是否存在问题?
如果读写请求都交给Master来处理,则所有的负载压力都会集中到Master上,当Master节点超负荷时,极有可能宕机。
所以思路是想办法降低Master的负载,解决办法是:数据库读写分离。

Master节点只负责写请求,而Slave节点负责读请求。从而达到降低Master的负载压力的目的

读写分离,是一种业务类应用在解决读流量时,单机无无法承受的架构,学名scale out。注意:读写分离是假设在主从复制的基础上的。针对Mysql的读写分离,可以利用amoeba,mycat等技术来实现。

3.当读请求的量继续增大,已经超过一台机器的负载能力时,如何解决?
44.大数据之旅——java分布式项目05
解决办法:负载均衡
这个概念不是数据库独有的概念,是指在由一个集群提供服务时,怎么把请求分配到集群中的某个服务器,能够最小化延迟,最大化集群的利用率。

Mysql的主从复制


概念介绍
Mysql作为目前世界上使用最广泛的免费数据库,在实际的生产环境中,由单台Mysql作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面。

因此,一般来说都是通过 主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy)来提升数据库的并发负载能力这样的方案来进行部署与实施的。

主从复制原理说明
44.大数据之旅——java分布式项目05
Mysql默认是不开启主从复制的,我们可以通过配置使其生效。

1.在Master-mysql上开启二进制日志服务(默认是关闭的)。这个服务开启后,Master-mysql会将数据更改类操作(比如增、删、改)记录到Binary log日志里。

2.Slave-mysql 会开启两个线程,一个是I/O线程,一个是SQL线程。

3.从服务器I/O线程读取主服务器Binlog log的内容并将该数据拷贝到本地文件中,即中继日志(Relay log)。

4.SQL线程监听本地中继日志,执行记录的SQL语句,从而完成两个数据库的内容同步。

Linux下配置主从复制

实现步骤
0.准备两台虚拟机,为了便于后续操作,关闭虚拟机防火墙
执行:service iptables stop
或者也可以通过打开3306端口。

1.上传和解压Percona安装包

2.按如下顺序安装Percona组件服务:
①rpm -ivh Percona-Server-56-debuginfo-5.6.24-rel72.2.el6.x86_64.rpm
②rpm -ivh Percona-Server-shared-56-5.6.24-rel72.2.el6.x86_64.rpm
③rpm -ivh Percona-Server-client-56-5.6.24-rel72.2.el6.x86_64.rpm
④rpm -ivh Percona-Server-server-56-5.6.24-rel72.2.el6.x86_64.rpm

3.启动Mysql服务
执行:service mysql start

4.修改数据库初始密码
执行:mysqladmin -u root password “root”;

5.登录验证
执行:mysql -uroot -proot

6.为了后续外部节点访问当前数据库,需要放开外部访问权限
在mysql数据库下,执行:grant all on *.* to 'root'@'%' identified by 'root';
语法说明:
grant [权限] on [数据库名].[表名] to [‘用户名’]@[‘web 服务器的ip地址’] identified by [‘密码’];

配置Master节点
7.如果以上步骤都操作成功,则停掉mysql服务,开始配置mysql-master节点。
执行:service mysql stop

8.进入目录:cd /var/lib/mysql
44.大数据之旅——java分布式项目05

主从复制注意事项


44.大数据之旅——java分布式项目05

Mysql的读写分离与amoeba


44.大数据之旅——java分布式项目05

amoeba安装和配置


实现步骤:
1.关闭虚拟机防火墙(或者打开8066端口)
2.安装和配置jdk
①通过 tar -xvf jdk的jar包 安装JDK
②配置JDK的环境变量 vi /etc/profile
在尾行添加

#set java environment
JAVA_HOME=/home/software/jdk1.7
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME  PATH CLASSPATH

保存退出
③source /etc/profile 使更改的配置立即生效
④java -version 查看JDK版本信息。
3.上传和解压amoeba
4.进入conf目录,对dbServer.xml进行配置
配置示例:

<?xml version="1.0" encoding="gbk"?>
 
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
 
                <!-- 
                        Each dbServer needs to be configured into a Pool,
                        If you need to configure multiple dbServer with load balancing that can be simplified by the following configuration:
                         add attribute with name virtual = "true" in dbServer, but the configuration does not allow the element with name factoryConfig
                         such as 'multiPool' dbServer   
                -->
 
        <dbServer name="abstractServer" abstractive="true">
                <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
                        <property name="manager">${defaultManager}</property>
                        <property name="sendBufferSize">64</property>
                        <property name="receiveBufferSize">128</property>
 
                        <!-- mysql port -->
                        <property name="port">3306</property>
 
                        <!-- mysql schema -->
                        <property name="schema">test</property>
 
                        <!-- mysql user -->
                        <property name="user">root</property>
 
 
                        <property name="password">root</property>
 
                </factoryConfig>
 
                <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
                        <property name="maxActive">500</property>
                        <property name="maxIdle">500</property>
<property name="minIdle">10</property>
                        <property name="minEvictableIdleTimeMillis">600000</property>
                        <property name="timeBetweenEvictionRunsMillis">600000</property>
                        <property name="testOnBorrow">true</property>
                        <property name="testOnReturn">true</property>
                        <property name="testWhileIdle">true</property>
                </poolConfig>
        </dbServer>
 
        <dbServer name="server1"  parent="abstractServer">
                <factoryConfig>
                        <!-- mysql ip -->
                        <property name="ipAddress">192.168.234.231</property>
                </factoryConfig>
        </dbServer>
 
        <dbServer name="server2"  parent="abstractServer">
                <factoryConfig>
                        <!-- mysql ip -->
                        <property name="ipAddress">192.168.234.232</property>
                </factoryConfig>
        </dbServer>
 
        <dbServer name="multiPool" virtual="true">
                <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
                        <!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
                        <property name="loadbalance">1</property>
 
                        <!-- Separated by commas,such as: server1,server2,server1 -->
                        <property name="poolNames">server1,server2</property>
                </poolConfig>
        </dbServer>
 
</amoeba:dbServers>

5.针对amoeba.xml 进行配置
配置示例:

<?xml version="1.0" encoding="gbk"?>
 
<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">
 
        <proxy>
 
                <!-- service class must implements com.meidusa.amoeba.service.Service -->
                <service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager">
                        <!-- port -->
                        <property name="port">8066</property>
 
                        <!-- bind ipAddress -->
                        <!-- 
                        <property name="ipAddress">127.0.0.1</property>
                         -->
 
                        <property name="manager">${clientConnectioneManager}</property>
 
                        <property name="connectionFactory">
                                <bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory">
                                        <property name="sendBufferSize">128</property>
                                        <property name="receiveBufferSize">64</property>
                                </bean>
                        </property>
 
                        <property name="authenticator">
                                <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
 
                                        <property name="user">root</property>
 
                                        <property name="password">root</property>
 
                                        <property name="filter">
                                                <bean class="com.meidusa.amoeba.server.IPAccessController">
                                                        <property name="ipFile">${amoeba.home}/conf/access_list.conf</property>
                                                </bean>
                                        </property>
                                </bean>
                        </property>
 
                </service>
 
                <!-- server class must implements com.meidusa.amoeba.service.Service -->
                <service name="Amoeba Monitor Server" class="com.meidusa.amoeba.monitor.MonitorServer">
                        <!-- port -->
                        <!--  default value: random number
                        <property name="port">9066</property>
                        -->
                        <!-- bind ipAddress -->
                        <property name="ipAddress">127.0.0.1</property>
                        <property name="daemon">true</property>
                        <property name="manager">${clientConnectioneManager}</property>
                        <property name="connectionFactory">
                                <bean class="com.meidusa.amoeba.monitor.net.MonitorClientConnectionFactory"></bean>
                        </property>
 
                </service>
 
                <runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
                        <!-- proxy server net IO Read thread size -->
                        <property name="readThreadPoolSize">20</property>
 
                        <!-- proxy server client process thread size -->
                        <property name="clientSideThreadPoolSize">30</property>
 
                        <!-- mysql server data packet process thread size -->
                        <property name="serverSideThreadPoolSize">30</property>
 
                        <!-- per connection cache prepared statement size  -->
                        <property name="statementCacheSize">500</property>
 
                        <!-- query timeout( default: 60 second , TimeUnit:second) -->
                        <property name="queryTimeout">60</property>
                </runtime>
 
        </proxy>
 
        <!-- 
                Each ConnectionManager will start as thread
                manager responsible for the Connection IO read , Death Detection
        -->
        <connectionManagerList>
                <connectionManager name="clientConnectioneManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
                        <property name="subManagerClassName">com.meidusa.amoeba.net.ConnectionManager</property>
                        <!-- 
                          default value is avaliable Processors 
                        <property name="processors">5</property>
                         -->
                </connectionManager>
                <connectionManager name="defaultManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
                        <property name="subManagerClassName">com.meidusa.amoeba.net.AuthingableConnectionManager</property>
 
                        <!-- 
                          default value is avaliable Processors 
                        <property name="processors">5</property>
                         -->
                </connectionManager>
        </connectionManagerList>
 
                <!-- default using file loader -->
        <dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">
                <property name="configFile">${amoeba.home}/conf/dbServers.xml</property>
        </dbServerLoader>
 
        <queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
                <property name="ruleLoader">
                        <bean class="com.meidusa.amoeba.route.TableRuleFileLoader">
                                <property name="ruleFile">${amoeba.home}/conf/rule.xml</property>
                                <property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property>
                        </bean>
                </property>
                <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
                <property name="LRUMapSize">1500</property>
                <property name="defaultPool">server1</property>
 
 
                <property name="writePool">server1</property>
 
                <property name="readPool">server2</property>
 
                <property name="needParse">true</property>
        </queryRouter>
</amoeba:configuration>

6.进入amoeba的bin目录
执行:vim amoeba
然后针对这行数据进行更改:把128k变成256k。这是amoeba最小的java栈大小。128k太小,会导致启动报错。
44.大数据之旅——java分布式项目05

课后完成:和amoeba整合

实现步骤:

  1. 将京淘电商的数据库表,建立到mysql-master的数据库中的jtdb库中

  2. 京淘的数据库连接,更改为amoeba的代理连接。
    配置京淘后台系统的jdbc.properties文件

配置示例:

  1. 启动京淘,测试是否能正确访问

架构缓存的问题


存在的问题
对于电商网站,在购物节时,大家都来到商场上浏览商品,购买商品。并且在大多数情况下,用户浏览的商品会集中在某些热门商品上,比如某新款手机、电脑,某折扣服饰等。在这种情况下,某一商品的url会产生极大的访问量。

缓存机制
缓存是介于应用程序和物理数据源之间,作用是为了降低应用程序对物理数据源访问的频次,从而提高应用的运行性能。缓存内的数据是对物理数据源中数据的复制,应用程序在运行时从缓存读数据,在特定的时刻或事件被触发时,缓存会同步物理数据源的数据。

缓存机制的介质一般是内存,所以读写速度很快。目前也有用SSD固态硬盘做缓存介质的情况。

引入缓存机制后新的问题和挑战
1.缓存的与物理数据源的数据一致性问题。如果物理数据源的数据更新,但是缓存里的数据没更新,这时用户如果从缓存里读数据就是错误数据。
2.缓存数据的生命周期问题。即缓存里的某些数据不可能一直存放在缓存里,比如一些几乎不会被访问的数据、一些历史周期较长的数据存在缓存里,占用宝贵的内存资源。所以哪些缓存数据该定期进行清理、哪些缓存数据该保留,这不仅仅要通过代码,还要结合实际业务情况。
3.缓存里数据的落地问题(数据持久化)。
4.缓存服务器的单点故障问题。比如一个电商网站,如果只用一台服务器做缓存,如果这台缓存服务器挂掉,就会去数据库访问数据,此时极有可能带来缓存雪崩现象。
雪崩现象指的是:当缓存服务器重启或者大量缓存集中在某一个时间段失效,在失效阶段里,本来应该涌入缓存的大量访问请求,都涌入了后端系统(比如DB),在短时间内给服务器带来特别高的负载,这种现象称之为雪崩现象。雪崩最严重的后果是使服务器失去响应能力,甚至宕机。
5.主—从缓存架构的主节点失效检测问题,即需要有一个检测机制,能够检测到主节点的状态,一旦主节点宕机能够把从节点变成主节点继续对外提供服务。
……

上一篇 43.大数据之旅——java分布式项目04