/ thinking  

2022Q3 随想录

生活或者工作中总有些值得记录下的小感想,没必单独写一篇独立文章那就写在 随想录 里吧。随想录 以季度为单位开设。

随想录 专题的直接原因是:在翻看扔进 _drafts 里 18 年写的工作笔记,看到当时留下的一些技术疑问而现在已有答案。这真是一种很棒的感觉,可以感觉到自己的成长、变化,可以复盘自己是否走向自己希望的方向。

自己每天都和自己在一起,很不容感觉到自己变化。不记录事件下当时的想法,在之后回顾此时身处事情之外很容易对当时的想法进行修饰或者修正,变的面目全非。

还是多写写吧,就当快照一样记录下当时的想法。“正经人谁写日记啊。”

工作

生活

迁移 2018 笔记

未明确指定字段所属表的隐患

在修改表结构时,在 a 表新添加 name 字段,b 表本事就有 name 字段;原来的项目中有 a b 表的关联查询,并用到了 name 字段。这时,原来 name 指的是 a 还是 b 表中的变的不确定了,造成报错。

主要原因就是在连表时:未明确指定字段所属表,造成了伏笔。

2022Q3:关联查询现在多用模型的方案。

数据库枚举值的坑

在数据库使用枚举时可以规范数据字典,但是也造成了要添加值时,需要修改数据库结构,这是不可接受的。

而且枚举值查询可以使用 0,1,2.. 索引值进行查询,也可以使用 ‘public’ ‘private’ 这样的规定的字典值查询,有二义性,可能有伏笔。

  • 典类型的字段我都以 _type 结尾,tinyint 型,无符号,数字代表的值写在字段注释里。eg: book_type
  • 是否 概念的字段也不要用 枚举,我会使用 is_ 开头。eg: is_review

2022Q3:数据库枚举值没再用过。is_ _type 的命名方式沿用至今。

补充说明:枚举类型不但可以使用下标 0,1,2.. 查询,也可以使用不加引号的 0,1,2..(下标)来写入某个类型。

举个栗子:

类型:enum('none','public','private','1') 当你 insert into ... set a = 1 时:

  • a = 1 是插入 enum 的第一个值,即 public。
  • a = '1' 是插入 enum 值为 1 的类型。

所以在 PHP 弱类型语言中,数字可以不加单引号,所以要注意到这点。

NGINX 没有配置结束符的伏笔

location ~*.xml$ {
rewrite '^/sitemap/([a-z_0-9]*)\.(xml)$' /sitemap/$1 last;
add_header X-Robots-Tag noindex;
}

这是配置 sitemap XML 转发和添加 header,在 ~*.xml$ 中,如果没有 $ 会造成只要 slug 中有 xml 就进行了转发。eg: /abc/abcxmldef 将被转发 这是不符合预期的。

MySQL 连接遇到的端口问题

自己的电脑有两个 MySQL 服务,一个 3306 一个 3307。在使用 mysql -uroot -p -P3307 这样指定端口连接是无效的。

其实这个是 MySQL 故意设计的,如果你的 host 是 localhost(如果不指定默认也是 localhost),那 MySQL 必须用 unix socket 连接,那样的话设置端口什么的当然没用啦。所以正确的做法是指定 host 为 127.0.0.1 再指定端口,绝对管用。

查看端口:

show global variables like 'port';

MySQL 配置文件的读取顺序和位置可以通过 mysql --help 查看。

Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/Cellar/mysql-client/8.0.30/etc/my.cnf ~/.my.cnf

测试,坚持如一

今天发现了:因为测试不全导致的手机端部分页面显示异常的情况。问题的发现还是用户发现后反馈的。

原因:手机端的页面代码位置应该总体是和 PC 端是一致的,但是在整理代码时,一个两端的结构差异导致了缺少引用一个 JavaScript 库,在测试过程中,没有测试到此一级页面,PC 端代段此级正常。

还是自己懈怠了,测试,坚持如一,欠的总会还。引以为戒。

2022Q3:近日也出现了整理代码删除了还在被使用的类文件。永远不能心存侥幸,要多看一眼。

MySQL 用户不同导致的数据库无法打开

使用 Navicat 无法打开数据库,提示大概是权限什么的问题,使用 mysql 命令是可以的。

后来发现是:在线上建立了一个视图,使用的是一个远程用户,后来数据备份,视图也被备份到本地了。但是这个远程用户在本地是没有的,所以导致使用 Navicat 时,无法打开数据库。

2022Q3:现在多使用的是云数据库,授权用户权限要谨慎。

页面中 JavaScript 中正则表达式中的特殊字符被转码

今天遇到 HTML 页面中直接写了 JavaScript 的验证的表达式:

"[©]+";

里面涉及了一个特殊字符 ©,页面第一次加载时,一起正常,但是 ajax 提交后,pjax reload 页面后,©encode

解决方法:使用 unicode [\\u00A9]+·

2022Q3:当时还是纯手写 JavaScript,现在使用 webpack babel 等工具,是否不会再有类似问题了?

一款很秀的 正则表达式 工具推荐给大家 jex.im/regulex

Firefox word-break: break-word

Firefox 疑似不支持 word-break: break-word 对词进行折行

  • Use word-break: break-all; instead of word-break: break-word;
  • Or, Use word-wrap: break-word; instead of word-break: break-word;

所以 CSS 编写要考虑好厂商差异,亟待使用前端工具,最近准备使用 gulp 优化项目前端。

2022Q3:现在使用 Vue2 全家桶,CSS 有相关 loader 处理兼容性。

Policy 条款要认真对待

在做部分功能是违反了 Google Policy,被直接标记为恶意网站,流量骤降。对应敏感信息要认真对待不可轻视。

2022Q3:现在主要做内部系统。C 端问题遇到的比较少了。

数据查询的 N+1 问题

N+1 查询问题 就是查询扩展字段时的循环查询问题。

为了解决 N+1 问题我使用了模型 预加载 方式,但是由于后台框架限制(也可能是使用不当),将 一对多 的被关联的模型数据都查出来了,数据量很大,导致页面卡顿,一次反向优化。优化要权衡不能硬搬书本。

2022Q3:消除 N+1 问题仍是开发优化必修课。

使用 … 运算符定义变长参数函数

在写一方式时使用了 ... 运算符,但是这个运算符是 PHP 5.6 增加的,线上是 PHP 5.5 导致 500 报错,环境问题暴露。如果可能出错,就一定会出错。

2022Q3:开发、测试、UAT、PROD 环境一致性必须对齐。

Ubuntu 核心参数

net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 5000 65000

sysctl -p 显示系统内核参数变化。其中含义待研究。

2022Q3:仍然不懂。

/etc/sysctl.conf

net.ipv4.tcp_tw_recycle 改为 0

tcp_tw_recycletcp_timestmaps 同时开启时,会有 risk,来自 NAT 网路的用户访问会有丢包情况从而导致 504。tcp_tw_recycle 默认是不开启的,之前的优化配置开启该选项时时并没有考虑这一点。从 Linux 4.12 开始,该选项已被移除。

2022Q3:仍然不懂。

正确使用 Redis

在读 Redis 大数组会占用大量的 PHP-FPM 内存,影响查询效率。在大量(百万级)使用存储 Redis Key 发现慢查询,拖累服务器,是否是此原因待详细查。如何正确使用 Redis、配置 Redis 需要总结。

2022Q3:Redis 一次读取大数据是可能造成阻塞的,当时使用 Redis 都是本地安装,现在都是使用云服务。类似问题没在遇到过,遇到后再分析。

MySQL 索引选择

某查询中通过 explain 发现 MySQL 选择了一个较慢的索引,发现相同条件下不同的时间会使用不同的索引,引发了慢查询。需要研究 MySQL 如何进行索引的选择,和如何建立合理的索引。

2022Q3:最近在读《MySQL 实战 45 讲》真的收获很多。

AWS EC2 服务器类型

定额配置信用积分,影响服务器性能。

Python SELECT 查询事务

Python 的 SELECT 查询默认是事务性的操作,期间无法对表 DDL 进行改变。

SELECT 语句也应该进行 COMMIT。道听途说,待自测详查。

2022Q3:最近在读《MySQL 实战 45 讲》真的收获很多。应该是 MDL(metadata lock) 的原因。

NGINX Log 中挖掘项目隐藏的问题

  • 通过 log 监控流量、访问行为、发现爬虫
  • 通过 log 分析非 200 状态码,检查项目页面

2022Q3:现在的使用的日志监控服务就是监控 NGINX 与项目应用日志。

数据库字段中包含 HTML 元素导致页面错乱

数据库数据有 </div> 等标签,与模板元素连接在一起,导致页面错乱。要显示的数据要 htmlspecialchars 转码。

2022Q3:提防 HTML 注入。

爬取检查时发生 Connection to the other side was lost in non-clean

thanks for xq24.

Scrapy 快速的三次 retry 之后 give up,然后接着 url 都出现这个问题。

此时状态:这时浏览器挂上代理能访问出现问题的 url,但是本地无代理时 IP 无法访问。

查看服务器 Log:

发现有状态码 499 但是,只有访问一次这个 url 会出现俩三个 499 的 response,然后一段时间内,整个站就都不能访问了,没有反应了,NGINX 日志里面也没有记录到任何东西了,说明数据没有到 NGINX 应该是 TCP 层的网络有问题。

验证:

tcpdump + Wirsshark 分析。

sudo tcpdump tcp -i eth0 -t -s 0 -c 1000 and dst port ! 22 -w ./target.cap

出现了很多的 RST 导致 TCP 连接中断,仔细看,发现里面的 ACK 完全和上一个包的 Seq 对不上,我们客服端的 ACK 的是一个巨大的随机数。导致服务器端返回 RST

因为项目是 HTTP 应用层的,不会影响到 TCP 层,所以 Google 关键字 tcp reset + blogspot.com 看到 reddit 一篇 8 年前的讨论。讲到了 关于中国防火墙。中国 GFW 会有根据 tcp 协议里面的关键字来进行屏蔽。然后会通过 reset 修改来屏蔽整个站几分钟。https 协议的不会。

测试了俩个国外的网站:

加入了 blogspot.com 就无法访问了。

所以问题找到了中国 GFW 会通过 URL 里面的敏感字进行封锁网站,有篇具体分析的文章。线上因为用的 HTTPS 协议所以内容加密了,没有被 block,解决方法:

  • 将测试服务器换成 HTTPS 然后就可以访问了
  • 通过代理访问

2022Q3:网络知识问题,待继续学习。

NGINX Log 出现大量(10K)HTTP 499 错误

499 CLIENT CLOSED REQUEST

A non-standard status code introduced by nginx for the case when a client closes the connection while nginx is processing the request.

NGINX Log 出现大量(10K)HTTP 499 错误,几乎都是 AJAX POST 请求。经过日志排查,发现这些 499 请求都是来自于 Safari 浏览器,再通过日志查看,这些请求都是正常的用户行为。在本地使用 Safari 浏览器实测时也是会出现这样的问题。基本可以断定是 Safari 浏览器导致。

最终确定为在点击一个 button 时同发送了两请求,分别为 async: false,async: true。

在进行控制变量的测试中,基本确定与 AJAX 同异步请求有关。不建议修改 async 为 false。

在测试的过程中,也发现虽然使用 Safari 请求显示 NGINX 日志中会显示 499,但是数据的记录并没有受到影响。

2022Q3:待再研究。

服务器器运维工具 atop

待整理。

完全独立的分支

在使用 Git 进行版本控制的某些场景中我们可能需要在一个项目中建立完全独立的分支,此分支将作为一个独立的版本历史根节点,不与之前任何分支拥有相同的版本祖先。

比如当我们要在一个项目中使用一个分支进行项目文档的管理时,或者当我们想要发布一个软件的开源版本但又不希望将软件的版本历史暴露给外界时,都可以使用以下的方法建立一个独立分支。

通过带有 --orphan 参数的 checkout 命令即可从 start_point 或者 HEAD 创建一个独立分支:

git checkout --orphan 新分支名 <start_point>

如果希望创建全新的独立分支,例如用于文档管理,不想出现项目代码,则还需要进行如下删除操作。注意如果有不在索引中的文件,则需要手工删除(包括 .gitignore),删除此分支中的索引及索引中的所有文件:

git rm -rf .

– EOF –