innodb 为了提高磁盘I/O读写性能,存在一个 buffer pool 的内存空间,数据页读入会缓存到 buffer pool,事务的提交则实时更新到 buffer pool,而不实时同步到磁盘(innodb 是按 16KB 一页同步的,一事务可涉及多个数据页,实时同步会造成浪费,随机I/O)。事务暂存在内存,则存在一致性问题,为了解决系统崩溃,保证事务的持久性,我们只需把事务对应的 redo 日志持久化到磁盘即可(redo 日志占用空间小,顺序写入磁盘,顺序I/O)
sql 语句在执行的时候,可能会修改多个页面,还会更新聚簇索引和二级索引的页面,过程产生的redo会被分割成多个不可分割的组(Mini-Transaction)。MTR怎么理解呢?如一条 insert 语句可能会使得页分裂,新建叶子节点,原先页的数据需要复制到新数据页里,然后将新记录插入,再添加一个目录项指向新建的页子。这对应多条 redo 日志,它们需要在原子性的 MTR 内完成
MTR 产生的 redo 日志先会被复制到一个 log buffer 里(类似 buffer pool)。而同步到磁盘的时机如下:
事务需要保证原子性,也是说事务中的 *** 作要么全部完成,要么什么也不做。如果事务执行到一半,出错了怎么办-回滚。但是怎么回滚呢,靠 undo 日志。undo 日志就是我们执行sql的逆 *** 作
binlog有三种格式:Statement、Row以及Mixed。
redolog 中的事务如果经历了二阶段提交中的prepare阶段,则会打上 prepare 标识,如果经历commit阶段,则会打上commit标识(此时redolog和binlog均已落盘)。崩溃恢复逻辑如下:
一、前提条件 系统必须是使用LOG4J进行日志管理,否则方法无效。 系统必须包含中国mons-logging-xxx.jar,log4j-xxx.jar这两个JAR包,XXX为版本号。 二、 *** 作步骤 1、创建日志表要把日志持久化,必须在数据库中创建一张用来存储日志信息的表,表内字段为日志 的一个主要属性包括: *** 作类,执行方法,打印时间,日志级别,日志内容。CREATE TABLE RESLOG (LOGID VARCHAR2(20) NOT NULL, CLASS VARCHAR2(200), METHOD VARCHAR2(100), CREATETIME DATE, LOGLEVEL VARCHAR2(50), MSG VARCHAR2(4000))因为存储的类为类的全部路径,所以CLASS字段长度需要比较大。2、日志管理配置 LOG4J主要有两种配置文件.properties和.xml,这里以properties文件为基础来讲 述,关于XML文件的配置,相信大家看完下面的介绍也一样能轻松完成。 通常在LOG4J.PROPERTIES文件的第一行是: log4j.rootLogger= XXX,这句是控制日志的输出,如果想吧日志输出到数据库, 则需要在XXX中添加“DB”,如log4j.rootLogger=INFO,stdout,Platform,db。上面 这句就是把日志中级别为INFO的信息输出到STDOUT,PLATFORM和DB (DATABASE)中。 配置好如上的信息,LOG4J就知道用户是想把信息存入数据库,接下来我们就要来 配置数据库的相关信息(包括缓存,数据库连接信息,和执行SQL),配置信息如下: ###JDBCAppender log4j.appender.db = org.apache.log4j.jdbc.JDBCAppender //这个配置是选择使用JDBCAppender方法,将日志信息存储到数据库。当然,如果你还要做其他 *** 作,可以自己写个类,继承JDBCAppender就OK了。 log4j.appender.db.BufferSize=1 //这个配置是告诉LOG4J,有中国条日志信息后才存入数据库,我这里是1,就是说有一条就查一条,显然这样在生产环境下是很影响系统性能的。 log4j.appender.db.driver=oracle.jdbc.driver.OracleDriver //这个配置是告诉LOG4J,做数据库存储所用的驱动。 log4j.appender.db.URL=jdbc:oracle:thin:@:: //这个配置数据库连接的URL,不用说也都知道。 log4j.appender.db.user=XXX log4j.appender.db.password=XXX //上面两个是数据库连接时的用户名和密码 log4j.appender.db.sql=insert into RESLOG (LogId,Class,Method,createTime,LogLevel,MSG)values (SQ_RESLOG_LOGID.Nextval,'%C','%M', to_date('%d{yyyy-MM-dd HH:mm:ss}','yyyy-MM-ddHH24:mi:ss'),'%p','%m') //这个配置是告诉当LOG4J吧日志存储数据库时用的SQL语句。SQ_RESLOG_LOGID.Nextval是我建的一个SEQUENCE;‘%C’是日志中的CLASS;‘%M’是打印日志是执行到类里的方法;‘%d’是打印的时间,它支持格式化;‘%P’是日志级别,包括INFO、DEBUG、ERROR等;‘%m’是MSG,日志内容。注意这里的参数区分大小写。 log4j.appender.db.layout=org.apache.log4j.PatternLayout 通过上面的配置,现在再启动服务,LOG4J就会自动把原来存储在.LOG文件中的信息,同时存储到数据库数据持久化顾名思义就是把程序中的数据以某种形式保存到某存贮介质中,以达到持久化的目的。当程序运行时,一些数据是临时保存在内存中,一旦退出系统,这些数据就丢失了。那么,使用某种手段将数据保存在硬盘上或者数据库中,这样即使退出系统后又重新启动系统,那么这些数据仍然可以重新找回来。
例如管理员向一个用户管理系统中添加了一个用户的资料,那么这个系统需要将新添加的资料保存到数据库中,否则系统退出或者电脑重启后该用户资料就会丢失。将数据从内存保存到数据库中,这便是数据的持久化。当然,数据库只是持久化方式中的一种,也可以保存在其他的永久存贮介质中。
图为数据持久化的过程示意图。
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
持久化是将程序数据在持久状态和瞬时状态间转换的机制。
DBC就是一种持久化机制。文件IO也是一种持久化机制。
日常持久化的方法
在一定周期内保持不变就是持久化,持久化是针对时间来说的。数据库中的数据就是持久化了的数据,只要你不去删除或修改。比如在浏览器中一次Session会话中Session对象变量也是不变的,是Session容器中持久化。对象持久化的方式有很多种,根据周期不同有,page,Session,Application。对象序列化机制对于需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态. 对象序列化的过程是对象持久化的方法之一,把对象保存到文件中。
简单的理解持久化可以在二个层面:应用层和系统层、
应用层
如果关闭(shutdown)你的应用然后重新启动则先前的数据依然存在。
系统层
如果关闭(shutdown)你的系统(电脑)然后重新启动则先前的数据依然存在。
持久化是一种对象服务实现至少3个接口
,就是把内存中的对象保存到外存中,让以后能够取回。需要实现至少3个接口:
void Save(object o) 把一个对象保存到外存中
Object Load(object oid) 通过对象标识从外存中取回对象
boolExists(object oid) 检查外存中是否存在某个对象.
类似概念序列化
我们先跳开一下,看看另一个类似的有用概念:序列化Serialize也是一种对象服务,就是把内存中的对象序列化成流、或者把流反序列化成对象。需要实现2个接口:
void Serialize(Stream stream,object o) 把对象序列化到流中
object Deserialize(Stream stream) 把流反序列化成对象
序列化和持久化很相似,有些人甚至混为一谈,其实还是有区别的,序列化是为了解决对象的传输问题,传输可以在线程之间、进程之间、内存外存之间、主机之间进行。我之所以在这里提到序列化,是因为我们可以利用序列化来辅助持久化,可以说凡是可以持久化的对象都可以序列化,因为序列化相对容易一些(也不是很容易),所以主流的软件基础设施,比如.net和java,已经把序列化的框架完成了。
持久化方案可以分为关系数据库方案、文件方案、对象数据库方案、xml数据库方案
现今主流的持久化方案是关系数据库方案,
关系数据库方案不仅解决了并发的问题,更重要的是,关系数据库还提供了持久化服务之外的价值:统计分析功能。刚才我说到,凡是可以序列化的对象都可以持久化,极端的说,我们可以只建立一个表Object(OID,Bytes),但基本上没有人这么做,因为一旦这样,我们就失去了关系数据库额外的统计分析功能。关系数据库和面向对象之间有一条鸿沟,因为二者模式不匹配,所以就存在一个OR映射问题。
Redis支持两种数据持久化方式:rdb方式和aof方式。前者会根据配置的规则定时将内存中的数据持久化到硬盘上,后者则是在每次执行写命令之后将命令记录下来。两种持久化方式可以单独使用,但是通常会将两者结合使用。
1、RDB方式
RDB方式的持久化是通过快照的方式完成的。当符合某种规则时,会将内存中的数据全量生成一份副本存储到硬盘上,这个过程称作”快照”,redis默认开启该持久化功能,具体配置如下:
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
#文件名称
dir ./
#rdb文件存放路径
配置后系统会自动进行快照,save 60 10000表示60秒内有10000次写入,那么就会调用bgsave
除了系统自动进行快照外,我们也可以手动执行SAVE或BGSAVE命令主动进行快照 *** 作:
执行SAVE或BGSAVE命令
执行FLUSHALL命令
2、AOF方式
在使用Redis存储非临时数据时,一般都需要打开AOF持久化来降低进程终止导致的数据丢失,AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程会降低Redis的性能。
默认情况下,Redis没有开启AOF(append only file)持久化功能,可以通过在配置文件中作如下配置启用:
appendonly no #是否开启aof,开启时将no改为yes
appendfilename "appendonly.aof" 持久化文件名称
auto-aof-rewrite-percentage 100
#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-min-size 64mb
#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
appendfsync :everysec (推荐配置)
#持久化策略
always (同步持久化,每次发生数据变更会被立即记录到磁盘,性能差但数据完整性比较好)
everysec (异步 *** 作,每秒记录,如果一秒钟内宕机,有数据丢失)
no (将缓存回写的策略交给系统,linux 默认是30秒将缓冲区的数据回写硬盘的)
一般来说可以考虑同时使用两种持久化方案.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)