使用canal实现redis缓存刷新

背景

假设现有项目P1,是直连数据库(mysql)的。为了提高性能,现在要加上缓存(redis),但是另有项目P2,也对数据库有操作,如何保证当P1加上redis后,P2对数据库修改后,P1从redis中获取的数据是最新的。有两种方案:

  • 一种是P1的开发人员和P2开发人员协调,当P2对mysql有修改、增加等操作,必须清除P1使用到的相关缓存。当P1读redis时,发现缓存失效,再读mysql,获取最新数据。
  • 一种是利用阿里巴巴的canal,获得mysql-binlog,根据mysql-binlog清除相关的缓存。这种方法的好处是不需要修改原来的程序。

使用到的技术

部署配置canal

canal的部署可以参考官方文档:https://github.com/alibaba/canal/wiki/QuickStart 配置的时候要注意:

  • conf/canal.properties是canal本身的配置文件,基本上默认即可
  • conf/example/instance.properties:应用的配置参数,一般需要修改其中的数据库连接配置

使用

1.启动canal:

sh bin/startup.sh

canal 的官方例子: https://github.com/alibaba/canal/wiki/ClientExample

利用canal解析mysql-binlog,能够获取到执行的sql,修改的表数据等信息,我这里获取修改的表,根据表名去清除掉使用到这个表的相关缓存,所以这里有一个对应关系:表名--缓存key

这里表名和缓存key的对应关系,为了方便,我将其存在一个属性文件中:cache.properties,并提供一个web界面来维护这个文件。

2.配置cache.properties

在计算机上任一位置建一文件:cache.properties,在项目的application.properties中有一属性:cache.properties.path,指向cache.properties文件的位置:

cache.properties.path=/Users/acheron/cache.properties

2.配置redis

util/RedisUtil.java中配置redis相关信息,主要是以下三项:

// Redis的地址
private static String HOST = "127.0.0.1";
// Redis的端口号
private static int PORT = 6379;
// 访问密码
private static String PASS = null;

3.添加表-缓存key配置

运行项目,浏览器访问,添加一条记录,数据将会保存到cache.properties

table_name1=herohuang'skey
table_name2=user.name.haha
table_name3=hahaha,com.hero,com.herohuang*
table_name4=com.hahaha,user.name.key,test

注意cachekey的配置:

  • 如果有多个,则用英文逗号隔开
  • 如果要删除所有以com.herohuang开头的缓存,则可以com.herohuang*

源码地址:https://github.com/Ac-heron/hexo-canal

界面展示

canal1canal2

学习总结:如何设计良好的数据库

数据库设计的概念

一个应用系统需要存放数据,那么我们就需要考虑用什么数据库,建几张表,表与表之间的关系是什么,每张表有多少字段,每个字段有什么特性,比如:数据类型、数据长度、数据约束(主外键、唯一约束、非空约束等)、数据索引等。

良好的设计和糟糕的设计

良好的设计:

  • 可以减少数据库的冗余
  • 尽可能的避免数据异常
  • 解决存储空间
  • 可以达到高效的访问

糟糕的设计:

  • 存在大量数据冗余
  • 存在数据插入,更新,删除异常
  • 浪费大量存储空间
  • 访问数据低效

数据库设计的步骤

  1. 需求分析:根据数据的属性和特点设置数据类型
  2. 逻辑设计:实现数据库的逻辑建模和数据关系(ER图)
  3. 物理设计:考虑具体的需求来选择合适的数据管理系统
  4. 维护优化:考虑表结构的建立、索引优化、大表拆分等

一、需求分析

我们接到一个项目,一般会进行以下的分析:

  1. 首先要去分析这个项目有哪些模块
  2. 然后针对具体模块分析有哪些属性
  3. 针对属性分析哪个属性或哪几个属性的集合可以用来作为[唯一标识]
  4. 分析这个模块数据是否永久存储,是否数据增长很快,是否经常查询
  5. 如果就要考虑分库分表了
  6. 如果不是,那么这些数据是否只会存储一定时间,是否需要永久记录
  7. 如果需要永久记录,我们就定期归档及数据的迁移操作

二、逻辑设计

1. 逻辑设计的工作

  • 将需求转化为数据库的逻辑模型
  • 通过ER图的形式对逻辑模型进行展示
  • 逻辑设计同所选用的具体的数据库管理系统无关

2. 数据库设计范式

数据库设计范式概念:是一些设计数据库的良好的规则或者经验。常见的数据库设计设计包括:第一范式、第二范式、第三范式

  • 【第一范式】: 数据库中的所有字段都是单一属性,不可再分的。这个单一属性是由基本的数据类型所构成的,如整数,浮点娄,字符串等。第一范式要求数据库中的表都是二维表。
  • 【第二范式】 数据库中的表中不存在非关键字段对任一候选关键字段的部分函数依赖。 部分函数依赖是指存在着组合关键字中的某一关键字决定非关键字的情况。 换名话说:所有单关键字段的表都符合第二范式。
  • 【第三范式】 第三范式是在第二范式的基础之上定义的。如果数据表中不存在非关键字段对任意候选关键字段的传递函数依赖则符合第三范式。 第三范式存在的问题:存在数据冗余;存在数据插入、更新和删除异常
  • 【BCNF范式(Boyce.Codd范式)】 在3范式基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合BC范式。也就是说如果是复合关键字,则复合关键字之间也不能存在函数依赖关系。

三、物理设计

1. 物理设计要做什么

  • 选择合适的数据库管理系统: oracle、sqlserver、mysql、PgSQL
  • 定义数据库、表以及字段的命名规范
  • 根据所选的dbms系统选择合适的字段类型
  • 反范式化设计

2. 选择哪种数据库

  • 商业数据库:oracle sqlserver 要考虑对应的成本,版权的费用
  • 开源数据库:mysql、 pgsql 考虑对应的效率,对应的系统,开发所使用的语言
  • 商业数据库更适合企业级项目, 开源数据库适用于互联网系统
  • Mysql常用存储引擎:
存储引擎 事务 锁粒度 主要应用 忌用
MyISAM 不支持 支持并发插入的表级锁 select,insert 读写操作频繁
MRG_MYISAM 不支持 支持并发插入的表级锁 分段归档,数据仓库 全局查找过多的场景
Innodb 支持 支持MVCC的行级锁 事务处理
Archive 不支持 行级锁 日志记录,只支持insert,select 需要随机读取、更新、删除
Ndb cluster 支持 行级锁 高可用性 大部分应用

3. 表及字段命名规则

  • 可读性原则(使用大小写来格式化的库对象名以获得良好的可读性)
  • 表意性原则(对象的名字应该能描述出它所标识的的对象)
  • 长名原则(尽可能少使用或不适用缩写)

4.字段选择类型的原则

基本原则 :
列的数据类型一方面影响数据存储空间的开销,另一方面也会影响数据查询的性能。当一个列可以选择多种数据库类型时,应该优先考虑数字类型,其次是日期或二进制类型,最后是字符类型。对于相同级别的数据类型,应该优先选择占用空间小的数据类型。

  • 在对数据进行比较(查询条件、JOIN条件及排序)操作时,同样的数据,字符处理往往比数字处理慢。
  • 在数据库中,数据处理以页为单位,列的长度越小,利于性能提升。

5. 如何具体选择字段类型

char与varchar的选择:
  • 如果列中要存储的数据程度差不多是一致的,则应该考虑用char,否则应该考虑用varchar
  • 如果列中的最大长度小于50byte,则一般先要考虑char
  • 一般不定义大于50byte的char类型列。
decimal与float 如何选择
  • decimal用于存储精确数据,而float只能用于存储非精度数据。
  • 由于float的存储空间开销一般比demimal小。(精确到7位小数只需要4个字节,而精确到15位小数只需要8个字节),故非精度数据优先选择float
时间类型如何存储
  • 使用int来存储时间字段的优缺点
    优点:字段长度比datetime小
    确定:使用不方便,要进行函数转换。
    限制:只能存储到2038-1-19 11:14:07即是2的32次方为2147483648
  • 需要存储的时间粒度
    年月日小时分秒周

6. 数据库设计的注意事项

如何选择主键

1.区分业务主键和数据库主键
业务主键用于标识业务数据,进行表与表之间的关联。
数据库主键为了优化数据存储

2.根据数据库的类型,考虑主键是否要顺序增长
有些数据库是按主键的顺序逻辑存储的

3.主键的字段类型所占用空间要尽可能的小
对于使用聚集索引方式的存储的表,每个索引后都会附加主键的信息

避免使用外键约束
  • 降低数据导入的效率
  • 增加维护成本
  • 虽然不建议使用外键约束,但是相关联的列上一定要建立索引。
避免使用触发器
  • 降低数据导入的效率
  • 可能会出现意想不到的数据异常
  • 使业务逻辑变的复杂。
关于预留字段
  • 无法准确的知道预留字段的类型
  • 无法准确的知道预留字段中所存储的内容
  • 严禁使用预留字段

7. 反范式化表设计

反范式化设计就是为了性能和读取效率的考虑而适当的对第三范式的要求进行违反,而允许存在少量的数据冗余,换句话来说反范式化就是使用空间来换取时间。
好处:减少表的关联数量、增加数据的读取效率、反范式化一定要适度

四、维护优化

1. 维护优化要做什么

  • 数据字典记录表中每个列所存储的内容是什么,方便后期维护和升级,特别是一些状态字段
  • 索引的维护,主要是从一个动态变化的角度来看待我们的数据和索引
  • 数据表中存在过时的字段,需要清理
  • 当表中的数据量达到一个数量级的话,影响查询的速度,需要对表进行适当的拆分

2. 如何维护数据字典

  • 使用第3方工具对数据字典进行维护(ORACLE PL/SQL, ORACLE TOAD…)
  • 利用数据库本身的备注字段来维护数据字典:
 //MYSQL为例:
CREATE TABLE Customer(cust_id in auto_increment not null comment ‘自增ID’, cust_name varchar(10) not null comment ‘客户姓名’, primary key(cust_id)) comment ‘客户表’
//导出数据字典(MYSQL数据字典案例:
select a.table_name, b.table_comment, a.column_name, a.column_type, a.column_comment from INFORMATION_SCHEMA.COLUMNS a join INFORMATION_SCHEMA.TABLES b on a.table_schema = b.table_schema and a.table_name = b.table_name where a.table_name = ‘customer’;

3. 如何维护索引

  • 出现在WHERE从句,GROUP BY从句,ORDER BY从句中的列
  • 可选择性高的列要放到索引的前面
  • 索引中不要包括太长的数据类型

【注意事项】:
– 索引不是越多越好,过多的索引不但会降低写效率而且会降低读的效率
– 定期维护索引碎片
– 在SQL语句中不要使用强制索引关键字

4. 数据库中适合的操作

维护表结构注意事项:

  • 使用在线变更表结构工具:
    MYSQL5.5之前可以使用 pt-online-schema-change
    MYSQL5.6之后本身支持在线表结构的变更
  • 同时对数据字典进行维护
  • 控制表的宽度和大小(表字段的大小控制,表数据量的分区,拆分处理等)
  • 禁止使用SELECT *这样的查询(把不必要的字段也查询出来,浪费IO)
  • 控制使用用户自定义函数(索引失效)
  • 不要使用数据库中的全文索引

5. 表的垂直拆分和水平拆分

  • 垂直拆分:解决宽度的问题
  • 水平拆分:解决数据量的问题

垂直拆分:当表的列过多,几十列等等,这是查询该表的IO速度会变慢,这是就建议进行垂直拆分,即拆分列,为了控制表的宽度。
– 经常一起查询的列放到一起
– TEXT, BLOB等大字段拆分到附加表中

水平拆分:表的水平拆分就是为了控制表的大小,也就是说,把一张大表里面的数据分配到其它几张相同的表中,这样就可以减少一张表里面存储的数据。一般采用的是哈希(hash key)的方式。

Linux系统MySQL的安装与使用

安装与配置MySQL

安装MySQL数据库

MySQL数据库分服务器和客户端,服务器用于管理和维护数据库,客户端用于连接和访问数据库,可以用下列命令安装服务器和客户端。安装期间将会提示输入数据库管理员root的密码。

sudo apt-get install mysql-server

配置文件my.cnf

MySQL的配置文件是/etc/mysql/my.cnf,主要用于配置数据库文件的存储位置,日志文件等,以下是安装之后默认的配置参数。

2015.07.24_19h25m36s_003_

mysql配置参数2
注意:
每次修改my.cnf时,都需要重新启动mysqld守护进程,可以使用如下命令:

sudo /etc/init.d/mysql restart

MySQL的简单使用

使用mysql

进入mysql命令环境,使用如下命令,-u后跟用户名,-p后跟密码,没有则为空

mysql -u -root -p

创建 查询 使用和删除数据库

创建:

create database test;

查询:

show databases;

使用:

use test;

删除:

drop database test;

设置用户及访问权限

mysql的用户和密码都存在一个专用的数据库mysql中,管理员root可以在其中添加用户及赋权,命令如下:

GRANT ALL PRIVILEGES ON database TO username@"servername" IDENTIFIED BY 'password';

如果flush配置变量没有设为ON,或者启动mysql进程时没有使用“–flush”选项,需要使用flush命令,才能使添加的帐户的生效。

flush privileges

SQL脚本与批处理

可以将多条命令写入一个文件,以I/O的方式运行mysql,批量执行命令,命令如下 :

mysql -u username -p [password] < scriptfile

例如新建一个文件:test.sql,内容如下:

show databases;
use test;
show tables;
select * from user;

利用命令执行,则将会显示执行结果:

mysql -u root -p < test.sql;

如果是在mysql交互环境下,则可用“source” 或 “ \ . ” 命令运行sql脚本:

source test.sql;

\. test.sql

绿色版MySQL的安装配置

我以mysql-5.6.13-win64.zip为例安装
 
一、配置环境变量
     
1、解压绿色版Mysql到某个目录,我这里是D:\javatools\mysql-5.6.13-winx64,将bin目录设为系统环境变量
绿色版MySQL的安装配置
二、修改my-default.ini文件
修改D:\javatools\mysql-5.6.13-winx64\my-default.ini文件,主要修改两个地方,basedir和datadir,默认是用#号注释的,去掉#号,basedir设为mysql安装目录;datadir设为mysql数据库存放位置

修改ini

三、安装mysql的服务
 
1、运行cmd,进入到bin目录下,运行命令:mysqld install MySQL –defaults-file=”D:\javatools\mysql-5.6.13-winx64\my-default.ini”
     出现Service successfully installed.表示安装成功。 如果出现Install/Remove of the Service Denied! 是因为权限不够,进入 C:\Window\System32找到cmd.exe右键选择 以管理员身份 进行,再进入相应目录执行命令,一切就OK了。
安装服务
四、启动mysql


   1、安装服务完成后,打开服务窗口,就可以找到mysql服务了,右键选择启动,可以在右键属性中,将启动类型设为自动,这样就能随开机而启动了。

  如果无法启动,报1067错误,则删除data/下ib-logfile0   ib-logfile1两个文件,然后启动。
绿色版MySQL的安装配置

绿色版MySQL的安装配置

     2、也可以用命令来启动和停止mysql
2014.07.13_15h15m38s_007   
     

五、登录mysql服务器
     输入命令:mysql -uroot
     注意:mysql的管理员用户名为root,密码默认为空。
     2014.07.13_15h19m34s_008

六、操作

1.查看数据库:show databases;

2.使用数据库:user 数据库名
3.查看表:show tables;
2014.07.13_15h28m27s_009