PHP_MVC框架开发,nosql学习,mysql优化,以及高并发web架构处理

PHP 专栏收录该内容
16 篇文章 0 订阅

定义入口文件

  • 定义常量
  • 引入库函数
  • 引入核心模块

image-20210401161012543

完成自动加载

入口文件 index.php

<?php

// door file

// define system const
define('LSPHP', __DIR__ . "/");
define('APP', __DIR__ . "/app");
define('CORE', __DIR__ . "/core");


//define debug
define('APP_DEBUG',true);

if (APP_DEBUG) {
    ini_set('display_errors', 'On');
} else {
    ini_set('display_errors','Off');
}


// include core func file
include CORE . '/common/function.php';
// test
// p("1234");


// include core class file
include CORE . "/lsphp.php";
// test
// \core\lsphp::run();


// 实现类加载,注册加载函数
spl_autoload_register('\core\lsphp::load');

\core\lsphp::run();

自动加载 lsphp.php

<?php
    
namespace core;

class lsphp
{

    public static $classMap = [];

    public static function run()
    {
        $route = new \core\route();
    }

    // 实现自动加载
    public static function load($class)
    {
        if (isset(self::$classMap[$class])) {
            return true;
        } else {
            $filepath=str_replace('\\','/',$class);
            $filepath=LSPHP.$filepath.'.php';
            if(is_file($filepath))
            {
                require $filepath;
                self::$classMap=$filepath;
            }else{
                return false;
            }
        }
    }
}

route.php

<?php
namespace core;

class route
{
    public function __construct()
    {
        echo 'route';
    }
}

路由类

.htaccess

.htaccess 文件是 apache 服务器中的一个配置文件,她负责相关目录下的网站配置,通过 htaccess 文件,可以实现:

  • 网页301重定向
  • 自定义404错误页面
  • 改变文件扩展名
  • 允许/阻止特定的用户或者目录的访问
  • 禁止目录列表
  • 配置默认文档等功能
<IfModule mod_rewrite.c>
    # 打开Rerite功能
    RewriteEngine On

    # 如果请求的是真实存在的文件或目录,直接访问
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # 如果访问的文件或目录不是真事存在,分发请求至 index.php
    RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

explode

explode — 使用一个字符串分割另一个字符串

explode ( string $delimiter , string $string [, int $limit ] ) : array

此函数返回由字符串组成的数组,每个元素都是 string 的一个子串,它们被字符串 delimiter 作为边界点分割出来

和 python 的 split 函数功能相同

trim

trim — 去除字符串首尾处的空白字符(或者其他字符)

trim ( string $str [, string $character_mask = " \t\n\r\0\x0B" ] ) : string

此函数返回字符串 str 去除首尾空白字符后的结果。如果不指定第二个参数,trim() 将去除这些字符:

  • " " (ASCII 32 (0x20)),普通空格符
  • “\t” (ASCII 9 (0x09)),制表符
  • “\n” (ASCII 10 (0x0A)),换行符
  • “\r” (ASCII 13 (0x0D)),回车符
  • “\0” (ASCII 0 (0x00)),空字节符
  • “\x0B” (ASCII 11 (0x0B)),垂直制表符

和 python 的 strip 函数功能相同

array_slice

array_slice — 从数组中取出一段

array_slice ( array $array , int $offset [, int $length = NULL [, bool $preserve_keys = false ]] ) : array

array_slice() 返回根据 offsetlength 参数所指定的 array 数组中的一段序列

<?php
$input = array("a", "b", "c", "d", "e");

$output = array_slice($input, 2);      // returns "c", "d", and "e"
$output = array_slice($input, -2, 1);  // returns "d"
$output = array_slice($input, 0, 3);   // returns "a", "b", and "c"

实现

实现类似于 think PHP 那样的效果,将 url 中的参数分别取出

index.php/模块/控制器/操作/参数/#index.php 作为入口文件,所以后端要将传来的 url 进行分割取值

因为没有设置路由映射,我的网站 url 为:

http://localhost/demo/develop/index.php

# $_SERVER['REQUEST_URI'] = "/demo/develop/index.php"

数组下标从 0 开始

# route.php

<?php

namespace core\lib;

class route
{
    // 默认控制器和操作
    public $ctrl = "index";
    public $action = "index";
    public $param = [];

    public function __construct()
    {
        if (isset($_SERVER['REQUEST_URI'])) {
            $pathString = $_SERVER['REQUEST_URI'];
            $path_arr = explode('/', trim($pathString, '/'));
            // $path_arr='/demo/develop/index.php/index/index/param/222'
        }

        if (isset($path_arr[2]) && ($path_arr[2]) == "index.php") {
            $path_arr = array_slice($path_arr, 3, count($path_arr) - 2);
             p($path_arr);
            // $path_arr='index/index/param/222'
        }

        if (isset($path_arr[0])) {
            // 取控制器
            if (isset($path_arr[0])) {
                $this->ctrl = $path_arr[0];
            }
        }

        // 取操作
        if (isset($path_arr[1])) ;
        {
            $this->action = $path_arr[1];
        }

        // 取参数,因为参数是在数组下标 2 开始
        $i = 2;
        $count = count($path_arr);
        while ($i < $count) {
            if (isset($path_arr[$i + 1])) {
                $this->param[$path_arr[$i]] = $path_arr[$i + 1];
            }
            $i=$i+2;
        }

        p($this->ctrl);
        p($this->action);
        p($this->param);
    }
}

image-20210402150320504

控制器

加载控制器

定义好控制器文件

image-20210402194510725

# indexController.php<?php

namespace app\controller;

class IndexController
{
    public function index()
    {
        echo 'hello index';
    }
}

在 lsphp.php 文件中去定义加载功能

......    
	public static function run()
    {
        $route = new \core\lib\route();

        // 加载控制器
        $ctrl = $route->ctrl;
        $action = $route->action;

        $controllerFile = APP . "/controller/" . $ctrl . "Controller.php";
        $controllerClass="\\app\\controller\\".$ctrl."Controller";
        // 命名空间 \\ $ctrl(index)Controller

        if (is_file($controllerFile)) {
            require $controllerFile;
            $controller = new $controllerClass;
            $controller->$action();

        } else {
            throw new \Exception("controller not found!");
        }
    }
......

image-20210402194808127

数据库

新建数据库,表

image-20210402200220261

初始化连接

image-20210402200437526

db.php

使用 pdo 来实现,数据库配置连接

<?php

namespace core\common;

class db extends \PDO
{
    public function __construct()
    {
        $dsn = 'mysql:host=localhost;dbname=lsphp';
        $username = 'root';
        $password = 'root';
        try {
            parent::__construct($dsn, $username, $password);
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

数据查询函数

# indexController.php  
......
	public function query()
    {
        $db = new \core\common\db();
        $sql = "select * from ls_user";
        $data = $db->query($sql);
        p($data);
        p($data->fetchAll());
    }
......

index控制器 query操作

image-20210402202044746

视图

extract

(PHP 4, PHP 5, PHP 7)

extract — 从数组中将变量导入到当前的符号表

extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] ) : int

本函数用来将变量从数组中导入到当前的符号表中

检查每个键名看是否可以作为一个合法的变量名,同时也检查和符号表中已有的变量名的冲突

就是把一个键值对作为一个变量,键名为变量名,键值为变量值

image-20210403103510105

# render.php

<?php

namespace core;

class render
{
    public $param = [];

    // 传参数函数
    public function assign($name, $value)
    {
        $this->param[$name] = $value;
    }

    // 控制传到那个视图中去
    public function display($view)
    {
        $viewPath=APP."/view/".$view.".html";

        if(is_file($viewPath))
        {
            extract($this->param);
            include $viewPath;
        }else{
            echo "view is not found";
            exit();
        }
    }
}

# indexController.php
<?php

namespace app\controller;

class IndexController extends \core\render
    # 需要继承 render
{
    public function render()
    {
        $this->assign("title","ocean");
        $this->assign("content",'test');
        $this->display("index");
    }
}
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>

<h2>
    <?php echo $title ?>
</h2>
<p>
    <?php echo $content ?>
</p>
</body>
</html>

效果如下

image-20210403103643467

其他类

配置类

为了实现代码简介,将代码按功能进行划分,将配置文件单独存放,也方便修改

image-20210403203300498

两个配置文件作为示例

# db_config.php
<?php
return array (
    "dsn" => 'mysql:host=localhost;dbname=lsphp',
    "username" => 'root',
    "password" => 'root',
);
# route_config.php
<?php
return array(
    "1"=>"one",
    "2"=>"two",
    "3"=>"three"
);

\core\conf.php 去加载配置类

# \core\conf.php
<?php
// 获取加载配置config信息的函数
namespace core;

class conf
{
    # 获取一条信息
    public static function get($name, $file)
    {
        $fileName = CONFIG . "/$file" . ".php";
        if (is_file($fileName)) {
            $conf = include $fileName;
            if (isset($conf[$name])) {
                return $conf[$name];
            }else{
                throw new \Exception("not found config name!");
            }
        } else {
            throw new \Exception("not found file!");
        }
    }

    # 获取全部信息
    public static function all($file)
    {
        $fileName = CONFIG . "/$file" . ".php";
        if (is_file($fileName)) {
            $conf = include $fileName;
            return $conf;
        } else {
            throw new \Exception("not found file!");
        }
    }
}

因为使用了 CONFIG 常量,需要提前定义好

# index.php
define("CONFIG",__DIR__."/config");

这样的话就可以把数据库配置文件单独存放在 config 文件里

以下调用数据

# \core\common\db.php
class db extends \PDO
{
    public function __construct()
    {
        $db_config=\core\conf::all('db_config');
        $dsn=$db_config['dsn'];
        $username=$db_config['username'];
        $password=$db_config['password'];
        .....
            
# 单个调用            
    public function getroute(){
        $route= \core\conf::get("1",'route_config');
        p($route);            

日志类

记录操作步骤

添加 LOG 常量

# index.php
header("Content-type:text/html;charset=utf-8");
// 因为要返回中文,如果有乱码设置header头

define('LOG', __DIR__ . "/log");
# \core\log.php 日志记录文件

<?php
namespace core;

class log
{
    public function log($message)
    {
        ini_set('data.timezone', 'Asia/Beijing');
        $log_dir = LOG . '/' . date('Ymd');
        if (!is_dir($log_dir)) {
            if (mkdir($log_dir)) {

            } else {
                throw new \Exception("log file create error");
            }
        }

        $log_file = $log_dir . '/' . date('Hi');
        // H 表示 24小时,i 表示 60分钟
        if (!is_file($log_file)) {
            if(!file_put_contents($log_file,$message.PHP_EOL,FILE_APPEND)){
                // 文件名,文件内容.php换行(\n),写入方式:追加写入
            }else{
                throw new \Exception("log content write error");
            }
        }
    }
}

调用

# indexController.php
	public function log()
    {
        $log = new \core\log();
        $log->log("this is a test log");
        echo 'ok';
    }

会在 log 目录下生成文件

image-20210403215333629

composer插件

smarty是一个基于PHP开发的PHP模板引擎

smart插件安装

先新建 composer.json 定义 smart 配置信息

# composer.json
{
  "require": {
    "PHP": ">=5.3.0",
    "smarty/smarty": "~3.1"
  }
}

用 composer 安装 smart ,执行命令前检测是否有 composer.lock 文件,有的话可能检测不出来 json 文件有变化,导致无法更新,提示 Nothing to install or update

PS D:\phpstudy_pro\WWW\demo\develop> composer install

系统会自动寻找 json 文件,按配置进行安装,安装完成后会自动生成文件

image-20210404175855471

在 index.php 文件中定义系统常量

define('LIB',LSPHP."vendor");

包含核心类文件

// 包含核心文件
include LIB."/autoload.php";

smarty使用

新建目录

image-20210404180658627

引入 smarty 文件

# render.php
public $smarty;

public function __construct()
{
    $this->smarty=new \Smarty();
    // 导入smarty文件
    $this->smarty->setTemplateDir(APP.'/smarty/templates/');
    $this->smarty->setCompileDir(APP.'/smarty/template_c/');
    $this->smarty->setConfigDir(APP.'/smarty/configs/');
    $this->smarty->setCacheDir(APP.'/smarty/cache/');
}

使用

image-20210404182516219

# indexController.php
public function testsmarty()
{
    $this->smarty->assign("username","this is test smarty page");
    $this->smarty->display("index/index.html");
}

image-20210404182419065

whoops

Whoops 适用于PHP环境的错误捕获与调试PHP库,方便定位错误点

安装方法同于 smarty 的安装

在 composer.json 文件定义好安装版本

{
  "require": {
    "PHP": ">=5.3.0",
    "smarty/smarty": "~3.1",
    "filp/whoops": "*"
  }
}

定义好后使用安装命令,会自动安装

PS D:\phpstudy_pro\WWW\demo\develop> composer install

安装完成后生成 psr、filp 文件夹

image-20210404184248124

在 index.php 文件中导入 whoops

if (APP_DEBUG) {
    ini_set('display_errors', 'On');

    $whoops = new \Whoops\Run;
    $whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
    $whoops->register();
}
......

安装之后的报错界面

image-20210404184339839

var_dumper

对环境要求较高,建议使用 PHP 高版本

安装方法相同

"symfony/var-dumper": "*"

 composer install

使用:用 dump 方法代替 var_dump

class IndexController extends \core\render
{
    public function index()
    {
        var_dump($_SERVER);
        dump($_SERVER);
    }

两种方法对比

image-20210404185000563

medoo

轻量级 php 数据开发框架

开发文档:https://medoo.lvtao.net/doc.php

安装方法相同

"catfan/medoo": "*"

设置 medoo 配置数据

# config/medoo_config.php
<?php

return array(
    'database_type'=>'mysql',
    'database_name'=>'lsphp',
    'server'=>'localhost',
    'username'=>'root',
    'password'=>'root',
    'charset'=>'utf8',
    'port'=>3306, // 可选参数
    'prefix'=>'ls_', // 定义表的前缀
);

定义 Medoo 初始化文件

# core/medoo.php
<?php
namespace core;
class medoo extends \Medoo\Medoo{
    public function __construct()
    {
        $conf=\core\conf::all('medoo_config');
        parent::__construct($conf);
    }
}

查询语句

# controller/indexController.php
class IndexController extends \core\render
{
    public function index()
    {
        $medoo = new \core\medoo();
        $data = $medoo->select('user', "*", ["id" => '2']);
        # select('表名','字段名',where条件)
        dump($data);
    }
    ......

image-20210404194529187

插入语句

# controller/indexController.php
class IndexController extends \core\render
{
    public function index()
    {
        $medoo = new \core\medoo();
        $data = [
            "username" => "youku",
            "password" => "alibaba"
        ];
        $result = $medoo->insert('user', $data);
        # insert('表名','数据')
        $query = $medoo->select('user', '*');
        dump($query);
    }

image-20210404195016565

修改数据

class IndexController extends \core\render
{
    public function index()
    {
        $medoo = new \core\medoo();
        $data = [
            "username" => "tudou",
            "password" => "alibaba"
        ];
        $result = $medoo->update('user', $data,['username'=>'youku']);
        $query = $medoo->select('user', '*');
        dump($query);
    }

image-20210404195236565

删除数据

class IndexController extends \core\render
{
    public function index()
    {
        $medoo = new \core\medoo();

        $result = $medoo->delete('user',['username'=>'tudou']);
        dump($result->rowCount());
        # rowcount 受影响的行数
    }

image-20210404195704940

nginx_ev

apache 是同步多进程模型,一个连接对应一个程序,nginx 是异步的,多个连接(万级别)可以对应一个程序

通用方案是,前端 nginx 抗并发,后端 apache 集群,动态请求交给 apache 做,nginx 适合静态和反向代理

nginx的使用场景

1、反向代理
反向代理:反向代理(ReverseProxy)是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,简单来说就是真实的服务器不能直接被外部网络访问,想要访问必须通过代理。

反向代理的作用

  • 防止主服务器被恶意攻击
  • 为负载均衡和动静分离提供实现支持

2、负载均衡
负载均衡 : 使用反向代理同时代理多个相同内容的应用服务器(比如Apache),将客户端请求分发到各个应用服务器上并接收响应返回给客户端
负载均衡的作用:当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃。为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力。我们可以建立很多很多服务器,组成一个服务器集群,当用户访问网站时,先访问一个中间服务器,在让这个中间服务器在服务器集群中选择一个压力较小的服务器,然后将该访问请求引入该服务器。如此一来,用户的每次访问,都会保证服务器集群中的每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况

3、动静分离
运用Nginx的反向代理功能分发请求:所有动态资源的请求交给应用服务器,而静态资源的请求(例如图片、视频、CSS、JavaScript文件等)则直接由Nginx返回到浏览器

动静分离的作用:主要是nginx处理静态页面的效率远高于Apache的处理能力,使用c语言开发的nginx对静态资源每秒的吞吐量远高于其它应用服务器

Tengine

Tengine是由淘宝网发起的Web服务器项目。它在 Nginx 的基础上,针对大访问量网站的需求,添加了很多高级功能和特性

NoSQL

泛指非关系型数据库,关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据

关系型数据库一般将数据放入硬盘,非关系型放入内存

NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题

典型 NoSQL 数据库有三种

常见单位

  • QPS(Query per second) 每秒查询量
  • TPS(Transaction per second)每秒事务量

Memcached

优点

  1. Memcached 是一套分布式高速缓存系统,可以利用多核优势,单实例吞吐量极高,可以达到几十万 QPS (每秒查询率QPS,取决于 key、value 的字节大小以及服务器硬件性能,日常环境中 QPS 高峰大约在 4-6w 左右),适用于最大程度扛量
  2. 支持直接配置为session handle ,session

缺点

  1. 只支持简单的 key/value 数据结构,不想 Redis 可以支持丰富的数据类型
  2. 无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失
  3. 无法进行数据同步,不能将 MC 中的数据迁移到其他 MC 实例中
  4. Memcached 内存分配采用 Slab Allocation 机制管理内存,value 大小分布较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题,需要用户注重 value 设计

Redis

优点

  1. 支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基数估算)
  2. 支持持久化操作,可以进行 aof 及 rdb 数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段
  3. 支持通过 Replication 进行数据复制,通过 master-slave 机制,可以实时进行数据的同步复制,支持多级复制和增量复制,master-slave 机制是 Redis 进行 HA 的重要手段
  4. 单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题
  5. 支持pub/sub消息订阅机制,可以用来进行消息订阅与通知
  6. 支持简单的事务需求,但业界使用场景很少,并不成熟

缺点

  1. Redis 只能使用单线程,性能受限于 CPU 性能,故单实例 CPU 最高才可能达到 5-6wQPS 每秒(取决于数据结构,数据大小以及服务器硬件性能,日常环境中 QPS 高峰大约在 1-2w 左右)
  2. 支持简单的事务需求,但业界使用场景很少,并不成熟,既是优点也是缺点
  3. Redis 在 string 类型上会消耗较多内存,可以使用 dict(hash表)压缩存储以降低内存耗用

mongoDB

MongoDB 是一款NOSQL数据库 介于关系型数据库与NOSQL之间,可以完成更复杂查询功能的功能,而且支持分片和副本集

优点

  1. 更高的写负载,MongoDB 拥有更高的插入速度
  2. 处理很大的规模的单表,当数据表太大的时候可以很容易的分割表
  3. 高可用性,设置 M-S 不仅方便而且很快,MongoDB 还可以快速、安全及自动化的实现节点(数据中心)故障转移
  4. 快速的查询,MongoDB 支持二维空间索引,比如管道,因此可以快速及精确的从指定位置获取数据。MongoDB 在启动后会将数据库中的数据以文件映射的方式加载到内存中。如果内存资源相当丰富的话,这将极大地提高数据库的查询速度
  5. 非结构化数据的爆发增长,增加列在有些情况下可能锁定整个数据库,或者增加负载从而导致性能下降,由于 MongoDB 的弱数据结构模式,添加1个新字段不会对旧表格有任何影响,整个过程会非常快速

缺点

  1. 不支持事务
  2. MongoDB 占用空间过大
  3. MongoDB 没有成熟的维护工具

三者区别

  1. 性能

    三者的性能都比较高,总的来讲:Memcached和Redis差不多,要高于MongoDB

  2. 便利性

    Memcached数据结构单一

    Redis丰富一些,数据操作方面,Redis更好一些,较少的网络IO次数

    MongoDB支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富

  3. 存储空间

    Memcached可以修改最大可用内存,采用LRU算法

    Redis在2.0版本后增加了自己的VM特性,突破物理内存的限制;可以对key value设置过期时间(类似memcached)

    MongoDB适合大数据量的存储,依赖操作系统VM做内存管理,吃内存也比较厉害,服务不要和别的服务在一起

  4. 可用性

    Memcached本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的hash或者环状的算法,解决单点故障引起的抖动问题

    Redis,依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,所以单点问题比较复杂;不支持自动sharding,需要依赖程序设定一致hash 机制。一种替代方案是,不用redis本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡

    MongoDB支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制

  5. 可靠性

    Memcached不支持,通常用在做缓存,提升性能

    Redis支持(快照、AOF):依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响

    MongoDB从1.8版本开始采用binlog方式支持持久化的可靠性

  6. 一致性

    Memcached在并发场景下,用cas保证一致性

    Redis事务支持比较弱,只能保证事务中的每个操作连续执行

    MongoDB不支持事务

  7. 数据分析

    MongoDB内置了数据分析的功能(mapreduce),其他两者不支持

  8. 应用场景

    Memcached:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写少,对于数据量比较大,可以采用sharding)

    Redis:数据量较小的高性能操作和运算上

    MongoDB:主要解决海量数据的访问效率问题

总结分析

  1. 若是简单的存取key-value(主要是读)这样的数据用Memcached好一些。若是要支持数据持久化,量也不大,操作很频繁,多数据类型(如集合、散列之类的),用列表类型做队列之类的高级应用,就用Redis,但如果是数据量比较大时就采用MongoDB
  2. Memcached的很多客户端更加成熟稳定,Redis协议比Memcached复杂。Redis不可能比Memcached快?但是测试结果基本是Redis占绝对优势
  3. 云数据库Memcached版实例中的数据是存储在内存中的,当出现宕机、机房断电等意外,或是云数据库Memcached版实例在正常升级维护时,内存中的数据均会丢失。因此,云数据库Memcached版不能作为持久化的数据存储服务使用。Redis的数据都存放在内存中,如果没有配置持久化,Redis重启后数据就全丢失了,于是需要开启Redis的持久化功能,将数据保存到磁盘上,当Redis重启后,可以从磁盘中恢复数据,实现持久化
  4. 对于Redis和MongoDB来说,大家一般称之为Redis缓存、MongoDB数据库。Redis主要把数据存储在内存中,其“缓存”的性质远大于其“数据存储“的性质,其中数据的增删改查也只是像变量操作一样简单;MongoDB却是一个“存储数据”的系统,增删改查可以添加很多条件,就像SQL数据库一样灵活
  5. MongoDB和Redis都是NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于二者在内存映射的处理过程,持久化的处理方法不同。MongoDB建议集群部署,更多的考虑到集群方案,Redis更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式

img

概括

  1. memcached曾经的优势是可以集群,但是现在redis也可以了。
    redis支持更多数据结构,支持数据持久化。所以redis可以看做memcached的超集。
  2. redis最强大的特性是zset
  3. redis有hash,但是只有一层深度,mongodb是有理论上无限深度的hash
  4. mongodb是真正的数据库,而不是缓存数据库,他的竞争对手应该是mysql等关系型数据库

实际应用中: 最佳搭配是mysql + redis,操作都很方便,兼顾速度和容量

redis使用

phpstudy 可以安装 redis,可以一键开启 redis 服务

image-20210405102430756

也可以在命令行启动

PS D:\phpstudy_pro\Extensions\redis3.0.504> .\redis-server.exe .\redis.windows.conf
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 3.0.504 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 11004
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

[11004] 05 Apr 10:07:54.059 # Server started, Redis version 3.0.504
[11004] 05 Apr 10:07:54.059 * DB loaded from disk: 0.000 seconds
[11004] 05 Apr 10:07:54.059 * The server is now ready to accept connections on port 6379

redis cli 使用

启动

PS D:\phpstudy_pro\Extensions\redis3.0.504> .\redis-cli.exe
127.0.0.1:6379>

当前使用的 php 需要支持 redis

密码为空可以直接连接

image-20210405102309610

<?php

$redis = new Redis();
$redis->connect("127.0.0.1",6379);
$redis->set("ocean","ocean");

image-20210405102351834

MySQL优化

设计:存储引擎 字段类型

性能:索引 缓存 分区

架构:主从复制 读写分离 负载均衡

开启 MySQL 查询计时

mysql> show variables like "prof%";
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| profiling              | OFF   |
| profiling_history_size | 15    |
+------------------------+-------+
2 rows in set (0.00 sec)

mysql> set profiling =1;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show variables like "prof%";
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| profiling              | ON    |
| profiling_history_size | 15    |
+------------------------+-------+
2 rows in set (0.00 sec)

mysql> show profiles;
+----------+------------+-----------------------------+
| Query_ID | Duration   | Query                       |
+----------+------------+-----------------------------+
|        1 | 0.00194875 | show variables like "prof%" |
+----------+------------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

show profiles;

就可以看到 上句 sql 语句花费的时间

存储引擎

  • Innodb

    Innodb : 数据完整性, 并发性处理, 擅长更新, 删除

  • MyIASM

    MYIsam: 高速查询及插入, 擅长插入 \ 查询

总结:

  • 大容量的数据集时趋向于选择 Innodb。因为它支持事务处理和故障的恢复。Innodb 可以利用数据日志来进行数据的恢复。主键的查询在 Innodb 也是比较快的
  • 大批量的插入语句时(这里是 INSERT 语句)在 MyIASM 引擎中执行的比较的快,但是 UPDATE 语句在 Innodb 下执行的会比较的快,尤其是在并发量大的时候
索引

添加索引

image-20210405114507165

添加索引后,速度大大提高

image-20210405114441776

缓存

show variables like ‘query_cache%’;

分区

如果数据过大,可以通过分区提高速度

建表语句

partition by key(id) partitions 5;

explain

在 MySQL 语句前面加上 explain,会解析执行过程

image-20210405114959386

多并发

原子性

Apache 测试多线程工具 ab.exe

ab.exe -c 10 -n 100 [url]

image-20210405130047680

经过一千次测试,发现数据会有一定偏差

解决方法

MySQL 锁

就是把多线程在锁内变成了单线程

image-20210405130601136

文件锁

阻塞式,悲观锁

image-20210405130917330

redis处理多并发

非阻塞式,乐观锁,比如抢 100 次(请求100次),有的成功有的失败

image-20210405131340617

高并发WEB架构

针对高并发需求的在不同层有众多优化技术

业务展示层

(cdn加速,动静分离,页面压缩)

CDN 就是内容分发网络,在各处放置服务器来构成一层智能虚拟网络,此处服务器称之为节点服务器,它会自动根据用户请求信息把请求重新分配到离客户端最近的服务器

CDN的作用: 解决由于服务端与客户端所在区域的不同,导致影响数据传输速度和稳定性问题,一句话总结就是让数据传输更快更稳定

逻辑处理层

页面静态化(ob系列函数)

并发请求处理(swoole扩展)

消息队列(Kafka,ActiveMQ)

数据处理层

数据缓存

主从复制

读写分离

负载均衡

web 服务器集群

  • 大容量的数据集时趋向于选择 Innodb。因为它支持事务处理和故障的恢复。Innodb 可以利用数据日志来进行数据的恢复。主键的查询在 Innodb 也是比较快的
  • 大批量的插入语句时(这里是 INSERT 语句)在 MyIASM 引擎中执行的比较的快,但是 UPDATE 语句在 Innodb 下执行的会比较的快,尤其是在并发量大的时候

索引

添加索引

[外链图片转存中…(img-OvdsByhg-1617692347004)]

添加索引后,速度大大提高

[外链图片转存中…(img-kYAqHZEZ-1617692347005)]

缓存

show variables like ‘query_cache%’;

分区

如果数据过大,可以通过分区提高速度

建表语句

partition by key(id) partitions 5;

explain

在 MySQL 语句前面加上 explain,会解析执行过程

[外链图片转存中…(img-1ht8r7cv-1617692347006)]

多并发

原子性

Apache 测试多线程工具 ab.exe

ab.exe -c 10 -n 100 [url]

[外链图片转存中…(img-otNIEI3G-1617692347007)]

经过一千次测试,发现数据会有一定偏差

解决方法

MySQL 锁

就是把多线程在锁内变成了单线程

[外链图片转存中…(img-yzPEFuo2-1617692347008)]

文件锁

阻塞式,悲观锁

[外链图片转存中…(img-7s06YrSG-1617692347008)]

redis处理多并发

非阻塞式,乐观锁,比如抢 100 次(请求100次),有的成功有的失败

[外链图片转存中…(img-dpPlGt4p-1617692347009)]

高并发WEB架构

针对高并发需求的在不同层有众多优化技术

业务展示层

(cdn加速,动静分离,页面压缩)

CDN 就是内容分发网络,在各处放置服务器来构成一层智能虚拟网络,此处服务器称之为节点服务器,它会自动根据用户请求信息把请求重新分配到离客户端最近的服务器

CDN的作用: 解决由于服务端与客户端所在区域的不同,导致影响数据传输速度和稳定性问题,一句话总结就是让数据传输更快更稳定

逻辑处理层

页面静态化(ob系列函数)

并发请求处理(swoole扩展)

消息队列(Kafka,ActiveMQ)

数据处理层

数据缓存

主从复制

读写分离

负载均衡

web 服务器集群

  • 3
    点赞
  • 3
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值