Laravel Eloquent: 复制一行

首先我们需要有一张表:

Schema::create('tasks', function (Blueprint $table) {
    $table->increments('id');
    $table->string('task');
    $table->text('description');
    $table->timestamps();
    $table->softDeletes();
});

建一个 Model:

class Tasks extends Model
{
    use SoftDeletes;
    protected $table = 'tasks';
    protected $fillable = ['task', 'description'];
}

在数据里我们有一个任务:

ReplicateDatabaseSingle

接下来我们运行下面的代码来复制一行:

$tasks = Tasks::find(1);
$newTask = $tasks->replicate();
$newTask->save();

我们可以看到我们数据库里面的这一行已经复制成功了,有新的 idtimestamps

你只需要一行代码就可以复制很多数据,这个方法在循环中也有效,所以你可以用它复制所有的数据了。

SSH 命令的三种代理功能(-L/-R/-D)

ssh 命令除了登陆外还有三种代理功能:

  • 正向代理(-L):相当于 iptable 的 port forwarding
  • 反向代理(-R):相当于 frp 或者 ngrok
  • socks5 代理(-D):相当于 ss/ssr

如要长期高效的服务,应使用对应的专用软件。如没法安装软件,比如当你处在限制环境下想要访问下某个不可达到的目标,或者某个临时需求,那么 ssh 就是你的兜底方案。

正向代理:

所谓“正向代理”就是在本地启动端口,把本地端口数据转发到远端。

用法1:远程端口映射到其他机器

HostB 上启动一个 PortB 端口,映射到 HostC:PortC 上,在 HostB 上运行:

HostB$ ssh -L 0.0.0.0:PortB:HostC:PortC user@HostC

这时访问 HostB:PortB 相当于访问 HostC:PortC(和 iptable 的 port-forwarding 类似)。

用法2:本地端口通过跳板映射到其他机器

HostA 上启动一个 PortA 端口,通过 HostB 转发到 HostC:PortC上,在 HostA 上运行:

HostA$ ssh -L 0.0.0.0:PortA:HostC:PortC  user@HostB

这时访问 HostA:PortA 相当于访问 HostC:PortC。

两种用法的区别是,第一种用法本地到跳板机 HostB 的数据是明文的,而第二种用法一般本地就是 HostA,访问本地的 PortA,数据被 ssh 加密传输给 HostB 又转发给 HostC:PortC。

反向代理:

所谓“反向代理”就是让远端启动端口,把远端端口数据转发到本地。

HostA 将自己可以访问的 HostB:PortB 暴露给外网服务器 HostC:PortC,在 HostA 上运行:

HostA$ ssh -R HostC:PortC:HostB:PortB  user@HostC

那么链接 HostC:PortC 就相当于链接 HostB:PortB。使用时需修改 HostC 的 /etc/ssh/sshd_config,添加:

GatewayPorts yes

相当于内网穿透,比如 HostA 和 HostB 是同一个内网下的两台可以互相访问的机器,HostC是外网跳板机,HostC不能访问 HostA,但是 HostA 可以访问 HostC。

那么通过在内网 HostA 上运行 ssh -R 告诉 HostC,创建 PortC 端口监听,把该端口所有数据转发给我(HostA),我会再转发给同一个内网下的 HostB:PortB。

同内网下的 HostA/HostB 也可以是同一台机器,换句话说就是内网 HostA 把自己可以访问的端口暴露给了外网 HostC。

按照前文《韦易笑:内网穿透:在公网访问你家的 NAS》中,相当于再 HostA 上启动了 frpc,而再 HostC 上启动了 frps。

本地 socks5 代理

在 HostA 的本地 1080 端口启动一个 socks5 服务,通过本地 socks5 代理的数据会通过 ssh 链接先发送给 HostB,再从 HostB 转发送给远程主机:

HostA$ ssh -D localhost:1080  HostB

那么在 HostA 上面,浏览器配置 socks5 代理为 127.0.0.1:1080,看网页时就能把数据通过 HostB 代理出去,类似 ss/ssr 版本,只不过用 ssh 来实现。

使用优化

为了更好用一点,ssh 后面还可以加上:-CqTnN 参数,比如:

$ ssh -CqTnN -L 0.0.0.0:PortA:HostC:PortC  user@HostB

其中 -C 为压缩数据,-q 安静模式,-T 禁止远程分配终端,-n 关闭标准输入,-N 不执行远程命令。此外视需要还可以增加 -f 参数,把 ssh 放到后台运行。

这些 ssh 代理没有短线重连功能,链接断了命令就退出了,所以需要些脚本监控重启,或者使用 autossh 之类的工具保持链接。

功能对比

正向代理(-L)的第一种用法可以用 iptable 的 port-forwarding 模拟,iptable 性能更好,但是需要 root 权限,ssh -L 性能不好,但是正向代理花样更多些。反向代理(-R)一般就作为没有安装 frp/ngrok/shootback 时候的一种代替,但是数据传输的性能和稳定性当然 frp 这些专用软件更好。

socks5 代理(-D)其实是可以代替 ss/ssr 的,区别和上面类似。所以要长久使用,推荐安装对应软件,临时用一下 ssh 挺顺手。

补充下 iptable 的 port-forwarding 怎么设置,十分管用的功能,两个函数即可:

#! /bin/sh

# create forward rule by source interface
# http://serverfault.com/questions/532569/how-to-do-port-forwarding-redirecting-on-debian
PortForward1() {
    local IN_IF=$1
    local IN_PORT=$2
    local OUT_IP=$3
    local OUT_PORT=$4
    local IPTBL="/sbin/iptables"
    echo "1" > /proc/sys/net/ipv4/ip_forward
    $IPTBL -A PREROUTING -t nat -i $IN_IF -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
    $IPTBL -A FORWARD -p tcp -d $OUT_IP --dport $OUT_PORT -j ACCEPT
    $IPTBL -A POSTROUTING -t nat -j MASQUERADE
}

# create forward rule by source ip
# http://blog.csdn.net/zzhongcy/article/details/42738285
ForwardPort2() {
    local IN_IP=$1
    local IN_PORT=$2
    local OUT_IP=$3
    local OUT_PORT=$4
    local IPTBL="/sbin/iptables"
    echo "1" > /proc/sys/net/ipv4/ip_forward
    $IPTBL -t nat -A PREROUTING --dst $IN_IP -p tcp --dport $IN_PORT -j DNAT --to-destination ${OUT_IP}:${OUT_PORT}
    $IPTBL -t nat -A POSTROUTING --dst $OUT_IP -p tcp --dport $OUT_PORT -j SNAT --to-source $IN_IP
}

第一个函数是按照网卡名称设置转发:

PortForward1 eth1 8765 202.115.8.2 8765

这时,本地 eth1 网卡的 8765 端口就会被转发给 202.115.8.2 的 8765 端口。

第二个函数是按照本机的 ip 地址,比如本机是 192.168.1.2:

PortForward2 192.168.1.2 8765 202.115.8.2 8765

那么任何访问本机 192.168.1.2 这个地址 8765 端口,都会被转发到 202.115.8.2:8765

这个 iptable 的 port forwarding 是内核层运行的,性能极好,只不过每次重启都需要重新设置下。

作者:韦易笑
链接:https://zhuanlan.zhihu.com/p/57630633
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/usr/lib64/libstdc++.so.6: version `GLIBCXX_xxx’ not found的解决办法

原因

缺少 GLIBCXX_3.4.14 对应的版本

创景

编译软件时,将gcc从4.4.7版本升级到4.8.2以便让其支持c++11标准,会出现这个问题

解决办法

使用strings命令来查看报错的动态库/usr/lib64/libstdc++.so.6中是否含有GLIBCXX_3.4.14

cp /usr/local/lib64/libstdc++.so.6.0.19 /usr/lib64/
cd /usr/lib64

ln -sf libstdc++.so.6.0.19 libstdc++.so.6 

参考:http://www.cnblogs.com/weinyzhou/p/4983306.html

MySQL replace

最近在业务中,在数据转换的时候需要用到 MySQL 的 replace 函数,这里简单介绍一下。

REPLACE(str,from_str,to_str) 

 
比如你要将表 t 里面的 name 字段的 x 替换为 z 

UPDATE t SET name=REPLACE(name, 'x', 'x'); 

logrotate 使用方法

logrotate 是默认安装的,一般会定时运行 logrotate,通常是每天一次;会通过 crontab 运行,也就是直接运行 /etc/cron.daily/logrotate 脚本。

配置文件

默认使用 /etc/logrotate.conf 文件,作为全局配置,而不同应用的具体配置则在 /etc/logrotate.d 目录下,通常以应用程序的名称命名,例如 nginx、mysql、syslog、yum 等配置。

如下,是一个配置文件的具体内容。


/var/log/nginx/*.log  /var/log/app/*.log{   # 可以指定多个路径
    daily                      # 日志轮询周期,weekly,monthly,yearly
    rotate 30                  # 保存30天数据,超过的则删除
    size +100M                 # 超过100M时分割,单位K,M,G,优先级高于daily
    compress                   # 切割后压缩,也可以为nocompress
    delaycompress              # 切割时对上次的日志文件进行压缩
    dateext                    # 日志文件切割时添加日期后缀
    missingok                  # 如果没有日志文件也不报错
    notifempty                 # 日志为空时不进行切换,默认为ifempty
    create 640 nginx nginx     # 使用该模式创建日志文件
    sharedscripts              # 所有的文件切割之后只执行一次下面脚本
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

当配置完成后,可以通过如下方式进行测试。

----- 可直接手动执行
$ logrotate --force /etc/logrotate.d/nginx

----- 显示详细的信息;而且--debug/-d实际上不会操作具体文件(Dry Run)
$ logrotate --debug -v -f /etc/logrotate.d/nginx

MySQL批量写数据,Prepared statement contains too many placeholders

最近业务调整,需要一次性插入大量的数据到表中的时候,报下面这个错误

 SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders.

查看MySQL官网的解释:

Error: 1390 SQLSTATE: HY000 (ER_PS_MANY_PARAM)

Message: Prepared statement contains too many placeholders

参考:https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html

原因分析:
mysql使用PDO进行写入的时候,PDO支持最大占位符为65535。

当insert的表为6列(即6个字段),写入记录的行数为11000时,则insert的总占位符为:6×11000=66000.

66000大于mysql最大占位符为65535,故而mysql报错。

结论:写入数据为m列,n行。m*n必须小于65535。

Kubernetes 无状态服务和有状态服务

无状态服务(Stateless Service)

是指该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一个请求响应的结果是完全一致的。

借助k8s内部的负载均衡Ingress,当访问该服务的请求到达服务一端后,负载均衡会随机找到一个实例来完成该请求的响应(目前为轮询)。这类服务的实例可能会因为一些原因停止或者重新创建(如扩容时),这些停止的实例里的所有信息(除日志和监控数据外)都将丢失(重启容器即会丢失)。因此如果您的容器实例里需要保留重要的信息,并希望随时可以备份以便于以后可以恢复的话,那么建议您创建有状态服务。

有状态服务(Stateful Service)

是指该服务的实例可以将一部分数据随时进行备份,并且在创建一个新的有状态服务时,可以通过备份恢复这些数据,以达到数据持久化的目的。

无状态服务可以有一个或多个实例,因此支持两种服务容量调节模式;有状态服务只能有一个实例,不允许创建多个实例,因此也不支持服务容量调节模式。