进程

程序是一些保存在磁盘上的指令的有序集合,是静态的。进程是程序执行的过程,包括了动态创建、调度和消亡的整个过程,进程是程序资源管理的最小单位。

程序资源:内存资源、IO资源、信号处理等

线程

线程是操作操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位,一个进程内可以包含多个线程,线程是资源调度的最小单位。

同一进程中的多条线程共享该进程中的全部系统资源,如虚拟地址空间,文件描述符文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈、寄存器环境、线程本地存储等信息。

线程创建的开销主要是线程堆栈的建立,分配内存的开销。这些开销并不大,最大的开销发生在线程上下文切换的时候。

协程

协程,英文Coroutines,是一种比线程更加轻量级的存在。类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程,因此协程又称微线程和纤程。

协程不是进程,也不是线程,它就是一个可以在某个地方挂起的特殊函数,并且可以重新在挂起处继续运行。所以说,协程与进程、线程相比,不是一个维度的概念。

参考: https://zhuanlan.zhihu.com/p/337978321


nginx

Nginx (“engine x”) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。

cgi,fast-cgi

也叫通用网关接口,是Web服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。

早期的webserver只能处理html等静态文件,无法处理动态语言(比如php程序),于是出现了cgi协议,只要按照cgi协议去编写程序,就能实现语言解释器与webwerver的通信。

但是该方法有个缺点,就是webserver每收到一个请求,都会去fork一个cgi进程,请求结束再kill掉这个进程。很明显这很浪费资源。

于是出现了fast-cgi。fast-cgi每次处理完请求后,不会kill掉这个进程,而是保留这个进程,使这个进程可以一次处理多个请求。

php-fpm

全称:php-Fastcgi Process Manager.

php-fpm是 FastCGI 的实现,并提供了进程管理的功能。

进程包含 master 进程和 worker 进程两种进程。

master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。

Nginx + php-fpm

nginx 接收请求,然后通过反向代理功能将动态请求转向后端Php-fpm。具体流程如下:

    请求
     |
    nginx
     |
    加载nginx fast-cgi模块
     |
    fast-cgi监听127.0.0.1:9000地址
     |
    请求到达127.0.0.1:9000
     |
    php-fpm 监听127.0.0.1:9000(master进程)
     |
    php-fpm 接收到请求,启用worker进程处理请求
     |
    php-fpm 处理完请求,返回给nginx
     |
    nginx将结果通过http返回给浏览器
    

nginx 相关命令

  • service nginx start
  • service nginx stop
  • service nginx restart
  • service nginx status
  • nginx -s reload

php-fpm 相关命令

  • service php7.3-fpm start
  • service php7.3-fpm stop
  • service php7.3-fpm restart
  • service php7.3-fpm status
  • php7.3-fpm -s reload

文章参考:

https://zhuanlan.zhihu.com/p/439799459

四大部件

  • router 路由:负责接收请求和发送响应,为Web应用程序提供网页和API接口。
  • controller:响应来自路由器的请求,处理数据并返回对应的视图(View)或数据模型(Model);
  • Model:操作和管理数据的一组类,负责从数据库和其他数据存储中检索数据,进行 CRUD 操作等;
  • Views: 提供给用户的Web界面,包括HTML和CSS样式。

目录结构

app				应用核心目录
bootstrap 		启动目录,用于载入配置文件,中间件等
config			配置文件目录。数据库,文件系统,cache等配置
database		数据库迁移文件以及填充文件
public			对外访问目录。index文件,静态资源等
resource		对应的视图文件以及为编译的前端资源,邮件模板,本地化语言文件
routes			路由目录。包括:web.php,api.php,console.php,changes.php。
storage 		文件存储目录。缓存文件,日志,上传文件
tests 			测试目录。自动化的测试脚本
Vendor			包含了应用通过composer 加载的依赖

这里只展示跟目录。具体参考:
https://laravelacademy.org/post/21960

请求原理

路由 => 中间件 => 控制器 => 模型 => 控制器 => 视图

  • 路由接受请求,检测是否有中间件,如果有中间件,先进入中间件做数据处理。比如登录,日志,频次检测;
  • 如果没有中间件或者中间件检测没问题后,据配置的路由规则,将请求交给控制器;
  • 控制器做一些参数之类的检查,如果需要调用数据,则调用相关模型获取数据;
  • 控制器将处理号的数据反馈给视图。

通常控制器做处理数据,有点臃肿和庞大,中间可以件一些Sevice层,专门封装相关业务处理。控制器只负责和调用这些封装好的对象。这样做更符合设计原则。




原理

对称加密是指加密和解密使用相同的密钥的加密算法。它的加密原理是将明文 (输入的机密信息) 通过密钥进行加密,然后再将加密后的密文发送出去。接收方收到密文后,使用相同的密钥进行解密,从而获得明文。对称加密的优点在于速度快,加密强度高,且密钥管理简单。但是,它也存在缺点,例如密钥管理不当会导致密钥泄露,攻击者可以轻松地破解加密信息。

非对称加密是指加密和解密使用不同的密钥的加密算法。它的加密原理是将明文通过非对称密钥进行加密,然后再将加密后的密文发送出去。接收方收到密文后,使用对称密钥进行解密,从而获得明文。非对称加密的优点在于加密强度高,攻击者需要付出极大的代价才能破解加密信息,而且密钥管理简单。但是,它也存在缺点,例如由于非对称密钥较长,加密速度较慢,且密钥管理不当会导致密钥泄露。

区别

对称加密: 发送方和接收方密钥一样, 速度快,容易被破解, 安全性差。常见的算法有DES、IDEA、RC2等

非对称加密:发送方和接收方密钥不一样,速度慢,不容易被破解,安全性好。私钥加密的内容只有公钥才能解开,公钥加密的内容只有私钥才能解开。也就是说,用其中一个钥匙加密,那么必须用另一个钥匙解密。常见的算法有RSA、DAS、ECC等。

密钥管理

对称加密和非对称加密的安全性都非常高,因为它们使用高强度的密钥进行加密,使得攻击者需要付出极大的代价才能破解。密钥管理是加密很重要的环节,以下建议可以更安全的管理密钥:

  • 将密钥放到更安全的地方,比如放到个人邮箱。不要随便放到一个桌面记事本。
  • 定期更换密钥;
  • 将存储的密钥通过某些手段加密,保证密钥的安全;

应用

支付应用:非对称加密更安全

服务端-》客户端的交互:对称加密,比如mqtt 数据加密,一般用des加密

class test
{
    private static $instance = null; //私有静态属性,存放该类的实例
 
    private function __construct() //私有构造方法,防止在类的外部实例化
    {
        echo 'construct';
    }
 
    // private function __clone() //私有克隆方法,防止克隆
    // {
    //     // Fatal error: Call to private TestSingleton::__clone() from context '' 外部clone时会报错
    // }
 
    public static function getInstance() //公共的静态方法,实例化该类本身,只实例化一次
    {
        // instanceof self 检测 变量是否为self的实例
        if (!self::$instance instanceof self) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function setSinVar ($sinVar) {
        $this->sinVar = $sinVar;
    }
 
    public function getSinVar() {
        return $this->sinVar;
    }
}


$test_a = test::getInstance();
$test_b = test::getInstance();
$test_c = clone $test_b;
 
$test_a->setSinVar('aaa');
$test_b->setSinVar('bbb');
$test_c->setSinVar('ccc');
 
echo '</br>';
echo $test_a->getSinVar()."\r";
echo '</br>';
echo $test_b->getSinVar()."\r";
echo '</br>';
echo $test_c->getSinVar()."\r";

输出:
//construct
//bbb
//bbb
//ccc


合成复用原则(Composite/Aggregate Reuse Principle,CARP)是指尽量使用对象组 合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵 活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。

继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱 复用,对类以外的对象是无法获取到实现细节的。要根据具体的业务场景来做代码设计, 其实也都需要遵循 OOP 模型。


demo:

文章,数据库操作。两个各自的对象封装。

文章不应该继承数据库类来达到数据的增删改查,而是通过聚合,实例化数据库类来直接使用。当然不同的数据库应该中间有个抽象层,底层有选择来决定调用那个数据库。

任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,即基类随便怎么改动子类都不受此影响,那么基类才能真正被复用

这就要求必须以下的规则:

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。


优点:

代码共享,即公共代码被抽到父类。

提高代码重用性。

子类在父类的基础上可以有自己的特性。

提高代码的扩展性。

缺点:

侵入性。一旦继承,父类全部属性和方法都被子类拥有

约束性。子类需要拥有父类的属性和方法,子类多了一些约束。

耦合性。父类出现修改情况时,需要考虑子类的修改。


现实中的demo:

比如你在数据库操作模型中写了一个基类的 查询。理论上这个查询只要继承了这个基类所有models都可以调用,所以子类调用的时候,如果子类重写了该方法并且更改了原来的功能。这个继承就变得不在有意义。


定义:

又叫最少知道原则,如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。

作用:

其目的是降低类之间的耦合度,提高模块的相对独立性。

反作用:

增加了系统的复杂度

定义:

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。

作用:

依赖倒置原则可以降低类间的耦合性;

依赖倒置原则可以提高系统的稳定性;

依赖倒置原则可以减少并行开发引起的风险;

依赖倒置原则可以提高代码的可读性和可维护性;

demo:

员工A 要给 员工B发送消息通知

最开始,我们发送消息的方法用的是通过邮件发送。发送动作是高层模块,邮件发送是底层模块。当有一天邮件模块不可用了,需要通过短信发送。 这个适合 原来高层模块无法发送。因为不支持短信。要是直接改邮件发送模块很显然不是对的。

优化方案:

中间加一层发送的抽象类接口。 高级发送模块只需要依赖与这个抽象类,而底层模块也应该依赖于这个抽象类。当更改了发送方案的情况下,只需要让不同的抽象类调用底层的发送接口即可。




定义:

接口隔离原则(Interface Segregation Principle,ISP)的定义是客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。简单来说就是建立单一的接口,不要建立臃肿庞大的接口。也就是接口尽量细化,同时接口中的方法尽量少。
接口隔离原则必须先满足单一原则。这里的接口单一指的是业务上的接口单一,单一原则指的是职责上的单一。

特点:

将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。


  • 如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。
  • 如果把“接口”理解为单个API接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。
  • 如果把“接口”理解为OOP中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。