数据库读写分离与 Redis 缓存:从 MySQL 查询压力到缓存机制

本文探讨高并发场景下MySQL性能瓶颈的两种核心优化方案:读写分离通过主从架构分担读写压力,缓解单库负载;Redis缓存则利用内存高速访问特性,减少热点数据对数据库的重复查询。重点分析了主从延迟导致的一致性问题,以及缓存更新策略(如更新后删除缓存)在保障数据时效性中的关键作用。

前言:为什么应用服务器和数据库分离之后,还需要继续优化

我们上一篇文章学习到了单机架构逐渐演化到分布式架构的过程,最开始,应用程序和数据库都运行在同一台服务器上,随着访问量增加,我们可以将应用服务器和数据库服务器分开部署,减少它们之间的资源竞争,如果应用服务器的处理能力不够,还可以增加应用服务器,并通过负载均衡将请求分配给不同的服务器

但是,这样就意味着系统不会再出现性能问题了吗?答案是否定的

例如,一个电商网站有很多用户同时访问商品详情页。即使我们已经部署了多台应用服务器,这些服务器最终仍然可能需要访问同一个 MySQL 数据库,当大量请求集中访问数据库时,数据库依然可能成为整个系统的性能瓶颈。

那么,我们还能怎么优化?

接下来要理解两个重要的思路:

  1. 数据库读写分离:让不同的数据库实例分担读写压力。

  2. 引入缓存:让一部分请求不必每次都访问数据库。

这两个方案都可以改善系统的性能,但它们解决问题的方式并不相同,接下来我们的这篇文章就主要围绕这两个优化以及下面这张图来展开

一,数据库读写分离

为什么

在研究数据库读写分离之前,我们先要了解什么是读与写

读:用户查询商品详情,查看订单

写:用户修改个人信息,创建订单

通常访问量比较小的时候,一台MySQL数据库通常就能承担这些工作,但是当大量用户查询商品,数据库就需要处理大量读请求,并且事实也是如此,我们读的操作往往请求量是更大一些的,为了应对这个,我们就可以考虑读写分离了

怎么做

简单来说就是将数据库的读操作和写操作分配给不同的数据库实例处理,一般情况就分为多个从库和一个主库

主库:主要负责写操作,例如新增,修改和删除数据

从库:通常用于处理读操作,例如查询商品信息

数据复制:主库的数据变更会复制到从库,减少数据不同步的情况

存在的问题

这里分离之后存在的一个需要特别注意的问题:主库和从库的数据可能会不实时统一

就比如:当用户修改了自己的昵称之后,整个过程就是应用程序将新的昵称写入主库,主库成功完成更新,用户立即重新查询自己的昵称,而查询的请求被路由到了从库,但是此时的从库的数据还没有更新,这就是常说的复制延迟导致的数据读取不一致

因此我们在应对这种实时性要求很高的场景的时候,系统就需要将这次的查询路由到主库先或者采用其他的一致性的处理策略

二,Redis缓存

理解了读写分离之后,我们还需要考虑一个问题,就是加入我们网站有一个非常热门的产品,大量用户每天查询多次商品信息,但是与此同时,我们用户的信息以及商品的信息是不会频繁改变的,那每一次查看商品的时候都需要重新查询MySQL吗,这个时候我们就可以引入我们的主角Redis了

什么是缓存

缓存可以理解为是将经常使用的数据保存起来,在后续需要的时候优先在这个位置读取,从而减少重复的计算以及访问后端资源

为什么不直接使用MySQL

首先需要明确一点就是MySQL也是可以利用内存的,也就是说不能简单的理解为MySQL只能从硬盘读取数据,使用Redis是因为两个数据库的设计和应用场景不同

MySQL:适合关系型数据管理,复杂SQL查询

Redis:擅长以内存中的数据结构处理大量简单的频繁的数据访问操作

所以我们一般是MySQL以及Redis共同合作

怎么做

我们以用户查询为例子来理解Redis缓存是如何工作的

1. 第一次查询:缓存未命中

我们用户查询商品信息,spring boot接受请求之后查询Redis缓存,发现缓存里没有数据,我们就通过MySQL来查询数据并且将数据写到Redis缓存中

2. 第二次查询:缓存命中

如果商品信息已经在Redis中存储过了,那么我们就可以直接从Redis中获取商品详情

实时更新的问题

就是当我们MySQL中保存的商品信息已经更新了,但是我们的Redis的信息还是老的,这个时候我们该如何进行处理

1. 一种常见的处理方式:更新数据库后删除缓存

  1. 先更新 MySQL 中的业务数据。

  2. 更新成功后,删除 Redis 中对应的缓存。

  3. 下一次用户查询时,如果缓存不存在,就重新查询数据库。

  4. 获取最新数据后,再将结果写入 Redis。

为什么这里选择删除缓存,而不是一定要把新数据直接写入缓存?

这样可以减少缓存长期保存旧值的风险,也可以避免部分复杂的缓存的更新问题,不过在更加复杂的情况之下,我们还需要考虑一些其他的问题以及方案

三、总结

本文从数据库读写分离出发,进一步理解了 Redis 缓存的作用。

我们需要记住几个核心结论:

  1. 应用服务器与数据库分离之后,数据库仍然可能成为性能瓶颈。

  2. 数据库读写分离通过将读写请求分配给不同的数据库实例,分担数据库负载。

  3. Redis 缓存通过保存热点数据,减少重复访问 MySQL 的次数。

  4. 缓存命中时可以直接从 Redis 获取数据;缓存未命中时,应用程序需要从数据库获取数据。

  5. 使用缓存后,需要考虑过期时间、数据一致性以及缓存失效带来的问题。

  6. 数据库读写分离与 Redis 缓存可以配合使用,并不是相互替代的技术。

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
评论 17
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值