Memcache

NoSQL(Memcache)

php项目执行流程
【简单理解】
读取源码 -> 词法分析  -> 创建opcode -> 执行opcode 重复创建会增加额外的内存和CPU开销
【解决方案】
安装ZendOptimizer或APC2.0等可以加速PHP代码访问
主要用于缓存opcode而不是每次重复编译减少CPU和内存开销(php5.5+后不需要安装第三方软件,直接开启PHP配置文件中Opcache即可。
Memcache_第1张图片
2-1php流程.png

步骤 在php.ini中 输入一下代码 并重启Apache

;声明opcache扩展文件所在位置
zend_extension="PHP安装目录\php-5.6.27-nts\ext\php_opcache.dll"
;是否开启opcode缓存
opcache.enable=1
;OPcache 的共享内存大小,以兆字节为单位
opcache.memory_consumption=128
;用来存储临时字符串的内存大小,以兆字节为单位。 PHP 5.3.0 之前的版本会忽略此配置指令
opcache.interned_strings_buffer=8   
#OPcache 哈希表中可存储的脚本文件数量上限。
opcache.max_accelerated_files=4000
;检查脚本时间戳是否有更新的周期,以秒为单位。设置为 0 会导致针对每个请求,OPcache 都会检查脚本更新
opcache.revalidate_freq=60 
;打开快速关闭, 打开这个在PHP Request Shutdown的时候回收内存的速度会提高
opcache.fast_shutdown=1
;开启CLI
opcache.enable_cli=1
通过 phpinfo 检测是否开启成功 查看是否有OPcache

大型项目优化方向

代码优化
开启opcode缓存,减少额外CPU和内存开销,加快代码运行速度
重模型轻控制器,减少冗余
符合PHP-FIG规范和phpDoc规范,增强代码可读性&可扩展性有利于团队开发
类: 花括号独占一行
类中方法:华括号独占一行
类名:大驼峰
方法名:小驼峰
命名空间:后面空一行
常量名:大写,多个单词用下划线分割
数据库优化
架构:主从复制、读写分离
设计:存储引擎、字段类型、三范式
功能:缓存、分区、索引
缓存优化
好处:减少数据库查询,将数据缓存,加快查询数据
实现:
内存(memcache、redis)
文件(使用TP3.2的大S或大F方法  TP5中Cache类) 
数据库
架构优化
负载均衡、集群、动静分离、读写分离、主从复制、CDN加速等
    负载均衡:将用户的请求分配给多个服务器处理(轮着来,ip哈希)
    集群:多个服务器实现相同的业务
    分布式概念:多台服务器实现不同的业务
    动静分离:将静态资源单独放一台服务器
    主从复制:insert/update/delete到主服务器执行,所有从服务器检测主服务器有写入数据则自动同步
    读写分离:通过PHP判断,如果是insert/update/delete交给主处理,如果是select交给从服务器
    CDN加速:将静态资源缓存到用户所在城市,加快访问速度
Memcache_第2张图片
负载均衡.png

Memcache

概括:就是一个数据库、但是数据存在内存中

作用:常用来做缓存服务器、将从数据库查询的数据缓存起来,减少数据库查询、加快查询速度

与mysql比较 :
   共同点:都是C/S架构(客户端client/服务器server)
   不同点:mysql存磁盘文件、memcache内存
   不同点:mysql存储数据得先创建数据库再创建表、memcache直接以键值对形式存储
安装与配置Memcached(C/S结构)

服务端软件安装(win)

   说明:关于memcached.exe相关参数
-l    localhost              服务器ip地址(默认本机)
-p   port                        端口(11211)
-d   install/uninstall/start    管理memcache /安装/卸载/开启
-m  memory                   内存大小,默认64M

步骤 1 : 将下载的memcache解压到 指定目录中

步骤 2 : 安装memcache 服务器 (命令 cd 进入所在目录 -d install)

步骤 3: 启动memcached服务 memcached -d start

步骤 4: 检测是否启用成功 netstat -ano 查看是否有11211端口占用

通过putty连接memcache 数据库
Memcache_第3张图片
连接memcache.png
操作Memcached

命令手册 http://www.runoob.com/memcached/memcached-tutorial.html

增/改 (set)

   语法:set 键 是否压缩  缓存时间  数据长度
   键        -  对打长度不超过250字符
   是否压缩  -  1-是,0-否(以空间换时间)
   缓存时间  -  0-理论永久,其他-单位秒(注:最大存储时间30天)
   数据长度  -  写数字,单位字节(注:回车输入具体内容)
   说明: 键存在-则修改,键不存在-则创建

获取键值(get)

语法: get 键

添加键数据(add)

语法 : add 键 是否压缩 缓存时间 字节长度
如果键存在则报错

修改键数据 (replace )

语法 : replace 键 是否压缩 缓存时间 字节长度
注 : 只能修改不能添加(键不存在则报错)

删除键(delete)

语法 : delete 键

删除所有键 (flush_all)

语法 : flush_all

递增(incr)递减(decr)

   语法:incr  键  数字
   语法:decr  键  数字
   说明:返回增长后的结果,键必须存在

查看当前Memcached 运行状态 (stats)

stats
其中的数据 :
cmd_get:get命令请求次数
cmd_set:set命令请求次数
cmd_flush:flush命令请求次数
curr_items:当前存储的数据总数
total_items:启动以来存储的数据总数(包括过期的)
在PHP操作Memcached

在php开启php_memcache.dll扩展

下载扩展,网站 : http://pecl.php.net/package/memcache/3.0.8/windows

可通过phpinfo() 查看php版本 位数 .. 下载对应的扩展

在将下载的扩展文件移到到php ext目录下

修改php.ini扩展文件

extension dir = "php路径/ext" (扩展文件路径)
extension = php_memcache.dll 

重启apache 并通过phpinfo验证是否开启成功

操作

官方手册:https://secure.php.net/manual/zh/memcache.set.php

常用命令:

创建mem对象:$mem = new Memcache;
连接服务器:  $mem->connect(服务ip地址,端口)
关闭服务器:  $mem->close();
设置数据:    $mem->set(键,值  [,是否压缩,缓存时间])
获取数据:    $mem->get(键)
递增:        $mem->incrment(键,数字);
递减:       $mem->decrment(键,数字);
探究Memcache 能存储的数据类型
PHP 基本类型 : 字符串 布尔型 整型 浮点型
    复合类型 数组  对象
    特殊类型  null  资源(resource)
JS 基本类型 字符串  布尔 数值型(整型/浮点)
    复合类型:数组  对象
    特殊类型 unll undefined
验证存储的类型
connect('localhost', 11211);
//3.设置服务
$rs = $mem->set('int1', 8);
var_dump($rs);
$rs = $mem->set('int2', 8.88);
var_dump($rs);
$rs = $mem->set('int3', 'php12');
var_dump($rs);
$rs = $mem->set('int4', true);
var_dump($rs);

echo '
'; $rs = $mem->get('int1'); //int var_dump($rs); $rs = $mem->get('int2'); // float var_dump($rs); $rs = $mem->get('int3'); //string var_dump($rs); $rs = $mem->get('int4'); //bool

整型 浮点型 字符串 布尔型 都可以

connect('localhost', 11211);
//3.设置服务
$data1 = array('name'=>'zhangsan','age'=>18);
class test { public $name = 123;}   
$data2 = new test();

$rs = $mem->set('arr1', $data1);
var_dump($rs);
$rs = $mem->set('obj2', $data2);
var_dump($rs);

echo '
'; $rs = $mem->get('arr1'); //arr var_dump($rs); echo '
'; $rs = $mem->get('obj2');//object var_dump($rs); die;

注: 虽然数组和对象都可以存入 但其实通过putty查看arr1 发现是字符串 从根本上memcache是不支持数组的 但是通过php底层将数组序列化为字符串存储 在反序列化以数组显示

connect('localhost', 11211);
//3.设置服务
$data = fopen('xxxx', 'a+');
$rs = $mem->set('resource', $data);
var_dump($rs);
$rs = $mem->set('null1', null);
var_dump($rs);

echo '
'; $rs = $mem->get('resource'); //int(0) var_dump($rs); echo '
'; $rs = $mem->get('null1'); //null var_dump($rs); die;

null 是支持的 但是资源型不支持 虽然存储进入返回结果是true 但是打印出来是整0(false)

小结:

整型 浮点型 布尔型 数组(序列化为字符串) 对象 null 是可以存储的

资源型可以存储在 get出为int 0 (false) 也就是存储无效

Memcache的相关算法

惰性过期机制( lazy expiration )

memcached 内部不会监视记录是否过期

检查记录是否过期.这种技术被称为惰性过期

好处 : 减少监控过期产生的开销

#关闭服务
#启动服务
#查看状态当前运行状态(stats)
#设置一个键
#有效时间内,再查看运行状态(stats)
#有效时间后,再查看运行状态(stats)
#获取(get)后查看运行状态(stats)
最近最少使用算法 (LRU:Least Recently Used)

缓存空间已满 采用LRU策略

将使用频率最低数据进行删除

Memcache_第4张图片
LRU机制.png

Memcache常见问题

1 / 单个key键名最大长度为多少?
 最大长度是250个字符
2 / 每个item 选项最大存储多少数据
单个键最大存储数据为 1M
3 / 键的最大存储时间
最大存储时间为30天 (3600*24*30) 内都可以
0 为理论上永久 重启后数据会消失 数据满后 LRU也可以移除
验证 :
connect('localhost', 11211);
#步骤3:设置数据
$rs1 = $mem->set('data1', 111, 0, 3600*24*30 -1);  //30天-1秒
$rs2 = $mem->set('data2', 111, 0, 3600*24*30);     //30天
$rs3 = $mem->set('data3', 111, 0, 3600*24*30 + 1); //30天+1秒

var_dump($rs1);
var_dump($rs2);
var_dump($rs3);

echo '
'; var_dump($mem->get('data1')); //正常 var_dump($mem->get('data2')); //正常 true var_dump($mem->get('data3')); //false
memcached的cache机制是怎样的 ?
惰性过期机制  +  最近最少使用
惰性过期机制:不监控数据是否过期,每次获取判断
最近最少使用:磁盘空间占满,则删除最少使用的数据
memcache里面适合存储哪些数据

明确使用场景 : 缓存服务器

适合存储的数据

访问比较频繁的数据,安全性差的数据,丢失无所谓的数据。
数据更新,比较频繁的数据,比如用户的在线状态。
数据的单个键值不能太大,不要超过1Mb数据

分布式Memcache服务器

分布式原理

集群概念 : 多台服务器实现相同的业务

分布式概念 : 多台服务器实现不用的业务

使用PHP实现分布式Memcache
connect('localhost', 11211);
#设置memcache服务器连接池
$mem->addServer("192.168.43.37", 11211);
$mem->addServer("192.168.43.51", 11211);
$mem->addServer("127.0.0.1", 11211);

#步骤3:设置数据
$rs1 = $mem->set('name', 'dog');
$rs2 = $mem->set('age', 18);   
$rs3 = $mem->set('sex', 'boy'); 

var_dump($rs1);
var_dump($rs2);
var_dump($rs3);

echo '
'; var_dump($mem->get('name')); var_dump($mem->get('age')); var_dump($mem->get('sex'));

分别在三台服务器查看 数据通过底层算法分配

Session入Memcache缓存

说明 : 通过修改session的存储方式,可以将session存储到内存中

方法一 : 永久修改

修该php.ini配置文件

Memcache_第5张图片
session入memcache.png

重启apache ....

验证 :

';

echo session_id();  //获取键  使用键查询数据
方法二 : 临时改变

通过ini_set 函数来临时设置session的存储方式

';

echo session_id();
方法三 : 通过设置用户自定义会话存储函数

语法:session_set_save_handler(开启session机制函数,关闭session机制函数,
读取session数据函数,写入session函数,销毁session函数,后手过期session函数)
作用:自定义session会话处理方式,交给指定函数处理

自 PHP 5.4 开始,可以使用SessionHandlerInterface接口实现(注:接口里面都是抽象方法)
抽象类:有抽象方法的类就是抽象类
抽象方法:用关键词abstract并且没有函数体的方法
接口:特殊的抽象类(注:因为里面的方法都是抽象方法)
memcache = new Memcache;
            $this->memcache->addServer('127.0.0.1', 11211);
            return true;
        }

        public function close() {
            return true;
        }

        public function read($sessionId) {
            return $this->memcache->get( $sessionId ) ? : '';
        }

        public function write($sessionId, $data) {
            return $this->memcache->set($sessionId, $data);
        }

        public function destroy( $sessionId ) {
            //$this->memcache->delete($sessionId)
            return true;
        }

        public function gc( $lifetime ) {
            return true;
        }
    }
    
    MemcacheSessionHandler::start();
    $_SESSION['aa'] = 123;
    $_SESSION['bb'] = 456;
    echo session_id();

实现session共享

修改hosts文件,增加俩个域名解析到本机

hosts: 
 127.0.0.1  shop.test.com 
 127.0.0.1  blog.test.com

修改apache虚拟主机文件,增加二个站点 并重启apache


  ServerName shop.test.com
  DocumentRoot "E:\www2\a"
  
    Options +Indexes +FollowSymLinks +ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  



  ServerName blog.test.com 
  DocumentRoot "E:\www2\b"
  
    Options +Indexes +FollowSymLinks +ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  

分别在站点目录下创建test.php文件 ,输入以下代码

 1,
    'username' => '小泽'
);
echo session_id() . '
'; print_r($_SESSION); //-------------------------------------------- '; print_r($_SESSION);

单点登录

修改hosts文件,增加两个域名解析到本机

hosts: 
 127.0.0.1  shop.php.com 
 127.0.0.1  blog.php.com

修改apache虚拟主机文件,增加二个站点 并重启apache


  ServerName shop.php.com
  DocumentRoot "E:\www2\shop"
  
    Options +Indexes +FollowSymLinks +ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  



  ServerName blog.php.com
  DocumentRoot "E:\www2\blog"
  
    Options +Indexes +FollowSymLinks +ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  

将写好的shop和blog目录放在分别配置的虚拟机主机中

例 : 访问 shop.php.com/shop/index.php
登录后,在去访问 blog.php.com/blog/index.php 发现已登录
原理 : 
在shop..index.php  登录时将用户名保存到session
在访问blog..index.php 时检测session中是否有用户名 有则用
ini_set() — 为一个配置选项设置值
string ini_set ( string $varname , string $newvalue )
    成功时返回旧的值,失败时返回 FALSE

记录访问者信息

如何避免重复记录用户ip地址

连接数据库插入数据 (瑕疵 : 用户量大出现重复IP )

connect('127.0.0.1', 11211);

$ip = '192.168.9.'.rand(0, 10);

//3.创建用户信息数据结构
$person_info = [
    'ip' => $ip,
    'page'=> 'http://baidu.com',
    'referrer'=> 'http://baidu.com',
];
.
//4.判断是否记录IP:已记录-不管,未记录-入库
if( !$mem->get($ip) ) {
    //入库
    $filename = $ip . '_' . time();
    $mem->add($ip, $person_info);
    file_put_contents('./ip/'.$filename, 1);
}

加锁限制(排队操作避免出现重复ip插入)

connect('127.0.0.1', 11211);

$ip = '192.168.1.'.rand(0, 10);

//3.创建用户信息数据结构
$person_info = [
    'ip' => $ip,
    'page'=> 'http://baidu.com',
    'referrer'=> 'http://baidu.com',
];

//加锁不成功的,进行排队等待(注:第一个用户进来未处理完,后面的用户循环等待)
while ( !$mem->add('lock', 'lock', 0, 0) ){
    //进行休息
    usleep(1000); //usleep单位是微秒,1秒 = 1000毫秒 ,1毫秒 = 1000微秒
}

//4.判断是否记录IP:已记录-不管,未记录-入库
if( !$mem->get($ip) ) {
    //入库
    $filename = $ip . '_' . time();
$mem->add($ip, $person_info);
//因为memcache不能查看所有键,所以通过创建文件方式检测是否有重复
    file_put_contents('./'.$filename, 1);
}

//5.删除锁(注:操作完毕后,释放锁,让后面用户进来)
$mem->delete('lock');

你可能感兴趣的:(Memcache)