PHP 项目中缓存的多种应用实现

一、CDN缓存原理和介绍

1、各地部署多套静态存储服务,本质上是空间成本换时间

2、CDN是域名和真实服务器中间的一个环节,添加cdn节点后,用户访问时,自动选择最近的节点内容,不存在再请求原始服务器

3、CDN本质上是一种文件分发类系统,适合存储更新很少的静态内容,文件更新慢

注:cdn文件同步有两种方式

第一种:文件更新之后,由原始服务器将内容推送到cdn上

第二种:为cdn设置过期时间,到期之后,重新请求原始服务器获取最新数据

一般中小型公司,都是采用的免费的云cdn,比如阿里云的cdn分发系统、百度云的内容分发网络cdn等。

对于超大型公司来说,可能会采用自己搭建cdn系统的方式,但成本较高。


二、数据文件缓存方案

原理:将更新频率极低,且读取几率高的数据缓存为文件,获取时,不再查询数据库,而是直接读和解析缓存文件内容。

代码实现:

1、首先查询一遍数据库,并将查询到的数据生成 .json静态文件

public  function BannerToJson(){
    //1.我需要从数据库里提取到对应的焦点图的数据,
    $BannerModel = new  BannerBiz();
    $json = $BannerModel->GetBannerJson(7);

    //2.把数据进行整理,并生成为json格式,
    $RewriteModel = new RewriteBiz();
    $result = $RewriteModel->ToJson($json);
    if ($result){
        echo "焦点图生成成功";
    }else{
        echo "焦点图生成失败";
    }
}

2、之后,前台进行请求的时候,直接ajax请求之前生成好的json文件,就不需要再查询数据库了(缺点:实时性差)

//首页的轮播图
$.ajax({
    url: "/json/banner.json" ,
    type: "get",
    dataType: "json",
    async: false,
    success: function(json){
        if(json != null){
            for(var i=0;i<json.length;i++){
                $('.mainpage-slideshow-top .banner').append('<a href="'+json[i].url+'"><img src="'+json[i].pic+'" </a>');
            }
        }
        },
    error: function(){
            console.log( "AJAX fail");
        }
    });

//需要jquery.slideshow.js,可更改轮播间隔和主题颜色
$(".mainpage-slideshow-top").slideShow({color: "#f10823"});

总结:此方案类似于redis缓存或者memcache缓存,都是先把数据缓存到其他地方,避免频繁查询数据库

缺点:这种方案都有一种缺点,就是实时性比较差,需要我们写定时任务或者其他方式去定时更新缓存数据文件。这种方式比较适合新闻类网站,信息更新不是特别频繁。


三、全页面静态化

全页面静态化大致分为两种,一种是用类似smarty模板引擎实现,另一种则是是用ob实现,这里介绍的是类似smarty缓存的方式实现,但是推荐使用ob方式来实现页面静态化。

注:ob实现页面静态化 

原理:https://blog.csdn.net/guoshaoqing001/article/details/46673147

代码实现:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/79267703


数据文件缓存与全页面静态化对比:

数据缓存方案:

只是先将数据生成了静态文件,然后前台用ajax请求数据缓存文件,得到数据,展示给用户。

而全页面静态化:

则是直接将从数据库查询到的数据和前端页面进行结合,生成静态文件,存储在硬盘,用户访问时,直接请求生成的全静态页面,既没有数据库查询了,又没有了ajax请求了,直接将页面展示给用户即可。


代码实现方式:

常见于cms(内容管理系统),使用前后端分离的思想,如smarty,把页面共用区域做成模板,并留下变量区域,后台修改内容时,把变量替换入模板,并生成html。用户访问时,直接显示html页面。

全页面静态化:

优点:

有利于搜索引擎优化(seo),加快收录速度。

减轻服务器负担,减少数据库请求和运算量。

加快页面打开速度,便于进行cdn分发。

由于是静态文件,防止了漏洞和入侵。

非常适合文章类网站。

代码实现:

控制器部分:

/**
 * 全页面静态化代码实现
 */
public function ChannelToHtml(){

    //1.从数据库取出需要的数据【取数据就是普通的增删改查,不必关注】
    $channel_ids = array(1,2,3,4);
    $ChannelBiz = new ChannelBiz();
    $channel_data = array();
    foreach ($channel_ids as $channel_id) {
        //根据channel_id循环取出相应数据,并将四组数据放到同一个数组中
        array_push($channel_data , $ChannelBiz->GetChannelContent($channel_id));
    }

    //2.将从数据库取出的合并后的数据替换到html模板的相应位置
    $RewriteBiz = new RewriteBiz();
    $res = $RewriteBiz -> ToHtml('channel',$channel_data);
    if ($res) {
        echo '栏目生成成功';
    } else {
        echo '栏目生成失败';
    }

}


public function ToHtml($type , $data){

    if ('channel' == $type){

        //1.通过数组来取到对应的四个模块的html,
        $html_part = $this->GetChannelPart($data);
        //2.取到整页面的html模板,
        $html_template = file_get_contents(SITE_PATH.'/public/template/channel.html');
        //3.将四个栏目替换到模板的对应位置,
        $res_html = str_replace('<{channel_list}>' ,$html_part,$html_template);
        // 4.将合成后的html生成为静态文件,【fopen、fwrite、fclose这一套 相当于 file_put_contens,作用相似】
         $file = fopen(SITE_PATH.'/public/channel/channel.html','w');
         $res = fwrite($file,$res_html);
         fclose($file);
         if ($res) {
             return true;
         } else {
             return false;
         }
    }
}

public function GetChannelPart($data ,$i = 1){
    $html = file_get_contents(SITE_PATH.'/public/template/channel_part.html');
    $res_html = '';
    foreach ($data as $channel_data) {
        $part_html = $html;
        $part_sub_channel = $part_goods = $part_goods_foot = $part_brand =  '';
        $part_html = str_replace('<{i}>',$i,$part_html);
        $part_html = str_replace('<{channel_title}>',$channel_data['Info']['title'],$part_html);
        //子栏目部分,
        foreach ($channel_data['SubChannel'] as $sub_channel) {
            $part_sub_channel .= "<li><a href=\"".$sub_channel['url']."\">".$sub_channel['title']."</a></li>";
        }
        $part_html = str_replace('<{channel_link}>',$part_sub_channel,$part_html);

        //商品部分,
        $part_html = str_replace('<{main_goods}>','<a href="'.$channel_data['Goods'][1][0]['url'].'"><img src="'.$channel_data['Goods'][1][0]['pic_url'].'"></a>',$part_html);

        //小商品部分,
        foreach ($channel_data['Goods'][2] as $good) {
            $part_goods .=  '<li><a href="'.$good['url'].'"><p>'.$good['title'].'</p><p>'.$good['subtitle'].'</p><img src="'.$good['pic_url'].'"></a></li>';
        }
        $part_html =  str_replace('<{four_goods}>',$part_goods,$part_html);

        //小商品部分,
        foreach ($channel_data['Goods'][3] as $good) {
            $part_goods_foot .=  '<li><a href="'.$good['url'].'"><p>'.$good['title'].'</p><p>'.$good['subtitle'].'</p><img src="'.$good['pic_url'].'"></a></li>';
        }
        $part_html = str_replace('<{foot_goods}>',$part_goods_foot,$part_html);

        //品牌,,
        foreach ($channel_data['Brand'] as $good) {
            $part_brand .=  '<li><a href="'.$good['url'].'"><img src="'.$good['pic_url'].'"></a></li>';
        }
        $part_html =  str_replace('<{brands}>',$part_brand,$part_html);
        
        $res_html .= $part_html;
        
        $i++;
        
    }

    return $res_html;

}

html模板:

channel.html 以及 channel_part.html

<!DOCTYPE html>
<html>
<head>
    <title>京西频道页面</title>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
    <link rel="stylesheet" type="text/css" href="/static/css/common.css">
    <link rel="stylesheet" type="text/css" href="/static/css/main.css">
    <link rel="icon" href="/static/img/icon.ico">
    <script type="text/javascript" src="/static/js/jquery.js"></script>
    <script type="text/javascript" src="/static/js/jquery.slideshow.js"></script>
    <script type="text/javascript" src="/static/js/jquery.smimgslide.js"></script>
    <script type="text/javascript" src="/static/js/jquery.countdown.js"></script>
    <script type="text/javascript" src="/static/js/main.js"></script>
</head>
<body>
<div class="header">
    <div class="header-nav common-container">
        <ul class="header-nav-list">
            <li><h3><a href="#">秒杀</a></h3></li>
            <li><h3><a href="#">优惠券</a></h3></li>
            <li><h3><a href="#">闪购</a></h3></li>
            <li><h3><a href="#">拍卖</a></h3></li>
            <li><h3><a href="#">服装城</a></h3></li>
            <li><h3><a href="#">京西超市</a></h3></li>
            <li><h3><a href="#">生鲜</a></h3></li>
            <li><h3><a href="#">全球购</a></h3></li>
            <li><h3><a href="#">京西金融</a></h3></li>
        </ul>
    </div>
</div>
<div class="lovelife">
    <div class="common-container clearfloat lovelife-box">
        <div class="common-title">
            <i></i>
            <h2>爱生活</h2>
            <i></i>
        </div>
        <ul class="lovelife-list clearfloat">

            <{channel_list}>


        </ul>
    </div>
</div>
<!-- footer start -->
<div class="footer">
    <div class="footer-slogans">
        <ul>
            <li class="footer-slogans-item1"><i></i>
                <h3>品类齐全,轻松购物</h3></li>
            <li class="footer-slogans-item2"><i></i>
                <h3>多仓直发,极速配送</h3></li>
            <li class="footer-slogans-item3"><i></i>
                <h3>正品行货,精致服务</h3></li>
            <li class="footer-slogans-item4"><i></i>
                <h3>天天低价,畅选无忧</h3></li>
        </ul>
    </div>
    <div class="common-container clearfloat">
        <div class="footer-sevice clearfloat">
            <table class="footer-sevice-table">
                <thead>
                <tr>
                    <th>购物指南</th>
                    <th>配送方式</th>
                    <th>支付方式</th>
                    <th>售后服务</th>
                    <th>特色服务</th>
                </tr>
                </thead>
                <tbody>
                <tr>
                    <td><a href="#">购物流程</a></td>
                    <td><a href="#">上门自提</a></td>
                    <td><a href="#">货到付款</a></td>
                    <td><a href="#">售后政策</a></td>
                    <td><a href="#">夺宝岛</a></td>
                </tr>
                <tr>
                    <td><a href="#">会员介绍</a></td>
                    <td><a href="#">211限时达</a></td>
                    <td><a href="#">在线支付</a></td>
                    <td><a href="#">价格保护</a></td>
                    <td><a href="#">DIY装机</a></td>
                </tr>
                <tr>
                    <td><a href="#">生活旅行</a></td>
                    <td><a href="#">配送服务查询</a></td>
                    <td><a href="#">分期付款</a></td>
                    <td><a href="#">退款说明</a></td>
                    <td><a href="#">延保服务</a></td>
                </tr>
                <tr>
                    <td><a href="#">常见问题</a></td>
                    <td><a href="#">配送费收取标准</a></td>
                    <td><a href="#">邮局汇款</a></td>
                    <td><a href="#">返修/退换货</a></td>
                    <td><a href="#">京西E卡</a></td>
                </tr>
                <tr>
                    <td><a href="#">大家电</a></td>
                    <td><a href="#">海外配送</a></td>
                    <td><a href="#">公司转账</a></td>
                    <td><a href="#">取消订单</a></td>
                    <td><a href="#">京西通信</a></td>
                </tr>
                <tr>
                    <td><a href="#">联系客服</a></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td><a href="#">京西JD+</a></td>
                </tr>
                </tbody>
            </table>
            <div class="footer-sevice-info">
                <h5>京西自营覆盖区县</h5>
                <p>京西已向全国2654个区县提供自营配送服务,支持货到付款、POS机刷卡和售后上门服务。</p>
                <p><a href="#">查看详情 ></a></p>
            </div>
        </div>
        <div class="footer-lists">
            <ul class="footer-lists-links">
                <li><a href="#">关于我们</a></li>
                <li>|</li>
                <li><a href="#">联系我们</a></li>
                <li>|</li>
                <li><a href="#">商家入驻</a></li>
                <li>|</li>
                <li><a href="#">营销中心</a></li>
                <li>|</li>
                <li><a href="#">手机京西</a></li>
                <li>|</li>
                <li><a href="#">友情链接</a></li>
                <li>|</li>
                <li><a href="#">销售联盟</a></li>
                <li>|</li>
                <li><a href="#">京西社区</a></li>
                <li>|</li>
                <li><a href="#">风险监测</a></li>
                <li>|</li>
                <li><a href="#">京西公益</a></li>
                <li>|</li>
                <li><a href="#">English Site</a></li>
                <li>|</li>
                <li><a href="#">Contact Us</a></li>
            </ul>
            <br>
            <ul class="footer-lists-line1">
                <li><a href="#">京公网安备 11000002000088号</a></li>
                <li>|</li>
                <li>京ICP证070359号</li>
                <li>|</li>
                <li><a href="#">互联网药品信息服务资格证编号(京)-经营性-2014-0008</a></li>
                <li>|</li>
                <li>新出发京零 字第大120007号</li>
            </ul>
            <br>
            <ul class="footer-lists-line2">
                <li>互联网出版许可证编号新出网证(京)字150号</li>
                <li>|</li>
                <li><a href="#">出版物经营许可证</a></li>
                <li>|</li>
                <li><a href="#">网络文化经营许可证京网文[2014]2148-348号</a></li>
                <li>|</li>
                <li>违法和不良信息举报电话:4006561155</li>
            </ul>
            <br>
            <ul class="footer-lists-line3">
                <li>Copyright &copy; 2004 - 2016 京西JD.com 版权所有</li>
                <li>|</li>
                <li>消费者维权热线:4006067733&nbsp;&nbsp;&nbsp;&nbsp;<a href="#">经营执照</a></li>
            </ul>
            <br>
            <ul class="footer-lists-line4">
                <li>京西旗下网站:<a href="#">京西钱包</a></li>
                <li>|</li>
                <li><a href="#">京西云</a></li>
            </ul>
            <br>
            <ul class="footer-lists-icons">
                <li class="footer-lists-icons-item1"><a href="#"></a></li>
                <li class="footer-lists-icons-item2"><a href="#"></a></li>
                <li class="footer-lists-icons-item3"><a href="#"></a></li>
                <li class="footer-lists-icons-item4"><a href="#"></a></li>
                <li class="footer-lists-icons-item5"><a href="#"></a></li>
                <li class="footer-lists-icons-item6"><a href="#"></a></li>
            </ul>
        </div>
    </div>
</div>
<!-- footer end -->
</body>
</html>
<li class="lovelife-list-item<{i}> lovelife-list-col2  sidebarpointer" >

    <div class="lovelife-list-title">
        <h3><{channel_title}> </h3>
        <ul>
            <{channel_link}>
        </ul>
    </div>
    <div class="lovelife-list-content">
        <div class="lovelife-list-content-box">
            <div class="lovelife-list-content-leimg">
                <{main_goods}>
            </div>
            <ul class="lovelife-list-content-riimg">
                <{four_goods}>
                      </ul>
            <ul class="lovelife-list-content-mdimg">
                <{foot_goods}>
            </ul>
        </div>
    </div>
    <div class="lovelife-list-smimg">
        <span class="lovelife-list-smimg-leftarrow">&lt;</span>
        <span class="lovelife-list-smimg-rightarrow">&gt;</span>
        <div class="lovelife-list-smimg-box">
            <ul>
                <{brands}>
            </ul>
        </div>
    </div>


</li>

到此,类似smarty实现全页面静态化的工作就完成了。


四、数据分块加载——BigPipe 技术【类似facebook】

原理:分块加载,加载完一块,就先把页面数据刷给用户,再加载下面的,直到加载完毕

实现:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/80976332


五、 Memcache 缓存的应用


1、memcache安装及在项目中的使用 

https://blog.csdn.net/m_nanle_xiaobudiu/article/details/79279261

注:常用操作命令:http://www.runoob.com/memcached/php-connect-memcached.html


2、Memcache 和 Memcached的区别:

可以将memcached看做是memcache的升级版,memcache支持面向对象和面向过程两种写法,而memcached只支持面向对象的写法。



3、Memcache 和 Redis 的使用场景和性能的对比

实际上,这里并不推荐使用memcache,不仅是因为memcache没有认证和安全机制,而且不支持持久化,数据一旦丢失,或者memcache宕机,就将面临崩溃。同样是做缓存,更推荐使用redis。当然,具体还要根据业务场景做规划选择。

注:想要详细了解 memcache 和 redis的区别:https://www.cnblogs.com/Hondsome/p/5962144.html


六、集中式服务器——session共享问题

更改php.ini

默认php的session是存储在文件中的,我们需要更改成存储到memcache或者redis中

session.save_handler = "memcached"   #将session存储到memcache

session.save_path = "tcp://127.0.0.1:11211"   #填写memcache访问路径,如果是php7以上版本,“tcp:// ”可以省略

注:

如果只想某一个php文件中的session存储在缓存中,则可以在该文件中单独定义上面两个参数。


七、Nosql 之 Redis 内存数据库


1、简介:

Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

Redis拥有更多的数据结构,并支持更丰富的数据操作。

Redis支持数据持久化和数据恢复。

Redis的所有操作都是原子性的(相当于事务)。

简单的key-value存储,性能极高。

服务端支持AUTH密码验证。

手册下载https://download.csdn.net/download/m_nanle_xiaobudiu/10532352


2、常用命令

http://www.runoob.com/redis/redis-commands.html


3、用redis实现秒杀功能

https://blog.csdn.net/m_nanle_xiaobudiu/article/details/80479666


4、用redis实现数据库缓存功能

https://blog.csdn.net/m_nanle_xiaobudiu/article/details/79280419


5、运用redis缓存时,对于类型的选择

5.1、单一的key-value,自不必说,用string类型

5.2、如果是运用在消息队列,则选择list类型

5.3、如果是类似商品属性子属性,则选择hash类型

5.4、如果用于集合对比运算,比如南北差异,则使用set类型

5.5、如果用于显示排行榜,比如收藏榜,点击榜,则使用zset类型


6、Redis 持久化方案

两种方式:

RDB:指定的时间间隔内保存数据快照

AOF:先把命令追加到操作日志的尾部,保存所有的历史操作

详见:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/81001504


7、如何合理使用Redis

(1)防止内存占满

设置默认超时时间,避免key一直不释放。

不存放大文件,一般存储redis缓存时,一个键值对最好不要超过500字节。

不存储不常用数据,只存储高频数据(热数据)。

(2)提高使用效率

慎用正则处理。

合理使用不同的数据结构类型。

慎用批量操作Hash、Set 等。


8、六台机器搭建RedisCluster分布式集群

链接:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/81004557


八、浏览器缓存


猜你喜欢

转载自blog.csdn.net/m_nanle_xiaobudiu/article/details/80955723