最近测试服务器的数据库反复重启,产看日志, 提示

1
2
3
4
InnoDB: Log scan progressed past the checkpoint lsn 377750615222
InnoDB: The log sequence number in ibdata files does not match
InnoDB: the log sequence number in the ib_logfiles!
InnoDB: Database was not shut down normally!

之后无知的把ib_logfile1和ib_logfile2删掉,数据库依然反复重启。查看MySQL文件目录格式及存放位置才知道这两个文件还是有用的。

之后想到一个办法是重建数据库,也就是将SQL全部导出,之后再重新导入。在使用mysqldump导出数据时,老是提示mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table, 原因还是数据库重启了。

参考官网[forcing-innodb-recovery]
(https://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html), 在/etc/my.cnf里配置innodb_force_recovery=3, 将数据库的SQL成功导出。

修改/etc/my.cnf里的datadir,在新的目录里重启MySQL, 之后使用mysql导入数据,数据库终于正常。

使用mysqldump导出test这个数据库的命令

1
mysqldump -h 127.0.0.1 -u root -p123456 test > test.sql

而使用mysql命令行工具导入

1
mysql -h 127.0.0.1 -u root -p123456 test < test.sql

联系作者

服务器上老是有人尝试破解root用户的SSH登录密码,要想办法解决。一个办法是屏蔽ip.

在/etc目录下存在hosts.allow和hosts.deny, 看名字就知道它们的意义。

  • hosts.allow指的是允许登录的ip
  • hosts.deny指的是不允许登录的ip
  • 两个文件配置后自动生效,不要重启什么服务,因为监控这两个文件的服务会自动加载两个文件里的内容
  • 添加了屏蔽ip后,在/var/log/secure里就可以看到效果
    如在/etc/hosts.allow里添加
    1
    sshd:101.71.255.*

则是允许101.71.255.*等ip地址SSH登录

在/etc/hosts.deny里添加

1
sshd:116.31.116.*

则是禁止116.31.116.*等ip地址SSH登录。

hosts.allow和hosts.deny里配置的地址如果出现重复,优先使用hosts.allow, 也就是允许该地址SSH登录。

在/etc/hosts.deny里还可以添加

1
sshd:all

此时,只有hosts.allow里配置的地址才允许SSH登录。在我看来, hosts.allow配置只有当hosts.deny配置了sshd:all才有意义。

其实解决暴力破解root用户密码的最好办法是禁止root用户SSH登录,而用普通用户登录,登录之后切换到root用户。

兼任运维以来,数据库出问题,文件系统出问题,也是运气差。目前来看,还有很多地方需要完善的,慢慢来吧。

联系作者

今天服务器上出现了无法写入viminfo文件 /root/.viminfo错误,网上有人说删除~/.viminf*.tmp即可,查看目录没有这些文件。

后来发现是文件都变成了只读,想到上午的时候ext3文件系统出了问题。在网上找到[http://www.ha97.com/5428.html], 执行df -lhT,知道是ext4文件系统
想执行fsck.ext4 -y /dev/vda1,但不允许。因为这是线上系统。

于是继续找,发现mount -o remount rw /, 当时提示mount: you must specify the filesystem type, 于是加上文件系统类型,执行mount -t ext4 -o remount rw /,之后提示
mount: cannot remount block device rw read-write, is write-protected
查看鸟哥的私房菜,使用鸟哥的命令
mount -o remount,rw,auto/, 没有反应。

于是求助UCloud的工作人员,他们建议重启服务器。等到晚上,重启服务器,系统就起不来了。于是只好找UCloud的工作人员。后来他们进入单用户模式,修复文件系统,重新mount之后,终于弄好了。

可是线上服务停机了一个多小时,因为是单点服务。看来得再加一台机器了。

参考资料

联系作者

当需要添加新的监控程序时,添加了配置后,需要重新加载,这样才能监控起来。此时supervisorctl update命令就派上用场了。

执行supervisorctl update命令后,添加的配置会加载到Supervisor里,这样就可以用Supervisor监控程序了。

发现program配置里有directory这个选项,目的是在启动程序时,让程序进入的目录。例如在使用gunicorn启动Django项目时,如果wsgi指定的路径使用/隔开,则会报importerror import by filename is not supported, 配置directory为wsgi所在的目录,问题就得到解决。

联系作者

在使用Django REST framework时,对接口加上权限限制是必不可少的,例如对于一篇文章,只有管理员和作者才有删除的权限,其它人只能有读取权限。此时Permissions就派上用场了。

REST framework提供了很多种权限,如IsAuthenticated,IsAdminUser等等,要定制permissions, 也是很容易的一件事。要定制permissions, 只需继承BasePermission,然后实现其中一个或者两个方法

  • has_permission(self, request, view)
  • has_object_permission(self, request, view, obj)

其中,has_permission是相对接口而言的,也就是在访问这个接口时,会进行权限检测。而has_object_permission是相对于对象而言的,只有访问对象时才会进行权限检测。

还有一个问题是,当实现自己的get_object并且需要进行权限检查时,不要忘记调用self.check_object_permissions(self.request, obj)

1
2
3
4
def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj

而对于访问对象进行权限检测时,一个好的方法是如果是安全方法如GET, HEAD等,则运行访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""


def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True

# Instance must have an attribute named `owner`.
return obj.owner == request.user

联系作者

kill命令主要用来杀进程,以前不懂,一只都用kill -9, 现在才发现打错特错。

最近在学习使用Supervisor管理进程,测试Supervisor被杀死之后的情况。发现用kill -9杀死Supervisor后,管理的进程会变成孤儿进程。于是请教the5fire, 他提供了一篇no use kill 9, 顿时解决了疑惑。

在Mac上 man kill看到如下说明

1
2
3
4
5
6
7
1       HUP (hang up)
2 INT (interrupt)
3 QUIT (quit)
6 ABRT (abort)
9 KILL (non-catchable, non-ignorable kill)
14 ALRM (alarm clock)
15 TERM (software termination signal)

kill -9的主要弊端是被杀的进程来不及善后处理就已经死了,这回留下很多问题。所以强烈建议不要使用kill -9来杀死进程, 而是使用kill -15

联系作者

用Supervisor管理进程里说过,当supervisor挂了之后,它管理的进程就给了init进程,之后supervisor再次启动,端口已经被绑定了,怎么破?目前还没有找到解决的办法。现在继续说说这个问题。

这里说当supervisor挂了之后,它管理的进程就给了init进程,这并不完全对。这里其实是我主动用kill命令把supervisor杀掉,而且是用kill -9, 此时supervisor来不及将被杀的信息告诉管理的进程就死了,于是管理的进程变成了孤儿进程。当使用kill -15杀死supervisor时,它管理的进程也会一起挂掉,这样进程所占的资源也来得及释放。supervisor下次就可以正常启动。

一篇错误的博客

linux 后台进程管理利器supervisor里看到

不带参数运行supervisord是以daemon方式运行
当supervisord以非daemon方式运行时,杀掉supervisord后,被监控的进程也退出了。
而以daemon方式运行,杀掉supervisord对被监控进程无影响

然后我在博客里找什么是带参数和不带参数

supervisord (以daemon方式启动)
或 supervisord -c /etc/supervisord.conf (非daemon)

后来看了supervisor的官方文档,知道supervisor是否以daemon方式启动,是在supervisord.conf的supervisord项里配置的。当配置了nodaemon=true时,就会以非daemon方式启动,而不是根据带参数和不带参数决定的。

而被监控的进程是否一起死掉,也是更加supervisor被杀的方式决定的。从这方面看,这篇博客真是错误连篇。

一些需要注意的地方

  • autorestart=true
    在program配置项里,最好加上这个配置项,让监控的程序在关闭后自动重启。我遇到过一个问题是,用kill -15把监控的进程杀掉,之后程序没有自动重启。原因是它的退出码是0, 而exitcodes的默认配置是0,2 此时程序不会自动重启。因为exitcodes里配置的是The list of “expected” exit codes for this program used with autorestart, 而autorestart默认配置是unexpected。

联系作者

一直卡在gopkg.in/inconshreveable/go-update.v0,
想在CentOS6.5上安装Ngrok, 按照搭建 ngrok 服务实现内网穿透上的步骤安装。遇到问题,记录一下。

  • no package golang available.

参考CentOS-6.x下搭建golang环境的三种方式

  • no package build-essential available

参考CentOS Install Build Essentials

  • 卡在gopkg.in/inconshreveable/go-update.v0 (download)

参考ngrok服务安装笔记, 知道是git版本太旧。更新之后就可以编译成功

在CentOS6.5上如何更新git, 可参考CentOS6.5升级git

联系作者

以前就用过Supervisor,但没有细看,这次认真的使用了之后,还是发现了一些问题。

  • 如何让Supervisor成为服务

如果是通过pip install supervisor这种方式安装的Supervisor, 如何让Supervisor成为系统的一种服务,让系统开机时自动启动,在这里给出了一些例子,然而,我的系统是Centos 6.5, 这些例子没有包括。于是通过yum install supervisor的方式安装,得到了/etc/init.d/supervisord下的服务脚本. 之后把通过yum安装得到的/usr/bin/supervisord和/usr/bin/supervisorctl替换成pip安装得到的/usr/local/bin/supervisord和/usr/local/bin/supervisorctl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/bin/bash
#
# supervisord This scripts turns supervisord on
#
# Author: Mike McGrath <mmcgrath@redhat.com> (based off yumupdatesd)
#
# chkconfig: - 95 04
#
# description: supervisor is a process control utility. It has a web based
# xmlrpc interface as well as a few other nifty features.
# processname: supervisord
# config: /etc/supervisord.conf
# pidfile: /var/run/supervisord.pid
#

# source function library
. /etc/rc.d/init.d/functions

RETVAL=0

start() {
echo -n $"Starting supervisord: "
daemon supervisord
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/supervisord
}

stop() {
echo -n $"Stopping supervisord: "
killproc supervisord
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/supervisord
}

restart() {
stop
start
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart|force-reload|reload)
restart
;;
condrestart)
[ -f /var/lock/subsys/supervisord ] && restart
;;
status)
status supervisord
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
exit 1
esac

exit $RETVAL
  • Supervisor无法管理daemon进程

在启动Shadowsock的时候,加了-d参数
/usr/local/bin/ssserver -p 443 -k password --user nobody -d start, 也就是让它成为daemon进程,于是Supervisor就无法管理了。所以之后把这个参数去掉。

  • 当supervisor挂了之后,它管理的进程就给了init进程,之后supervisor再次启动,端口已经被绑定了,怎么破?目前还没有找到解决的办法。

参考资料

联系作者