Linux限制目录大小
需求情景:
存放日志或接收并存储数据的目录,为了防止程序出错时疯狂写日志硬盘被日志或存储的数据塞满。
原理,创建一个固定大小的img文件,映射成一个目录
1 | # 创建Log.img大小1G |
需求情景:
存放日志或接收并存储数据的目录,为了防止程序出错时疯狂写日志硬盘被日志或存储的数据塞满。
原理,创建一个固定大小的img文件,映射成一个目录
1 | # 创建Log.img大小1G |
参考:https://blog.csdn.net/sanve/article/details/80882731
安装
1 | apt install pptpd |
配置IP
1 | vim /etc/pptpd.conf |
查找并解开这3处的注释并修改相应配置
1 | #bcrelay eth1 |
bcrelay的意思我理解是来自虚拟局域网的广播要从哪个物理网卡转发出去
localip的意思本机是VPN服务器的IP地址
remoteip的意思是当有远程VPN客户端连接上来时被分配的IP段
我认为应该把虚拟局域网的网段和物理局域网分开,而且localip和remoteip应该在同一个网段,网上有localip和remoteip不应该在同一个网段的说法我并不认同。
配置DNS
1 | vim /etc/ppp/pptpd-options |
找到ms-dns解开注释并修改相应配置
1 | ms-dns 114.114.114.114 |
配置用户名密码
1 | vim /etc/ppp/chap-secrets |
1 | # Secrets for authentication using CHAP |
修改配置后重启PPTP服务器
1 | service pptpd restart |
打开IPv4转发
1 | vim /etc/sysctl.conf |
找到并修改或添加
1 | net.ipv4.ip_forward = 1 |
使配置生效
1 | sysctl -p service |
在网关上添加指向VPN网段的静态路由,设置下一跳地址为架设VPN服务器主机的IP,这样整个局域网都是可以通过VPN正常访问的。
如果没有操作网关的权限,也可以在需要访问的主机上添加静态路由
1 | ip route add 192.168.10.0/24 via 192.168.1.99 |
这里192.168.1.99就是架设VPN服务器的主机IP
参考:https://www.jianshu.com/p/1680c721f397 http://www.linuxfly.org/post/641/
1 | pptpsetup --create 连接名 --server VPN服务器地址 --username 用户名 --password 密码 --encrypt |
启动VPN连接
1 | pon 连接名 |
关闭VPN连接
1 | poff 连接名 |
查看路由表
1 | route -n |
添加路由,将通过VPN接入的物理局域网网段路由指定通过ppp0网口转发
1 | route add -net 192.168.1.0 netmask 255.255.255.0 dev ppp0 |
每次重连后路由会丢失,需要重新配置,可以用下面的方法在ppp0 up时自动添加路由
参考:https://blog.csdn.net/qq_27434019/article/details/102920504
1 | vim /etc/ppp/peers/连接名 |
增加ipparam一行
1 | ipparam 连接名 |
下面这步似乎不必要,不清楚作用
1 | vim /etc/network/interfaces |
增加
1 | auto tunnel |
======================================
新建脚本文件并修改权限
1 | touch /etc/ppp/ip-up.d/连接名 |
编辑脚本
1 | vim /etc/ppp/ip-up.d/连接名 |
在脚本中加入添加路由的语句
1 | route add -net 192.168.1.0 netmask 255.255.255.0 dev ppp0 |
可以poff 再 pon 再 route -n 看看路由是否自动添加
服务器其他用户反馈读取数据库很卡。
通过 sar -d -p 3
命令发现硬盘占用率比较高
通过 iotop
命令发现主要是被一个名为 [jbd2/sda2-8] 的进程占用
网上说法是 (13条消息) 性能分析之IO分析-jbd2引起的IO高_hualusiyu的专栏-CSDN博客
1 | jbd2的全称是journaling block driver 。这个进程实现的是文件系统的日志功能,磁盘使用日志功能来保证数据的完整性。这个需要评估一下安全和性能哪个更重要,解决方案是升级内核或者牺牲完整性来换性能。 |
差点被误导。
而使用命令 atop -d
发现其实是 snapd 占用
和这篇帖子情况一样 snapd持续运行,引起jbd2/sda2-8持续访问硬盘,占用大量io - Ubuntu中文论坛
1 | [#6](https://forum.ubuntu.org.cn/viewtopic.php?p=3221983#p3221983) |
snapd是ubuntu预装的一个软件包管理工具。
使用 snap list
发现只有一个core,也就是我没有基于snap安装过软件包。
通过 service snapd stop
关闭snapd,再通过 sar -d -p 3
观察硬盘占用,已经完全正常
至此确定是由snapd引发.
通过service snapd start 启动snapd,观察硬盘占用,先是再次上升数十秒后回到了正常。
如果下次再出现占用过高准备禁用或卸载snap。
禁用 systemctl disable snapd.service
卸载 apt purge snapd
相关命令
持续观察硬盘读写情况,每3秒刷新一次
1 | sar -d -p 3 |
sar常用的的参数还有监控CPU情况的
1 | sar -u 3 |
按IO从高到低排序监控进程,实时刷新
1 | iotop |
也能按IO从高到低排序,实时刷新,感觉比iotop好用
1 | atop -d |
atop也有监控CPU情况的
1 | atop -u |
在需要被挂载的服务器上安装nfs-kernel-server
1 | sudo apt install nfs-kernel-server |
通过此文件配置共享目录,样例
1 | # /etc/exports: the access control list for filesystems which may be exported |
这里配置了/data/share为共享目录,允许从192.168.1.157进行读写操作,允许从其他任意IP进行只读操作。
把共享目录的owner改成 nobody:nogroup
1 | sudo chown nobody:nogroup /data/share |
设置共享目录的权限
1 | sudo chmod 777 /data/share |
重新加载配置文件
1 | sudo exportfs -a |
在需要挂载的服务器需要安装nfs-common
1 | apt install nfs-common |
挂载命令样例 ,把140上的/data/share共享目录挂载到本地/mnt/140share
1 | mount 192.168.1.140:/data/share /mnt/140share |
使用到的端口,如果有防火墙需要设置
111/tcp+udp
2049/tcp
不同版本的NFS服务器也可能需要更多
1 | Data ONTAP: |
另外可能用到一个随机端口,在/etc/default/nfs-kernel-server中通过
1 | RPCMOUNTDOPTS="--port 33333" |
可以使之固定为33333。
更改设置后重启服务
1 | service nfs-kernel-server restart |
如果希望系统启动时自动加载文件系统
通过此文件配置系统启动时自动挂载
样例
1 | # <file system> <mount point> <type> <options> <dump> <pass> |
重新加载配置文件
1 | sudo mount -a |
配置中type是被挂载的路径的类型
常用的类型有:
nfs表示远程linux的共享路径
cifs表示远程windows的共享路径
ext4表示本地ext4路径
配置中options是挂载选项,在挂载windows目录时,通过以下方式指定用户名和密码
1 | defaults,auto,username=MZhDai,password=******,dir_mode=0777,file_mode=0777 |
另外挂载windows目录需要 mount.cifs 支持,如果没有可以通过以下命令安装
1 | sudo apt install cifs-utils |
挂载命令通过 -o指定选项
1 | sudo mount.cifs //192.168.1.107/f /mnt/107f -o user=MZhDai,pass=******,dir_mode=0777,file_mode=0777 |
还有常用的选项如
1 | ro :只读挂载 |
.cifs 可以省略,mount命令会自动识别需要挂载的路径类型
执行
1 | ls /mnt |
或
1 | df -h |
时卡住
可以使用
1 | strace ls /mnt |
或
1 | strace df -h |
查看命令执行的过程,看看最终卡在哪一步,比如卡在访问/mnt/abc
1 | cat /proc/mounts |
1 | nfsstat -s |
1 | umount <挂载点> |
如果卡住试下强制卸载
1 | umount -f <挂载点> |
或
1 | umount -lf <挂载点> |
如果还是卸载失败可以看一下哪个进程在使用挂载点下的文件
1 | lsof|grep <挂载点> |
考虑杀死进程后再卸载
1 | mount.nfs XXX XXX -o nfsvers=3 |
一般是v4版本卡住,改用v3可以解决
增加nolock挂载参数
1 | mount.nfs XXX XXX -o nfsvers=3,nolock |
主服务器:192.168.1.99
从服务器:192.168.1.150
在主服务器创建repl用户
1 | CREATE ROLE repl login replication password 'd71ea3'; |
配置repl用户访问权限
1 | vim /etc/postgresql/10/main/pg_hba.conf |
1 | host replication repl 192.168.1.150/32 md5 |
配置主服务器
1 | vim /etc/postgresql/10/main/postgresql.conf |
1 | wal_level = replica |
归档命令不加入rsync也可以,只需要在建立主从同步时手动把完整备份之后的归档复制到从库,后面配置从库时候会提到。
我实际使用的归档命令还加入了自动删除旧数据
1 | archive_command = 'DIR=/var/lib/postgresql/archivedir; test ! -f $DIR/%f && cp --preserve=timestamps %p $DIR/%f; find $DIR -type f -mtime +31|xargs rm -f' |
重启服务
1 | service postgresql restart |
停止服务
1 | service postgresql stop |
删除所有数据
1 | cd /var/lib/postgresql/10/main |
配置从服务器
1 | vim /etc/postgresql/10/main/postgresql.conf |
1 | hot_standby = on |
切换到postgres用户
1 | sudo su - postgres |
从主服务器创建初始备份,上面切换用户是为了不用调整文件权限
pg_basebackup -h 192.168.1.99 -U repl -D /var/lib/postgresql/10/main -F p -X stream -P -R -p 5432
Password: d71ea3
会自动生成 recovery.conf 启动之后会读取里面的配置进行主从同步
切回root
1 | sudo su - |
如果前面主服务器归档命令没有加入rsync,那么我们现在在主服务器上 复制最近一天内修改过的归档文件到从服务器
1 | cd /var/lib/postgresql/archivedir |
相当于整体上从库建立起同步需要的数据 = 完整备份 + 归档文件 + WAL缓存
从服务器启动服务
1 | service postgresql start |
从主服务器查看从服务器同步状态
1 | select application_name, sync_state from pg_stat_replication; |
查看系统进程运行状态,包括服务
1 | systemctl status |
所有可用的单元文件存放在 /lib/systemd/system/ 和 /etc/systemd/system/ 目录。
根据我的实验情况是我们应该在/lib/systemd/system/ 下存放.service文件,当设置了自启动后,会自动在 /etc/systemd/system/ 下创建一个软链接指向 /lib/systemd/system/ 下的文件。
查看所有已安装服务:
1 | systemctl list-units --type=service |
通过服务状态可以查看启动服务的.service配置文件
例如
1 | service mongodb status |
可以看到
1 | /lib/systemd/system/mongodb.service |
最重要的,运行命令,
1 | ExecStart=/usr/bin/mongod --unixSocketPrefix=${SOCKETPATH} --config ${CONF} $DAEMON_OPTS |
PS:要注意的是ExecStart指定的是一个阻塞的程序,不需要后台执行,如果不阻塞,服务会认为程序执行完了,认为服务不在启动状态。
以Kafka为例
1 | [Unit] |
详细的.service文件编写方法可以参考 http://www.jinbuguo.com/systemd/systemd.service.html
修改服务配置文件后需要
1 | systemctl daemon-reload |
设置服务开机自启动
1 | systemctl enable postgresql.service |
查询是否自启动服务
1 | systemctl is-enabled postgresql.service |
取消服务器开机自启动
1 | systemctl disable postgresql.service |
Alembic需要SQLAlchemy支持,如果项目是使用Python基于SQLAlchemy的开发的,那么可以用Alembic管理数据库版本变化。
Alembic将版本间的一组变化称为一个迁移,将变化过程称为迁移。我们可以说从一个版本迁移到另一个版本。
我们先新建一个目录alembic
1 | alembic init <YOUR_ALEMBIC_DIR> |
例如
alembic init alembic_foo,foo可以是项目的数据库名
有两个文件需要修改
alembic.ini
alembic_foo/env.py
在 alembic.ini
中修改sqlalchemy.url
例如 sqlalchemy.url = postgresql+psycopg2://用户名:密码@ip_address/dbname
在 env.py
修改 # target_metadata = mymodel.Base.metadata
修改把项目中用来定义数据模型基类的Base import进来,改成 target_metadata = Base.metadata,以便Alembic知道项目中有哪些表,表结构是什么
1 | alembic revision --autogenerate -m <log_message> |
我都是用日期和时间作为log_message,例如
1 | alembic revision --autogenerate -m "%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%" |
自动生成迁移的时候,Alembic会对比数据库现有的表结构和配置的Base.metadata对应的表结构,生成差异转换代码,我们首次生成的时候一般两边是一致的,所以生成的迁移脚本其实是什么都不做。
执行上面的命令可以看到会生成 alembic_foo/versions/xxxx.py
,其中xxx就是revision+log_message
1 | """20200326 91627 |
1 | alembic upgrade head |
其实会做一遍upgrade中的命令,现在为空就什么都不做。
其实alembic做了一件事,在数据库中创建了一张名为alembic_version的表,里面只有一行一列记录着当前的数据库版本
以后要修改数据库模型时的步骤如下:
(1)修改SQLAlchemy Base那边的代码,即通过ORM框架定义的表示数据表结构的Python类。
(2)执行 alembic revision --autogenerate ...
命令生成迁移脚本。
(3)检查自动生成的脚本,改成不准确的地方。(例如重命名会变成删除再添加,会丢失数据)
(4)执行 alembic upgrade head
把改动应用到数据库
升级到最新前面已经说过了
1 | alembic upgrade head |
要指定版本的话,看到前面自动生成的py文件里面有个Revision ID,同时也是py文件的前缀。
升级到指定版本
1 | alembic upgrade <Revision ID> |
降级到指定版本
1 | alembic downgrade <Revision ID> |
参考:
监视主线程卡死,卡死时保错再主动崩溃退出,同时打印当时的调用堆栈。
还可以再外部结合监视崩溃自动重启就可以在卡死时实现自动重启。
1 | import threading |
1 | @watch_dog(timeout=3, echo=True) |
我们监视func,设置其3秒超时,然后在里面sleep 5秒来引起超时,可以看到输出如下
1 | !!!!! WATCH DOG FAILURE TRIGGERED !!!!! |
在程序启动3.5秒后就主动崩溃了
1 | def main(): |
输出如下
1 | i=0 |
1 | import multiprocessing |
通过
1 | tzselect |
修改时区
根据屏幕提示选择选到 Asia/Shanghai 我这里是按4-9-1
然后把
1 | TZ='Asia/Shanghai'; export TZ |
加入到 .profile
中保证重启后有效
修改 /etc/localtime 链接到的文件
1 | ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime |
修改 /etc/timezone 的文件内容
1 | echo Asia/Shanghai > /etc/timezone |
如果在第一步tzselect就报错,需要先安装tzdata,也可以用下面的命令一步到位
1 | export TZ=Asia/Shanghai \ |
通过driver可以进行类似ActiveObject模式的设计,在此基础上还实现了通用的消息机制,基于driver进行编程可以充分的解耦。
1 | # -*- coding: utf-8 -*- |