一、数据表使用 uuid 作为主键,需要注意哪些事情?

可以在 boot 方法中增加生成 uuid 为主键的方法。如果在生成主键之后需要获取 id,那么需要设置 $incrementing = false。具体如下:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Uuid;

class Order extends Model
{

    public $incrementing = false;

    /**
     *  Setup model event hooks
     */
    public static function boot()
    {
        parent::boot();
        self::creating(function ($model) {
            $model->id = (string) Uuid::generate(4);
        });
    }
}

二、路由变量含有“/”,该如何定义路由?

有时候,我们需要在路由中传入复杂的变量,比如一段路径,这个时候可以通过在 routeServiceProvider 中定义一个 pattern 来实现变量被正确的解析。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{

    protected $namespace = 'App\Http\Controllers';

    public function boot()
    {
        //
        Route::pattern('path', '[a-zA-Z0-9-_/.:\?]+');
        parent::boot();
    }

}

这样,比如有以下一张动态剪裁的图片,图片的 path 为:

images/201911/bd484d1ef139b1d7f257d6f96baa3ac2.jpeg

构造的 url 为:

http://inspection.test/image/500x335/90/1/c296c89eb4c0fe68/images/201911/bd484d1ef139b1d7f257d6f96baa3ac2.jpeg

路由就可以这样定义了:

Route::get('/image/{width}x{height}/{quality}/{type}/{signature}/{path}', "[email protected]");

三、laravel 的 访问控制策略

laravel 提供了针对模型数据访问控制的方法,称之为 Policy,通过定义 Policy,我们可以非常方便的解决细粒度的权限问题。

比如,我们允许用户编辑,删除自己的文章,而不能编辑和删除他人的文章,这个该怎么做呢?

一般情况下,我们需要在控制器的代码段中做一下判断,判断一下该文章是否属于该用户,在这里 laravel 帮我们做了很好的封装,可以非常方便的定义这样的访问控制

3.1 第一步: 生成策略
使用 artisan 命令,可以生成一个策略类,该类默认被写入到 AppPolicies 目录下:

php artisan make:policy PostPolicy

所生成的类,大致上是这样的:

<?php

namespace App\Policies;

use App\User;
use App\Post;

class PostPolicy
{
    /**
     * 判断该方法能否被用户操作。
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return bool
     */
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

3.2 第二步: 注册策略

一旦策略存在,它就需要进行注册。新的 Laravel 应用中包含的 AuthServiceProvider 有一个 policies 属性,可以将各种模型对应到它们的策略中。注册一个策略将引导 Laravel 在授权动作访问指定模型的时候使用哪种策略:

<?php

namespace App\Providers;

use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * 应用的策略映射。
     *
     * @var array
     */
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    /**
     * 注册任意应用认证、应用授权服务
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
    }
}

3.3 第三步: 执行策略

  • 通过控制器:
$this->authorize('create', Post::class);
  • 通过中间件:
Route::post('/post', '[email protected]')->middleware('can:update,post');
  • 通过模版:
@can('update', $post)
    <!-- The Current User Can Update The Post -->
@elsecan('create', App\Post::class)
    <!-- The Current User Can Create New Post -->
@endcan

一、PBN 是什么?

PBN 是英文 Private Blog Network 的缩写,中文意思大致是“秘密博客网络”,建立多个站点,形成一个网络,然后用这个网络给目标网站建立外链,用于给目标网站的页面增加权重。因为这属于 SEO 作弊,不希望被搜索引擎发现,所以号称是秘密的。

PBN,在国内也被称为站群,是一种高风险高投入高回报的 SEO 手段,属于黑帽SEO的范畴,具有被 Google K站的风险,当然,这种方法所带来的效果也非常明显,是有效的 SEO 高级手段。

但是,不得不说,这条路难度系数也很高,需要很多资源的支持。

二、PBN 的基本原理

那么 PBN 是怎么样给目标网站增加权重呢?

核心思想是这样子:PBN 中的每个站的域名都会有权重。通过在这个站做直接的外链去目标网站的目标页面,就能把这个站本身的权重值传递给目标站。一般是直接用一级外链指向目标网站,为了安全起见,可以选择把站群的外链作为二级外链,从而进一步规避风险。

三、PBN 怎么做?

不得不说,这是一件非常复杂且非常讲究的事情,大体上来说,至少包含以下几个方面:

  1. 购买高权重域名
  2. 购买服务器资源
  3. 制作站点
  4. 部署站点
  5. 通过链接传递权重

删除文件,空间并未释放

linux某个目录空间快满了,删除了若干的文件后,使用 df -h 显示还是快满的,但是 df -h * 显示的总的文件大小又没那么大。

某个进程正在使用删除的文件,导致删除后,空间仍然不能释放。

查看rm掉但是仍被占用的文件的列表,使用如下命令:

lsof |grep -i deleted

再使用 ps -aux | grep pid 查到对应的进程号,关闭进程或者 kill 进程,再次查看空间已释放。

lsof命令是什么?

可以列出被进程所打开的文件的信息。被打开的文件可以是

1.普通的文件
2.目录
3.网络文件系统的文件
4.字符设备文件
5.(函数)共享库
6.管道,命名管道
7.符号链接
8.底层的socket字流,网络socket,unix域名socket
9.在linux里面,大部分的东西都是被当做文件的…..还有其他很多

怎样使用lsof

这里主要用案例的形式来介绍lsof 命令的使用

1.列出所有打开的文件:

lsof

备注: 如果不加任何参数,就会打开所有被打开的文件,建议加上一下参数来具体定位

  1. 查看谁正在使用某个文件

lsof /filepath/file

3.递归查看某个目录的文件信息

lsof +D /filepath/filepath2/

备注: 使用了+D,对应目录下的所有子目录和文件都会被列出

  1. 比使用+D选项,遍历查看某个目录的所有文件信息 的方法

lsof | grep ‘/filepath/filepath2/’

  1. 列出某个用户打开的文件信息

lsof -u username

备注: -u 选项,u其实是user的缩写

  1. 列出某个程序所打开的文件信息

lsof -c mysql

备注: -c 选项将会列出所有以mysql开头的程序的文件,其实你也可以写成 lsof | grep mysql, 但是第一种方法明显比第二种方法要少打几个字符了

  1. 列出多个程序多打开的文件信息

lsof -c mysql -c apache

  1. 列出某个用户以及某个程序所打开的文件信息

lsof -u test -c mysql

  1. 列出除了某个用户外的被打开的文件信息

lsof -u ^root

备注:^这个符号在用户名之前,将会把是root用户打开的进程不让显示

  1. 通过某个进程号显示该进行打开的文件

lsof -p 1

  1. 列出多个进程号对应的文件信息

  lsof -p 123,456,789

  1. 列出除了某个进程号,其他进程号所打开的文件信息

  lsof -p ^1

13 . 列出所有的网络连接

  lsof -i

  1. 列出所有tcp 网络连接信息

  lsof -i tcp

  1. 列出所有udp网络连接信息

  lsof -i udp

  1. 列出谁在使用某个端口

  lsof -i :3306

  1. 列出谁在使用某个特定的udp端口

  lsof -i udp:55

特定的tcp端口

  lsof -i tcp:80

  1. 列出某个用户的所有活跃的网络端口

  lsof -a -u test -i

  1. 列出所有网络文件系统

  lsof -N

20.域名socket文件

  lsof -u

  21.某个用户组所打开的文件信息

  lsof -g 5555

  22. 根据文件描述列出对应的文件信息

  lsof -d description(like 2)

  23. 根据文件描述范围列出文件信息

  lsof -d 2-3

想在 mac 上使用 ubuntu 的共享目录,方便对文件和目录的操作,不知道什么原因通过 smb 不能正常访问。

通过搜索,发现 mac 还提供了一个 afp 协议可以用于共享文件夹。

以下操作可以让 Mac 访问 Ubuntu 中的文件,亲测好用。

在Ubuntu上安装 netatalk

sudo apt-get install netatalk

进行 netatalk 的配置

sudo vim /etc/default/netatalk

找到以下配置语句,去除注释。

ATALKD_RUN=no
PAPD_RUN=no
CNID_METAD_RUN=yes
AFPD_RUN=yes
TIMELORD_RUN=no
A2BOOT_RUN=no

配置分享文件夹

sudo vim /etc/netatalk/AppleVolumes.default

~/                            "Home Directory"
/data/                        "data dir for share"

重启nettalk服务

sudo /etc/init.d/netatalk restart

在Mac上进行连接

atp://192.168.yourip

redis 默认安装启动之后,如果查看 redis 日志,经常会报几条警告,这些警告与 linux 操作系统的配置有关系。如果忽略它们,有可能会造成 redis 在运行过程中异常。

具体的报警信息如下:

27967:M 23 Jul 03:48:38.410 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
27967:M 23 Jul 03:48:38.410 # Server started, Redis version 3.0.6
27967:M 23 Jul 03:48:38.410 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
27967:M 23 Jul 03:48:38.410 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

解决办法如下:

一、修改 /etc/sysctl.conf

在配置文件末尾增加如下两行:

net.core.somaxconn=65535
vm.overcommit_memory=1

二、重新载入 sysctl 配置,使配置生效

sysctl --system

三、处理 transparent_hugepage

echo never > /sys/kernel/mm/transparent_hugepage/enabled

四、处理 maximum open files

启动 redis 的时候,还可能遇到这个问题,使用 ulimit -n 明明设置的都是比较大大值,比如 10240,但是似乎 redis 无法识别这个设置,始终会报如下警告:

Redis can't set maximum open files to 10032 because of OS error: Operation not permitted.

此时,你需要修改 /etc/pam.d/ 目录下的 sudo 文件, 添加如下行:

session required pam_limits.so

这将会帮助使得 /etc/security/limits.conf 中的设置生效。

五、vm.overcommit_memory 原理

Redis在启动时可能会出现这样的日志:

# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the 
command 'sysctl vm.overcommit_memory=1' for this to take effect.

在分析这个问题之前,首先要弄清楚什么是overcommit?Linux操作系统对大部分申请内存的请求都回复yes,以便能运行更多的程序。因为申请内存后,并不会马上使用内存,这种技术叫做overcommit。如果Redis在启动时有上面的日志,说明vm.overcommit_memory=0,Redis提示把它设置为1。

vm.overcommit_memory用来设置内存分配策略,它有三个可选值,如下表所示。

vm.overcommit_memory 含义
0 表示内核将检查是否有足够的可用内存。如果有足够的可用内存,内存申请通过,否则内存申请失败,并把错误返回给应用进程
1 表示内核允许超量使用内存直到用完为止
2 表示内核决不过量的(“never overcommit”)使用内存,即系统整个内存地址空间不能超过swap+50%的RAM值,50%是overcommit_ratio默认值,此参数同样支持修改

注意:本文的可用内存代表物理内存与swap之和。
日志中的Background save代表的是bgsave和bgrewriteaof,如果当前可用内存不足,操作系统应该如何处理fork。如果vm.overcommit_memory=0,代表如果没有可用内存,就申请内存失败,对应到Redis就是fork执行失败,在Redis的日志会出现:

Cannot allocate memory

Redis建议把这个值设置为1,是为了让fork能够在低内存下也执行成功。

5.2. 获取和设置

获取:

cat /proc/sys/vm/overcommit_memory

设置:

echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1

5.3. 最佳实践

Redis设置合理的maxmemory,保证机器有20%~30%的闲置内存。
集中化管理 aof 重写和 rdb 的 bgsave。
设置vm.overcommit_memory=1,防止极端情况下,会造成fork失败。

六. Transparent Huge Pages 原理

Redis在启动时可能会看到如下日志:

WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

从提示看Redis建议修改Transparent Huge Pages (THP)的相关配置,Linux kernel在2.6.38内核增加了Transparent Huge Pages (THP)特性 ,支持大内存页(2MB)分配,默认开启。当开启时可以降低fork子进程的速度,但fork之后,每个内存页从原来4KB变为2MB,会大幅增加重写期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询。例如简单的incr命令也会出现在慢查询中。因此Redis日志中建议将此特性进行禁用,禁用方法如下:

echo never >  /sys/kernel/mm/transparent_hugepage/enabled

而且为了使机器重启后THP配置依然生效,可以在/etc/rc.local中追加

echo never > /sys/kernel/mm/transparent_hugepage/enabled。

在设置THP配置时需要注意:有些Linux的发行版本没有将THP放到/sys/kernel/mm/transparent_hugepage/enabled中,例如Red Hat 6以上的THP配置放到/sys/kernel/mm/redhat_transparent_hugepage/enabled中。而Redis源码中检查THP时,把THP位置写死。

FILE *fp = fopen("/sys/kernel/mm/transparent_hugepage/enabled","r");
if (!fp) return 0;

所以在发行版中,虽然没有THP的日志提示,但是依然存在THP所带来的问题。

echo never >  /sys/kernel/mm/redhat_transparent_hugepage/enabled

七、TCP backlog 原理

Redis默认的tcp-backlog为511,可以通过修改配置 tcp-backlog 进行调整,如果 Linux 的 tcp-backlog 小于Redis设置的 tcp-backlog,那么在Redis启动时会看到如下日志:

# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

查看方法:

cat /proc/sys/net/core/somaxconn

修改方法:

echo 511 > /proc/sys/net/core/somaxconn