架构-1:高性能架构之读写分离和分表分库
架构-2:高性能架构之NoSQL和缓存
架构-3:高性能架构之单机高性能和负载均衡
架构-4:高可用架构之存储高可用
架构-5:高可用架构之Paxos和Raft
架构-6:高可用架构之一致性哈希算法和数据分片
架构-7.高可用架构之接口级故障
架构的复杂度来源-高性能
随着软件系统越来越复杂,软件系统不得不面对三个大问题(高性能,高可用,可拓展)。就拿一个网站来说,最开始用户量较少,单机架构就可以支持。随着用户量的增加,系统的功能不断叠加。软件系统开始变得慢,开始不稳定,修改个bug牵一发而动全身。这时就必须升级软件的架构。
尽管硬件的发展很快,相比于软件的发展,真是小巫见大巫。单机架构无论如何都无法支持大量的访问和事务。解决高性能问题的基本思想就是拆
- 把不同的任务拆分到不同的机器上,比如读写分离,分表分库。
- 把适合的任务拆分到适合的中间件:比如NoSql,缓存,队列
- 把相同的任务拆分到不同的机器:负载均衡
当然,一味的拆并不一定会提高性能。因为拆意味着组件之间必须要通讯,网络通讯速度肯定比不上直接调用。而且网络环境复杂,可用性也会降低。拆完后,组件之间的调用,也使得代码逻辑更加复杂。所以高性能,关键的是合适,单机架构能支撑的,就没必要考虑分布式微服务了。
高性能存储
读写分离
读写分离是指对数据库的查询拆分成两台或者多台机器,负责写的称之为主机,负责读的称之为从机。从机不负责写,只从主机复制数据。这样就能把读写的压力分开来。读写分离适合读写压力都非常大的业务,如果只是读压力大而写压力很小或者读压力很小而写压力大,甚至两个压力都不大,是没有必要使用读写分离的,毕竟读写分离的作用是分担压力,提高性能。
读写分离会遇到的问题
- 主机从机的复制延迟
主从并不是实时复制的,比如注册新用户后立马使用登录,这时注册的信息写入到主机了,而登录时读取的从机却还没有数据,导致登录失败。- 解决方案1:如果是紧随写操作的读操作,发送给主机(业务侵入性大)
- 解决方案2:如果读从机失败,再去主机读取一次(多次读压力大)
- 解决方案3:关键业务的读写都指向主机
- 分配问题
应用系统怎么知道哪个是主机哪个是从机呢?- 解决方案1:自己实现数据访问层,
- 解决方案2:开源实现:MyCat,淘宝的TDDL,Atlas,MySQL Router
mysql开启主从复制
- 主机配置
# 启用二进制日志
log_bin = mysql-bin
# 唯一标识,如果不设置server-id,主机将拒绝所有从机的连接
server-id = 111
log-bin-index=mysql-bin.index
binlog_format=mixed
binlog-do-db = testdb //同步数据库
binlog-ignore-db = mysql//忽略的数据库
binlog_checksum=NONE
####性能相关####
#1次提交都会执行复制
innodb_flush_log_at_trx_commit = 1
#数据库使用异步写入到磁盘时,每1次进行一次同步
sync_binlog = 1
确保注释skip-networking或者不使用,否则只允许本地从机连接
# skip-networking
- 创建同步账户
grant replication slave on *.* to slave@192.168.1.11 identified by '123456'
flush privileges;#刷新权限信息
- 记录主机状态
show master status;
记录下二进制日志文件名和位置
- 从机配置
# 定义server-id,每个从机和主机的唯一标识,不能重复,一般取IP最后一段
server-id=2
# 只读
read_only = 1
- 配置连接主库,从机操作
change master to master_host='192.168.1.10',master_user='slave',master_password='123456', master_log_file='mysql-bin.000008',master_log_pos=337;
master_host:主机ip
master_user:刚创建的复制用户
master_password:刚创建的复制用户密码
master_log_file:刚记录的主机状态的二进制文件名
master_log_pos:刚记录的主机状态的位置
- 开始同步,从机操作
start slave;
分表分库
分库
分库是指把不同的业务的数据分散到不同的数据库服务器.分散数据库能够分散访问压力,但是也带来一些问题。
- join问题
分布在不同数据库里的表,无法使用join进行关联。
解决方案- 1:先找出其中一个表的数据,在根据找出的数据(如ID)去另外一个数据库找对应的表数据。缺点是数据分页时,分页的条件不能同时落在两张表
- 2:冗余字段,在表1中冗余表2的字段,这样即不用考虑join问题,还能提高性能。但是更新数据时要维护两张表,会有一致性问题,同时增加了代码复杂度。
- 3:使用myCat支持的跨库join,只支持两张表的join。缺点是要引入数据库中间件。
- 事务问题
分布在不同数据库的表,无法使用数据库提供的事务,一般使用分布式事务解决。
解决方案:- 1.MySQL提供的XA事务:使用两段式提交,当所有的事务都执行成功后,再全部提交。串行执行,性能较差。
- 2.TCC补偿性事务:补偿性事务在当前数据库事务执行完毕后直接提交,并锁定资源(比如付款后冻结付款的金额),并提供一个回滚的方法(如其他事务执行失败后,解冻杯冻结的金额),缺点是必须编写很多额外的补偿性代码
- 3.本地消息表:在TCC的基础上增加一个消息队列和记录事务状态的记录表,适用于时间较长的事务。消息队列解耦了各个协同事务,而事务状态记录表可以重新发起失败的事务,避免事务丢失。
分表
- 垂直分表
垂直分表是把某些占用了大量空间但是不常用的字段分离出去,但是会让表的数量增加,在查询不常用字段时,需要join查询。 - 水平分表
水平分表区别于垂直分表,不是切分字段而是切分行。- 可以使用mysql的partition关键字分表,需要在表创建时定义。如果是已经存在的表,使用alert进行修改,可能会导致耗费大量的服务器资源,需要谨慎操作。
- 使用mycat,Sharding-JDBC等数据库中间件,把表分到不同的数据库。
- 自己写代码分表。
水平分表可以根据不同的条件分,如范围,指定值和hash