问题一:多版本迭代,如何兼容老的接口
多个版本迭代后,如何兼容老的接口。接口设计的一些准则和注意事项。开放给的三方厂商太多了。业务又需要迭代不清楚什么时候改老接口,什么时候做个新版本的接口
对于这种老接口,可能的场景是:属于祖传代码,经过很多人的维护,外部系统具体哪个还在使用,不好评估。所以需要考虑改动对外的影响。
接口直接通过 v1 v2这样的版本标识处理
controller/v1/……
controller/v2/……
在请求参数中通用传入version参数控制版本
场景例子:
第一个版本接口:public String getUserInfo(String name);
第二个版本接口,要新增一个参数 age
1.改变原来的接口结构,里面控制是否传参,
2.单独写一个新接口
问题二:数据迁移有些什么方案,通常怎么做
方案一:Mysql dump
1 将本地的数据库(dbname)导出为sql文件
mysqldump -uroot -p dbname> dbname.sql
2 在服务器的mysql中新建同名数据库(dbname),然后退出mysql
create database fangyuanxiaozhan charset=utf8;
Exit
3 将文件导入
mysql -uroot -p dbname< dbname.sql
优点:
mysqldump的优点就是逻辑备份,把数据生成SQL形式保存,在单库,单表数据迁移,备份恢复等场景方便,SQL形式的备份文件通用,也方便在不同数据库之间移植。
缺点:
mysqldump是单线程,数据量大的时候,备份时间长,甚至有可能在备份过程中非事务表长期锁表对业务造成影响(SQL形式的备份恢复时间也比较长)。
方案二:MySQL binlog
MySQL 的迁移可以考虑MySQL的主从复制replication的特性运行迁移过程不需要停机。
步骤:
1.master配置
开启binlog
创建同步账号,赋予权限
查看主服务器状态,并记录下状态 show master status;
2.slave配置
设置readonly
配置master,并开启同步
补充:
重新做主从,完全同步。(该方法适用于主从库数据相差较大,或者要求数据完全统一的情况。)
1)、进入主库,进行锁表,防止数据写入。注意:该处是锁定为只读状态,语句不区分大小写
mysql> flush tables with read lock;2)、进行数据备份并解锁
mysqldump -uroot -pYouPwd YourDB > bak.sql;
mysql> UNLOCK TABLES;3)、查看master 状态并记录
mysql> show master status;4)、把mysql备份文件传到从库机器,进行数据恢复5)、停止从库的状态
mysql> stop slave;6)、从库执行mysql命令,导入数据备份7)、设置从库同步,具体参数请根据master status填写
change master to master_host = '192.168.1.246', master_user = 'slave', master_port=3306, master_password='YourSalvePwd', master_log_file = 'mysqld-bin.000035', master_log_pos=120;8)、重新开启从同步
mysql> start slave;9)、查看同步状态
mysql> show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
方案三:使用中间件例如canal
带业务逻辑的增量数据处理
跨数据库的数据备份(异构数据同步),
例如mysql => oracle,mysql=>mongo,mysql =>redis,
mysql => elasticsearch等;
优点:
canal 基于binlog,对数据库无压力,准实时,延时性低,可接入业务服务清洗数据,场景灵活。
缺点:
额外引入中间件,技术成本
问题三:数据库误删数据如何找回
基于binlog进行恢复
binlog它记录了所有的 DDL 和 DML 语句(除了数据查询语句select、show等),以事件形式记录,binlog 的主要目的是复制和恢复。
步骤:
1.将原来实例全备份到新实例
2.查找对应的起始位点,在新实例恢复数据
3.将新实例的binlog备份到原来的数据库
show binlog events查看对应的语句,找到对应的位点
mysql> show binlog events in 'mysql-bin.000007' from 1190 limit 2\G
*************************** 13. row ***************************
Log_name: mysql-bin.000007
Pos: 1190
Event_type: Query //事件类型
Server_id: 123
End_log_pos: 1352 //结束pose点,下个事件的起点
Info: use `test`; insert into tb_person set name="name__2", address="beijing", sex="man", other="nothing"
mysqlbinlog --start-position=1190 --stop-position=1352
找到位点,我们通过命令,执行恢复:
b.直命令行解析
SHOW BINLOG EVENTS
[IN 'log_name'] //要查询的binlog文件名
[FROM pos]
[LIMIT [offset,] row_count]
1190-135如下:mysql> show binlog events in 'mysql-bin.000007' from 1190 limit 2\G
*************************** 13. row ***************************
Log_name: mysql-bin.000007
Pos: 1190
Event_type: Query //事件类型
Server_id: 123
End_log_pos: 1352 //结束pose点,下个事件的起点
Info: use `test`; insert into tb_person set name="name__2", address="beijing", sex="man", other="nothing"
*************************** 14. row ***************************
Log_name: mysql-bin.000007
Pos: 1352
Event_type: Xid
Server_id: 123
End_log_pos: 1383
Info: COMMIT /* xid=51 */
问题四:sql 如何调优?
简单的优化点补充:
1、使用函数,做条件判断
2、组合索引:遵循最左原则,常用作多条件排序
3、order by,例外:如果 order by 是主键或索引是整数类型,则会走索引
4、!= 号,例外:如果是主键,则会走索引
5、> 号,例外:如果是主键或索引是整数类型,则会走索引
6、or 条件中有未建立索引的列,索引失效
高级的优化点补充:
1、分库分表
2、更换数据源,例如:采用大数据数据库,ES等
3、预处理数据,例如:定时加载并处理数据,使用缓存等
4、读写分离 读库加索引
索引性能参数体现:
type:全称为"join type",意为连接类型。通俗的讲就是mysql查找引擎找到满足SQL条件的数据的方式。其值为:
system:系统表,表中只有一行数据
const:读常量,最多只会有一条记录匹配,由于是常量,实际上只须要读一次。
eq_ref:最多只会有一条匹配结果,一般是通过主键或唯一键索引来访问。
ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取
fulltext:进行全文索引检索。
ref_or_null:与ref的唯一区别就是在使用索引引用的查询之外再增加一个空值的查询。
index_merge:查询中同时使用两个(或更多)索引,然后对索引结果进行合并,再读取表数据。
unique_subquery:子查询中的返回结果字段组合是主键或者唯一约束。
index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引。
rang:索引范围扫描。
index:全索引扫描。
all:全表扫描。
possible_keys:可能用到的索引
key:使用的索引
ref:ref列显示使用哪个列或常数与key一起从表中选择行。
rows:显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。
Extra:额外的信息
Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。
Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。
Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表
问题描述:报表类应用如何设计缓存?
背景:数据库类有约1000W明细数据,包含交易大区,交易小区,城市,业务类型,一级负责人,二级负责人等近10个维度字段。前端提供基于这些维度字段的自由分类,汇总,排序等操作的报表,也会下钻查看明细数据。这样的系统如何进行缓存的设计?
备注:数据库内1000W的数据会在每天全量更新1-3次
如果维度还要多,分更多层级,我们可以使用拼接的形式,比如:
a维度_b维度_c维度 -> key1
value如果数据非常非常多,比如占用空间很大,那么就进行更细粒度的拆分;(a维度_b维度_c维度 -> key1)
如果value不算特别大,就可以粗粒度的拆分。(a维度 -> key1 ;b维度 -> key2; )
考虑:采用mongodb,es
延时双删理解:
在数据库更新这步一直加锁,当处理完数据库的更新,才释放锁。
这样,及时B线程开始读缓存,也会被阻塞,一直等到数据库更新完。
此时B线程,再拿到锁,去读缓存,读不到,再去读数据库,已经是对的数据了
如果是这个样子呢,b线程在更新数据库之前,进行了查询缓存、查询数据库,并且更新了缓存。
此时已经将缓存刷成了错误的数据。
延时删除缓存,就变得有意义了,会再一次清除缓存,使后面的线程查询时,更新到最新的数据。
问题:服务挂了怎么配置重试时间?
(从场景考虑)
我能想到两种场景:
1、自己的服务宕机
2、依赖的外部服务挂了
针对第一种,我能考虑的是,无法重试,属于线上服务故障,需要及时引发报警,进行及时的问题排查以及重启;
针对第二种,我的服务,依赖外部服务的接口,此时会考虑两个问题:
a.是否需要重试
b.重试的话,按照什么维度:是频率,1s、2s、3s、5s;还是次数,1秒一次,共3次,还是5秒1次,共2次;
a.是否需要重试:我举个例子,比如我通过外部接口,判断这个用户是否有访问权限,当外部服务挂掉了,我并不知道他是否有权限访问页面,只能当时请求一次,无法支持让用户等重试时间。
b.重试的话,按照什么维度:
再举个例子:当a服务,凌晨定时处理数据,处理完成后,b服务需要进行取最终的数据。
通过频率限制,取数的频率,并不能通过次数限制。
分表后如何分页?
中间件查询原理
对于sharding-key分页查询:中间件支持直接进行查询
对于非sharding-key分页查询引入ES进行查询