MySQL -- 读写分离
读写分离架构客户端直连
Proxy
对比
客户端直连
少了一层Proxy转发,查询性能稍微好一点
整体架构简单,排查问题方便
需要了解后端部署细节,在出现主从切换、库迁移时,客户端有感知,需要调整数据库连接信息
一般伴随着一个负责管理后端的组件,例如ZooKeeper
Proxy – 发展趋势
对客户端友好,客户端不需要关注后端细节,但后端维护成本较高
Proxy也需要高可用架构,带Proxy的整体架构相对复杂
过期读由于主从延迟,主库上执行完一个更新事务后,立马在从库上执行查询,有可能读到刚刚的事务更新之前的状态
解决方案强制走主库
将查询请求做分类
必须要拿到最新结果的请求,强制将其发送到主库上
可以读到旧数据的请求,将其发到从库上
如果完全不能接受过期读,例如金融类业务,相当于放弃读写分离,所有的读写压力都在主库上
SLEEP
主库更新后,读从库之前先SLEEP一下,类似于SELECT SLEEP(1)
基于的假设:大多数主从延时在1秒内
卖家发布商品后,用Ajax直接把客户端输入的内容作为“新的商品”显示在页面上,而非真正的做数据库查询
等卖家再次刷新页面,其实主从 ...
MySQL -- 主从切换
一主多从
虚线箭头为主从关系,A和A'互为主从,B、C、D指向主库A
一主多从的设置,一般用于读写分离,主库负责所有的写入和一部分读,其它读请求由从库分担
主库故障切换A'成为新的主库,B、C、D指向主库A'
基于位点的切换B原先是A的从库,本地记录的也是A的位点,但相同的日志,A的位点与A'的位点是不同的
12345678-- 节点B设置为节点A'的从库CHANGE MASTER TOMASTER_HOST=$host_nameMASTER_PORT=$portMASTER_USER=$user_nameMASTER_PASSWORD=$passwordMASTER_LOG_FILE=$master_log_nameMASTER_LOG_POS=$master_log_pos
寻找位点
很难精确,只能大概获取一个位置
由于在切换过程中不能丢数据,在寻找位点的时候,总是找一个稍微往前的位点,跳过那些已经在B执行过的事务
常规步骤
等待新主库A'将所有relaylog全部执行完
在A'上执行SHOW MASTER STATUS,得到A ...
MySQL -- 从库并行复制
主从复制
第一个黑色箭头:客户端写入主库,第二个黑色箭头:从库上sql_thread执行relaylog,前者的并发度大于后者
在主库上,影响并发度的原因是锁,InnoDB支持行锁,对业务并发度的支持还算比较友好
如果在从库上采用单线程(MySQL 5.6之前)更新DATA的话,有可能导致从库应用relaylog不够快,造成主从延迟
多线程模型
coordinator就是原来的sql_thread,但不会再直接应用relaylog后更新DATA,只负责读取relaylog和分发事务
真正更新日志的是worker线程,数量由参数slave_parallel_workers控制
123456mysql> SHOW VARIABLES LIKE '%slave_parallel_workers%';+------------------------+-------+| Variable_name | Value |+------------------------+-------+| slave_parallel_workers | 4 |+-- ...
Java核心 -- final + finally + finalize
final
修饰类,代表不可以继承扩展
修饰变量,代表变量不可以修改
修饰方法,代表方法不可以重写
实践
推荐使用final关键字来明确表示代码的语义和逻辑意图
将方法或类声明为final,明确表示不允许重写或继承
使用final修饰参数或变量,能够避免意外赋值而导致的编程错误
final变量产生了某种程度的不可变(immutable)的效果,可以用于保护只读数据
现在JVM足够智能,_**final对性能的影响,在大部分情况下,都没有必要考虑**_,应用程序更应该关注的是语义
final != immutableJava目前没有原生的immutable支持
12345678// final只能约束strList这个引用不可以被赋值,但strList对象本身的行为是不受影响的final List<String> strList = new ArrayList<>();strList.add("Hello");strList.add("World");// since 9List<String> unmodifiabl ...
MySQL -- 主从复制的可靠性与可用性
Master-Master 主从切换
同步延时
主库A执行完成一个事务,写入binlog,记为T1
然后传给从库B,从库B接收该binlog,记为T2
从库B执行完成这个事务,记为T3
同步延时:T3-T1
同一个事务,在从库执行完成的时间和主库执行完成的时间之间的差值
SHOW SLAVE STATUS中的Seconds_Behind_Master
Seconds_Behind_Master
计算方法
每个事务的binlog里面都有一个时间字段,用于记录该binlog在主库上的写入时间
从库取出当前正在执行的事务的时间字段的值,计算它与当前系统时间点差值,得到Seconds_Behind_Master
即T3-T1
如果主库与从库的时间不一致,Seconds_Behind_Master会不会有误差?
一般不会
在从库连接到主库时,会通过SELECT UNIX_TIMESTAMP()获取当前主库的系统时间
如果从库发现当前主库的系统时间与自己的不一致,在计算Seconds_Behind_Master会自动扣除这部分差值
但建立连接后,主库或从库又修改了系统时间,依然会不准确
在网络 ...
MySQL -- 基于Docker搭建主从集群
目录结构12345678$ tree.├── master│ ├── data│ └── master.cnf└── slave ├── data └── slave.cnf
master.cnf12345678[mysqld]pid-file = /var/run/mysqld/mysqld.pidsocket = /var/run/mysqld/mysqld.sockdatadir = /var/lib/mysqlserver-id=1log-bin=master-bingtid_mode=onenforce_gtid_consistency=on
slave.cnf1234567891011[mysqld]pid-file = /var/run/mysqld/mysqld.pidsocket = /var/run/mysqld/mysqld.sockdatadir = /var/lib/mysqlserver-id=2log-bin=slave-binread-only=1relay_log=relay-binlog-slave ...
MySQL -- 主从复制的基本原理
主从切换
在状态1,客户端的读写都是直接访问节点A,节点B是节点A的从库
只是将节点A的更新都同步过来,在节点B本地执行,保持一致
在状态1,虽然节点B没有被直接访问,但依然建议设置成readonly模式
运营类的查询语句会在从库上执行,设置成readonly模式能够防止一些误操作
防止切换逻辑有Bug,例如出现双写,造成主从不一致
可以通过readonly状态来判断节点的角色
在状态1,节点B设置为readonly模式,同样能与节点A保持同步更新
readonly设置对超级权限用户是无效的,而节点B中用于同步更新的线程,就拥有超级权限
主从同步在节点A执行update语句,然后同步到节点B
从库B与主库A之间维持一个长连接,主库A内部有一个专门用于服务于从库B长连接的线程
在从库B上执行CHANGE MASTER命令,设置主库A的信息
IP、PORT、USER、PASSWORD
从哪个位置(文件名 + 日志偏移量)开始请求binlog
在从库B上执行START SLAVE命令,这时从库B会启动两个线程:io_thread + sql_thread
io_thread:负责与主库 ...
MySQL -- 数据可靠性
binlog的写入机制
事务在执行过程中,先把日志写到binlog cache,事务提交时,再把binlog cache写到binlog file
一个事务的binlog是不能被拆开的,不论事务多大,也要确保一次性写入
系统会给每个线程分配一块内存binlog cache,由参数binlog_cache_size控制
如果超过了binlog_cache_size,需要暂存到磁盘
事务提交时,执行器把binlog cache里面的完整事务写入到binlog file,并清空binlog cache
12345678-- 2097152 Bytes = 2 MBmysql> SHOW VARIABLES LIKE '%binlog_cache_size%';+-----------------------+----------------------+| Variable_name | Value |+-----------------------+----------------------+| binlog_cache_size ...
Java核心 -- Exception + Error
继承关系
概念
Exception:程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相关处理
Checked Exception:源代码显式捕获处理,编译期检查,设计初衷为从异常情况中恢复
Unchecked Exception(RuntimeException):可以编码避免的逻辑错误,不会在编译期强制要求
Error:在正常情况下,不太可能出现,绝大部分的Error都会导致程序处于不可恢复的状态
ClassNotFoundException12345Thrown when an application tries to load in a class through its string name using: The forName method in class Class. The findSystemClass method in class ClassLoader. The loadClass method in class ClassLoader.but no definition for the class with the specified na ...
MySQL -- 短连接 + 慢查询
短连接
短连接模式:连接到数据库后,执行很少的SQL后就断开,下次需要的时候再重连
在业务高峰期,会出现连接数突然暴涨的情况
MySQL建立连接的成本非常昂贵
成本:TCP/IP三次握手 + 登录权限判断 + 获取连接的数据读写权限
max_connections
max_connections:MySQL实例同时存在的连接数上限
当连接数超过max_connections,系统会拒绝接下来的连接请求,返回:Too many connections
当连接被拒绝,从业务角度来看是数据库不可用
如果机器负载较高,处理现有请求的时间会变长,每个连接保持的时间也会变长
如果再有新建连接的话,很容易触发max_connections的限制
max_connections的目的是保护MySQL的
如果把max_connections设置得过大,更多的连接就会进来,导致系统负载会进一步加大
大量的资源会耗费在权限验证等逻辑上,而已经拿到连接的线程会抢不到CPU资源去执行业务SQL
123456mysql> SHOW VARIABLES LIKE '%max_connect ...