2020年07月
2020-7-1 周三
Redis 简单限流
滑动窗口
def is_action_is_allowed(user_id, action_key, period, max_count): key = 'hist:%s:%s' % (user_id, action_key) now_ts = int(time.time() * 1000) # 毫秒时间戳 with r.pipeline() as pipe: # value:score 都是毫秒时间戳 pipe.zadd(key, {now_ts: now_ts}) # 移除时间窗口之前的操作记录 pipe.zremrangebyscore(key, 0, now_ts - period * 1000) # 获取窗口内的行为数量 pipe.zcard(key) # 设置 zet 过期时间,避免冷用户持续占用内存 pipe.expire(key, period + 1) # 过期时间再宽限一秒 _, _, current_count, _ = pipe.execute() return current_count <= max_count
for i in range(8): print(is_action_is_allowed("tabll6", "replay", 60, 5)) # 60秒内限制5次操作
返回:
True True True True True False False False
2020-7-2 周四
Redis 漏斗限流
基本原理就是按照代码中的逻辑来
实际情况是有更加完美的包解决的:Redis-Cell
class Funnel(object): def __init__(self, capacity, leaking_rate): self.capacity = capacity # 漏斗容量 self.leaking_rate = leaking_rate # 流水速率 self.left_quota = capacity # 漏斗剩余空间 self.leaking_ts = time.time() # 上一次漏水时间 def make_space(self): now_ts = time.time() # 距离上一次漏水的时间 delta_ts = now_ts - self.leaking_ts # 可以腾出的空间 delta_quota = delta_ts * self.leaking_rate # 如果空间不足则下次再说 if delta_quota < 1: return self.left_quota += delta_quota # 增加剩余空间 self.leaking_ts = now_ts # 记录漏水时间 # 剩余空间不得高于容量 if self.left_quota > self.capacity: self.left_quota = self.capacity def watering(self, quota): self.make_space() # 判断剩余空间是否足够 if self.left_quota >= quota: self.left_quota -= quota return True return False
funnels = {} # 所有的漏斗
# 检查执行是否被允许 def is_action_allowed(user_id, action_key, capacity, leaking_rate): key = '%s:%s' % (user_id, action_key) funnel = funnels.get(key) if not funnel: funnel = Funnel(capacity, leaking_rate) funnels[key] = funnel return funnel.watering(1)
for i in range(20): print(is_action_allowed("tabll6", "replay", 15, 5)) # 容量 15, 流水速率 5/s
返回:
True True True True True True True True True True True True True True True False False False False False
2020-7-3 周五
Redis-Cell
这个也是需要额外安装并启用的模块,是比较完美的漏斗限流解决方案
r.execute_command('CL.THROTTLE', "tabll6:get", 15, 10, 20, 1) # key / 15漏斗容量 / 10 option 10个操作 / 20 seconds 每20秒 / need 1 quota
1) (integer) 0 # 0 表示允许,1 表示拒绝
2) (integer) 15 # 漏斗容量 capacity
3) (integer) 14 # 漏斗剩余空间 left_quota
4) (integer) -1 # 如果拒绝了,需要多长时间后再试(漏斗有空间了,单位秒)
5) (integer) 2 # 多长时间后,漏斗完全空出来(left_quota==capacity,单位秒)
相关文档:https://github.com/brandur/redis-cell
2020-7-6 周一
代码圈块复杂度
最近安装了 SonarLint
插件,发现项目中非常多的 function
被提示需要优化
SonarLint: Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed. [+15 locations] more... (Ctrl+F1)
圈复杂度 (Cyclomatic Complexity
) 是一种代码复杂度的衡量标准,由 Thomas McCabe
于 1976
年定义。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。
一般来说圈复杂度V(G)
与代码质量的关系如下:
V(G) ∈ 0 , 10:代码质量不错;
V(G) ∈ 11 , 15:可能存在需要拆分的代码,应当尽可能想措施重构;
V(G) ∈ [16 , ∞):必须进行重构;
降低圈复杂度
Extract Method(提炼函数)
Substitute Algorithm(替换你的算法)
Decompose Conditional(分解条件式)
Consolidate Conditional Expression(合并条件式)
Consolidate Duplicate Conditional Fragments(合并重复的条件片断)
Remove Control Flag(移除控制标记)
Parameterize Method(令函数携带参数)
2020-7-7 周二
GitLab 与 GitHub 同步
GitHub 最近开启了”北极代码库”计划,会将所有的代码在北极存一份。有点末日种子库的感觉,以后人类还能看到千年前的写BUG
备份还是必要的,防止自建的GitLab有一天挂了,现在打算将GitLab上的代码都同步一份到GitHub上面去
步骤很简单,不过好像基础版的GitLab暂时不支持镜像同步的功能
首先在GitHub上面创建一个新的仓库,公开或者私有都可以,支持两边的查看权限不一致
然后在GitLab中找到仓库的设置->仓库->镜像仓库
填写仓库URL地址,注意这里的仓库URL地址需要拼接上你的用户名
比如 https://XXXXX@github.com/XXXXX/ABC.git
镜像的方向是推送,你也可以反向的从GitHub上面拉取
密码是在GitHub上面生成的Token
完成之后它不会立即同步,可能需要等一会儿,你可以点击立即同步按钮,让它立即执行
这个同步只会同步仓库的代码和commits记录,合并请求ci/cd这些都不会同步过去,目前感觉还是gitlab的ci好用
2020-7-8 周三
网页速度测试
Google 的工具
在这里不仅可以看到页面的评分,还可以看到当前可以优化的选项
需要执行什么操作都写的很清楚
Lighthouse 插件
这个其实就是 Google 的工具整合成了一个网页插件,很方便的在浏览网页的时候能够随时随地分析一波
其它工具
它可以统计并显示出国内外相关节点的访问速度
优化完成
2020-7-9 周四
VI 删除所有行
在命令行模式下输入:
:.,$d
会删除从当前行直到末尾的数据
2020-7-10 周五
MySQL JSON 查询
address_ids
的格式是 [1, 2, 3]
,数据库中存储的类型是 JSON
查询包含了 3 的字段
SELECT * FROM users where JSON_CONTAINS(address_ids, '3', '$');
假如 address_ids
的格式是 {"a": [1,2,3]}
SELECT * FROM users where JSON_CONTAINS(address_ids, '3', '$.a');
2020-7-13 周一
升级 NodeJS 版本
npm cache clean -f npm install -g n n stable
installing : node-v12.18.3 mkdir : /usr/local/n/versions/node/12.18.3 fetch : https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-x64.tar.xz installed : v12.18.3 (with npm 6.14.6) Note: the node command changed location and the old location may be remembered in your current shell. old : /usr/bin/node new : /usr/local/bin/node To reset the command location hash either start a new shell, or execute PATH="$PATH"
2020-7-14 周二
NPM 淘宝镜像
npm install -g cnpm –registry=https://registry.npm.taobao.org
npm install sitespeed.io@13.3.0 -g
apt install XVFB
2020-7-15 周三
Apache 反向代理
需要将 A/api/inner/prs/*
代理到 B/api/*
上
Apache
版本 2.4
<VirtualHost *:80> ServerName tabll.com ServerAlias sh.tabll.com sz.tabll.com hz.tabll.com ProxyRequests on DocumentRoot "E:/www/public" DirectoryIndex demo.html index.php <Directory "E:/www/public"> Options +Indexes +FollowSymLinks +ExecCGI AllowOverride All Order allow,deny Allow from all Require all granted </Directory> <Proxy *> Order deny,allow Allow from all </Proxy> <Location /api/inner/prs> ProxyPass http://192.168.0.161:8030/api ProxyPassReverse http://192.168.0.161:8030/api </Location> <Location /api/inner/crm/prs> ProxyPass http://192.168.0.161:8030/api ProxyPassReverse http://192.168.0.161:8030/api </Location> </VirtualHost>
这里需要注意的是URL的结尾不要多一个 /
否则会报 404
2020-7-16 周四
PHP 加速
有一个 opcache
可以用
[opcache] ;DLL地址 zend_extension=php_opcache.dll; ;开关打开 opcache.enable=1 ;开启CLI opcache.enable_cli=1 ;可用内存, 酌情而定, 单位为:Mb opcache.memory_consumption=528 ;Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB) opcache.interned_strings_buffer=8 ;对多缓存文件限制, 命中率不到 100% 的话, 可以试着提高这个值 opcache.max_accelerated_files=10000 ;Opcache 会在一定时间内去检查文件的修改时间, 这里设置检查的时间周期, 默认为 2, 定位为秒 opcache.revalidate_freq=1 ;打开快速关闭, 打开这个在PHP Request Shutdown的时候回收内存的速度会提高 opcache.fast_shutdown=1
参考链接:PHP性能加速Opcache的开启与设置
2020-7-17 周五
mkdir
参数
-p
-p
直接创建一个不存在的目录下的子目录,而不会报错
-m
-m 777
创建权限为 777
的目录
-v
-v
显示操作的详细结果
2020-7-20 周一
GitLab 浏览器性能测试
按照官方文档无法正常执行
browser_performance: stage: performance image: name: sitespeedio/sitespeed.io:13.3.0 entrypoint: [""] tags: - quality allow_failure: true variables: URL: https://test.tabll.cn/ SITESPEED_VERSION: 13.3.0 SITESPEED_OPTIONS: '' SITESPEED_IMAGE: sitespeedio/sitespeed.io script: - mkdir -p gitlab-exporter - wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/1.0.1/index.js - mkdir -p sitespeed-results - /start.sh --plugins.add ./gitlab-exporter --outputFolder sitespeed-results $URL -b chrome - mv sitespeed-results/data/performance.json browser-performance.json artifacts: paths: - sitespeed-results/ reports: browser_performance: browser-performance.json needs: ["sast", "license_scan", "secret_detection", "dependency_scan"]
2020-7-21 周二
GitLab 负载测试
这个的官方文档也有问题,按照步骤无法正常执行
load_performance: stage: performance tags: - quality image: name: loadimpact/k6:0.26.2 entrypoint: [""] allow_failure: true variables: K6_IMAGE: loadimpact/k6 K6_VERSION: 0.26.2 K6_TEST_FILE: test.tabll.cn/js/k6-test.js K6_OPTIONS: '' script: - k6 run $K6_TEST_FILE --summary-export=load-performance.json artifacts: reports: load_performance: "load-performance.json" needs: ["sast", "license_scan", "secret_detection", "dependency_scan"]
2020-7-22 周三
哈夫曼编码
2020-7-23 周四
Docker 指定阿里云拉取
docker pull registry.cn-hangzhou.aliyuncs.com/XXX/XXX:latest
2020-7-24 周五
HTTP 2.0 的优缺点
HTTP 1.0 的缺点
连接无法复用
:导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大
head of line blocking
:导致带宽无法被充分利用,以及后续健康请求被阻塞。后续从应用层发出的请求只能排队,请求2,3,4,5只能等请求1的response回来之后才能逐个发出
HTTP 2.0 的优点
二进制分帧
:在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层
多路复用 (Multiplexing)、连接共享
:HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息
每个stream都可以设置又优先级(Priority)和依赖(Dependency)
首部压缩(Header Compression)
:使用了专门为首部压缩而设计的 HPACK
算法
服务端推送(Server Push)
:服务器可以对客户端的一个请求发送多个响应
重置连接表现更好
:引入 RST_STREAM
类型的 frame
,可以在不断开连接的前提下取消某个 request
的 stream
流量控制(Flow Control)
:通过sliding window的算法来做流量控制。发送方有个sending window,接收方有receive window
更安全的SSL
:使用了 tls
的拓展 ALPN
来做协议升级
2020-7-27 周一
Go 语言编码规范
CodeReviewComments:https://github.com/golang/go/wiki/CodeReviewComments
2020-7-28 周二
Go 语言垃圾回收机制(GC)
触发条件
1 超过内存大小阈值
2 达到定时时间
阈值是由一个gcpercent的变量控制的,当新分配的内存占已在使用中的内存的比例超过gcprecent时就会触发。比如一次回收完毕后,内存的使用量为5M,那么下次回收的时机则是内存分配达到10M的时候。也就是说,并不是内存分配越多,垃圾回收频率越高。
一直达不到内存大小的阈值,GC就会被定时时间触发
2020-7-29 周三
GitLab Runner 里安装 Go
wget -o https://studygolang.com/dl/golang/go1.14.6.linux-amd64.tar.gz tar xfz go1.14.6.linux-amd64.tar.gz -C /usr/local # 修改~/.bashrc vim ~/.bashrc # 添加 Gopath 路径 export GOPATH=/usr/local/go export PATH=$GOPATH/bin:$PATH # 激活配置 source ~/.bashrc # 查看安装的版本 go version warning: GOPATH set to GOROOT (/usr/local/go) has no effect go version go1.14.6 linux/amd64 # 变量修改为以下配置 vim ~/.bashrc export GOROOT=/usr/local/go export GOPATH=$PATH:$GOROOT/bin # 激活配置 source ~/.bashrc # 查看安装的版本 go version go version go1.14.6 linux/amd64
2020-7-30 周四
Go CI
原先是想在 sh
的 runner
里面运行的,现在是使用的 docker
的 runner
# This file is a template, and might need editing before it works on your project. image: golang:1.14.6 variables: # Please edit to your GitLab project REPO_NAME: gitlab.tabll.cn/Tabll/bellflower-go # The problem is that to be able to use go get, one needs to put # the repository in the $GOPATH. So for example if your gitlab domain # is gitlab.com, and that your repository is namespace/project, and # the default GOPATH being /go, then you'd need to have your # repository in /go/src/gitlab.com/namespace/project # Thus, making a symbolic link corrects this. before_script: - mkdir -p $GOPATH/src/$(dirname $REPO_NAME) - ln -svf $CI_PROJECT_DIR $GOPATH/src/$REPO_NAME - cd $GOPATH/src/$REPO_NAME - go env -w GO111MODULE=on - go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/ stages: - test - build - deploy format: stage: test tags: - quality script: - go fmt $(go list ./... | grep -v /vendor/) - go vet $(go list ./... | grep -v /vendor/) - go test -race $(go list ./... | grep -v /vendor/) -cover compile: stage: build tags: - quality script: - go build -race -ldflags "-extldflags '-static'" -o $CI_PROJECT_DIR/mybinary artifacts: paths: - mybinary
2020-7-31 周五
开始用 Go
语言重写博客