需要给公司的域名添加HTTPS,决定先给自留地添加HTTPS支持,安装过程中遇到一些问题,记下来。

libbrotli安装

安装libbrotli时,出现Makefile.am:5: Libtool library used but LIBTOOL is undefined,执行yun install libtool安装即可。

/lib/lsb/init-functions: No such file or directory

执行yum provides ‘/lib/lsb/init-functions’ 可以找到哪个包支持。

1
redhat-lsb-core-4.0-7.el6.centos.i686 : LSB base libraries support for CentOS

之后执行yum install redhat-lsb-core-4.0-7.el6.centos.i686即可

安装免费证书

本来想 Let’s Encrypt, 但DNS解析出问题,想切换到外国的DNS,但考虑到公司的域名解析不能切换,所以继续找免费证书。最好找到沃通

参考资料

联系作者

在看Django源码时,知道了Counter,

1
2
3
4
5
6
7
8
9
# Check for duplicate app names.
counts = Counter(
app_config.name for app_config in self.app_configs.values())
duplicates = [
name for name, count in counts.most_common() if count > 1]
if duplicates:
raise ImproperlyConfigured(
"Application names aren't unique, "
"duplicates: %s" % ", ".join(duplicates))

感觉很不错,比用dict统计方便多了,以后需要计数时,就用Counter。看来collections库是个宝库,要好好看看。

联系作者

此前,MySQL的默认引擎是MyISAM, 所以导致数据库里很多表都是MyISAM, 而MyISAM是表级锁,很容易引起性能问题。最近服务又被锁住了,原因依然是MyISAM的表级锁。于是将MyISAM引擎改为InnoDB。

之前运维同事写过一个脚本,直接拿来用就好。
github地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

# 将 db_name 下引擎为 MyISAM 的表改为 InnoDB

# 以下变量按需修改
host_name=''
user_name='root' # root 或该用户有 root 同等级权限
password=''
db_name=''

tables=$(mysql -h${host_name} -u${user_name} -p${password} -e "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='${db_name}' AND ENGINE='MyISAM';")

for table in ${tables}
do
if [ ${table} != 'TABLE_NAME' ]; then # 排除标题
echo ${table}
mysql -h${host_name} -u${user_name} -p${password} -e "ALTER TABLE ${db_name}.${table} ENGINE='InnoDB';"
fi
done

联系作者

之前测试服务器上的Thrift服务每天都报
OperationalError: (2006, ‘MySQL server has gone away’)错误,但正式服务器就不会,在网上找了很久还是没找到解决的办法。

最后在(2006, ‘MySQL server has gone away’) in django1.6 when wait_timeout passed找到如下回答:

If you hit this problem and don’t want to understand what’s going on, don’t reopen this ticket, just do this:

  • RECOMMENDED SOLUTION: close the connection with from django.db import connection; connection.close() when you know that your program is going to be idle for a long time.
  • CRAPPY SOLUTION: increase wait_timeout so it’s longer than the maximum idle time of your program.

In this context, idle time is the time between two successive database queries.

这里说对于这个问题,有两种做法,一种是关闭连接, 另一种是设置wait_timeout大于空闲时间。从这里明白原因,因为测试服务器没人访问,所以会断开连接,而正式服务器一直有人访问,所以不会。

关闭连接的话不想采用,不能每次使用都关闭连接。第二种也不采用。于是只好设置一个crontab任务,定时去访问Thrift服务。

联系作者

国内访问Docker官网镜像很慢,需要修改镜像地址。阿里云的速度不错,注册之后就可以拿到专属加速器地址。

阿里云后台有说明,根据不同系统,版本号,有相应的设置

我的Ubuntu上

1
2
echo "DOCKER_OPTS=\"--registry-mirror=https://xxxxxx.mirror.aliyuncs.com\"" | sudo tee -a /etc/default/docker
sudo service docker restart

其中xxxxxx需要替换成专属加速器。

在我的Mac上,根据Docker for Mac, 参考Preferences 设置, 在Preference->Advanced->registry mirrors里添加专属加速器地址

参考资料:

联系作者

之前有几个站点是用Wordpress搭建的,准备迁移服务器后,需要安装Wordpress, 这次想用Docker来迁移。于是就在Docker中安装Wordpress. 看到Compose的文档里有一篇Quickstart: Docker Compose and WordPress, 于是使用Compose安装。

按照文档安装,报如下错误。

1
2
wordpress_mysql | 2016-09-22T09:34:33.723755Z 0 [ERROR] InnoDB: mmap(137428992 bytes) failed; errno 12
wordpress_mysql | 2016-09-22T09:34:33.723792Z 0 [ERROR] InnoDB: Cannot allocate memory for the buffer pool

发现是内存不够,因为已经安装了一个MySQL, 并且服务器内存只有512M, 于是内存吃紧, 只好放弃这种安装方法,直接连接现有的MySQL容器。

docker pull wordpress拉取最新版本的Wordpress后,执行命令后台启动Wordpress

1
docker rund --name wordpress --link mysql:db -p 8000:80 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_NAME=wordpress -e WORDPRESS_DB_PASSWORD=password wordpress:latest

又发现CPU吃紧, 查看进程后发现loop0进程很占CPU,原来用的是Apache服务器,这就显得浪费了,我已经安装的Nginx了,而Wordpress镜像里还安装Apache。

得想想其它办法才好。当然如果内存足够,这样安装也没什么问题。

联系作者

phpmyadmin用来查看MySQL非常方便,决定给测试服务器上安装一个,这样开发人员就可以通过浏览器访问数据库,很方便。

查看官方的说明文档,一直没弄懂要如何连接本地安装的MySQL, 好在测试环境的数据库是通过docker容器安装的,方便连接。

执行docker pull phpmyadmin/phpmyadmin拉取官方的镜像后,假设已经存在一个在运行的MySQL容器,名字叫mysql, 执行

1
docker run --name myadmin -d --link mysql:db -p 8000:80 -e PMA_USER=root -e PMA_PASSWORD=mysql123456 phpmyadmin/phpmyadmin

其中–link是连接已经运行的mysql容器, db只是别名. 而PMA_USER和PMA_PASSWORD是连接mysql的用户名和密码, 这样开发人员在使用phpmyadmin时,就可以不用输入用户名和密码了,之后访问服务器的8000端口就可以访问MySQL数据库了,很方便。

参考资料:

联系作者

在使用requests库时,遇到中文文件名问题,现象如下

如果是英文文件名,body中的内容为

1
Content-Disposition: form-data; name="document"; filename="my.doc"

如果是中文文件名,body中的内容为

1
Content-Disposition: form-data; name="document"; filename*=utf-8''03%E7%BD%91%E7%AB%99%E5%A4%87%E6%A1%88%E4%BF%A1%E6%81%AF%E7%9C%9F%E5%AE%9E%E6%80%A7%E6%8F%90%E4%BE%9B%E7%94%B5%E5%AD%90%E7%89%88%E6%89%AB%E6%8F%8F%E4%BB%B6.doc

查看requests的源码,从request.post一路跟踪,进入session.request, 进入 session.prepare_request, 进入PreparedRequest.prepare, 进入进入PreparedRequest.prepare_body, 进入PreparedRequest._encode_files, 进入RequestField.make_multipart, 进入RequestField._render_parts, 进入RequestField._render_part,最后进入RequestField.format_header_param方法, 内容如下

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
def format_header_param(name, value):
"""
Helper function to format and quote a single header parameter.

Particularly useful for header parameters which might contain
non-ASCII values, like file names. This follows RFC 2231, as
suggested by RFC 2388 Section 4.4.

:param name:
The name of the parameter, a string expected to be ASCII only.
:param value:
The value of the parameter, provided as a unicode string.
"""

if not any(ch in value for ch in '"\\\r\n'):
result = '%s="%s"' % (name, value)
try:
result.encode('ascii')
except UnicodeEncodeError:
pass
else:
return result
if not six.PY3: # Python 2:
value = value.encode('utf-8')
value = email.utils.encode_rfc2231(value, 'utf-8')
value = '%s*=%s' % (name, value)
return value

这里明确说明文件名只能是ascii, 于是只好将文件名urlencode一下,使用urllib将文件对象的名字修改后,例如假设document是一个文件对象, 可以进行如下修改

1
2
f = {'document': (urllib.quote(document.name.encode('utf-8')), document, document.content_type)}
response = requests.post(UPLOAD_DOCUMENT_URL + "?access_token=%s" % access_token, files=f, data=params)

参考资料:

联系作者

MySQL提供了count命令来统计表中的记录数, 使用起来非常方便。但加上where条件的count命令有时会很慢,此时需要优化。

最近在项目中就遇到这个问题。看下面两个SQL的查询结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SELECT COUNT(*) FROM user WHERE user.is_active = 1;
+-----------+

| COUNT(id) |
+-----------+

| 239563 |
+-----------+

1 row in set (0.21 sec)

mysql> select count(*) from sku_pro where is_agent=1;
+-----------+

| count(id) |
+-----------+

| 1253535 |
+-----------+

1 row in set (0.11 sec)

看到这个结果,肯定会很吃惊。user表的数据比sku_pro表的数据少很多,但执行时间却比它长,匪夷所思。查看两个表结构,两个表都是MyISAM引擎,看到的差别是user表61个字段,而sku_pro表16个字段。

在网上找各种资料,没有找到问题的答案。于是请教同学,同学提示说看数据大小,如果数据大的,读到内存需要花费更多的IO,这样会更慢一些。但发现两个表数据大小差不多。

在查看show table status的结果时,发现user表的RowFormat是Dynamic, 而sku_pro表的是Fixed, 于是查看user表结构,发现很多字段是varchar字段,于是猜测在Dynamic时,要查找到字段的值,需要计算便宜量,这样速度更慢。在MySQL Optimization: Faster Selects with MyISAM fixed row format一文中有提到这个问题。

但是如果不想改变RowFormat又该怎么做?在StackoverFlow上提了这个问题, 很快得到解答,只需要创建索引即可,需要注意索引里有加上id字段,

1
CREATE INDEX is_active ON user (is_active,id);

值得注意的是,这里不是创建

1
CREATE INDEX is_active ON user (is_active);

在解答中有提到,这个索引会被忽略。

参考资料:

联系作者