Hi there 欢迎 👋

大学狗; 谷粉

🌈 希望每人都是一束光,每人也都可以被照亮

🌎 Believe in OPENNESS

Ubuntu 20.04 安装 PostgreSQL

写于 2021-10-19 请注意实效性。 毕竟我也不是专业运维,一直以来服务器上都用宝塔面板偷懒,直到决定换成更现代化的数据库——PostgreSQL。与 MySQL 形成鲜明对比,宝塔对 PgSQL 的支持简直就是一坨💩。先罗列一下基本罪状: 安装后无法重启服务。 创建数据库后实际上并没有创建。 删除数据库不会删除关联的用户。 …… 其中部分已经有人反馈,也被官方收录,但就是不修。无奈,还是老老实实自己安装。 本文没什么技术含量,随意记录一下而已。 安装 Ubuntu 官方仓库已经收录了 PostgreSQL,但是每个系统版本都绑定了一个特定的 PG 版本,无法手动选择。Ubuntu 20.04 绑定的是 PG 12.8 正好符合需求。如果不符合,去看看 PG 的文档添加一个源就好了。 安装非常简单,甚至比宝塔还简单。 sudo apt update sudo apt install postgresql postgresql-contrib 其中 postgresql-contrib 是第三方贡献的额外代码,一些实用工具之类的,一并装上吧。 完成后执行下面命令检查安装情况与版本号: sudo -u postgres psql -c "SELECT version();" 连接 PG 默认情况下 PG 会创建一个名为 postgres 的角色(也就是用户),并且与系统同名账户关联。使用此账户可以直接登录数据库。那么理论上,执行 sudo -i -u postgres 就可以切换。 然而… sudo: unable to change directory to /home/postgres: No such file or directory sudo: unable to execute /bin/sh: No such file or directory 原因已经写的很清楚了,那我们就来手动修复一下。执行...

October 19, 2021 · Chenhe

K8s 访问集群外部的服务

从 docker 到 compose 再到 k8s,容器化是越来越火了,应该也有不少小伙伴和我一样跃跃欲试。但是马克思告诉我们要一分为二地看待问题。容器化固然好,不过也不是所有服务都适合这么搞。典型的,数据库服务是否适合放在 k8s 中就一直饱受争议。 这次的问题也起于此。通过 Service 暴露内部服务到外部已经轻车熟路了,倒过来则讨论少了许多。究其原因,我觉得是太简单,甚至不值得讨论——直接访问域名和 ip 不就行咯。 确实可以,但不够「优雅」, 尤其当我们不确定某个服务是否会在某天也容器化时。这非常符合处于过渡阶段的项目。 服务间通讯 首先来看一下集群内部服务之间的通讯。官方文档传送门🌀。 这个太简单了,默认情况下,k8s 会根据服务名,为每个服务都创建一个内部的 FQDN,格式为 my-svc.my-namespace.svc.cluster-domain.example。集群内的其他服务可以通过此域名直接访问。 访问集群外服务 那么我们想,如果把这种思路用于外部服务,岂不是太好了。 这样一来,随着容器化的推进,就可以无缝切换,不需要重新调整服务地址的配置。 Service - ExternalName 搂一眼配置: kind: Service apiVersion: v1 metadata: name: pgsql namespace: default ports: - port: 5432 spec: type: ExternalName externalName: pgsql.mydomain.com 这也是一个 Service,只不过没有选择器。访问这个服务所对应的 FQDN 时,实际将解析到 externalName 所指定的域名对应的 IP。最常见的用例应该就是购买云计算厂商的数据库,通常会给我们一个地址用于连接。通过这种方式,相当于把外部地址和内部地址做了映射。 这种方式内部其实利用了 DNS 的 CNAME 技术。这就意味着 externalName 必须是一个有效的域名,而不能 IP 地址。 如果… 就是想要 IP 呢? Endpoint 其实 Service 一直都有 Endpoint,只不过因为是自动的而被我们忽略。通常,Service 通过选择器与 Pod 关联,这时候 k8s 就会根据 Pod 的信息搞出一个 Endpoint 作为访问点。那… 我是不是可以手动指定它呢?...

October 18, 2021 · Chenhe

Nginx HTTPS 性能优化

启于 一开始源于一个一闪而过的想法——反向代理是否会引入额外的延时?然后进一步思考:倘若 CDN 使用 https 回源,然后又用 https 反代,这光是握手是不是就得来回十几遍才行? 显然,放弃 https 不是一个合理的做法(事实上是一个疯狂的做法),那么就研究了一下 https 的优化思路,整合了一些网上的资源,在此记录一下。 以下配置并不适用于所有情况,最典型的,CDN 不提供某些配置选项,我们只能把我们掌控之下的事情做好。 一些思路 HTTP2 HTTP1.1 发布于1999年,已经是上个世纪的东西了。当时智能手机、自动驾驶还停留在科幻作品里。然而20年后的今年,那些曾经处于幻想中的设备,竟然还在使用当初的协议… 我们知道 TCP 的反复握手总是很恶心。一个网页往往有含有大量的资源,于是很多时间被浪费在建立连接上,可以到这个网站测试感受一下。对于 HTTP2,同域名只建立1个 TCP 连接,也就是说握手再也不会充斥我们的网路了。当然,还有其他优点,这里不再一一列举。 启用 HTTP2 很简单,加上一个标志即可: listen 443 ssl; # 旧配置,改成下面这行 listen 443 ssl http2; 多数 CDN 应该支持此功能。 这个工具可以检测 HTTP2 以及下面几个配置项的状态。 启用 OCSP Stapling (装订) 对于个人站长,这个也许是作用最明显的了。由于一些不可描述的原因,Let’s Encrypt 的证书验证服务器从中国大陆访问不是很稳定。通常客户端会按照 OSCP 协议去查询证书的状态(以免证书被吊销但本地的吊销列表没有及时更新),如果这一步骤很慢,则直接影响整体加载速度。 启用 OCSP Stapling 后,服务器会预先查询自己证书的状态,将带有 CA 签名的结果缓存在本地,与证书链一并发送给客户端,这样客户端不需要自己再进行请求,只要验证合法性即可。也就避免了网络因素导致的延时。 启用方法也不复杂,加上三行配置: ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /path/to/full_chain.pem; # 完整证书链 多数 CDN 应该支持此功能。...

September 5, 2021 · Chenhe

不可描述的东西

都说啦不可描述啦~

August 27, 2021 · Chenhe

面向萌新的位与 0xFF 解释

TL; DR 0xFF 通常用于过滤,也叫掩码。和它进行与运算,结果是只保留一个数据的最低8位,其他位全部置0。 背景 在位运算中经常看到A & 0xFF 的身影,甚至已经成了习惯性动作,但一直没有深究它的具体意义,直到这次忘记了神奇的 0xFF,于是发生了很糟糕的事情… 本来是一个很简单的需求——将 int 转为字节数组,然后再转换回来。为了不误导大家,这里先给出正确的实现(kotlin): fun Int.toBytes(bytes: ByteArray? = null): ByteArray { val result = bytes ?: ByteArray(4) if (result.size < 4) { throw IllegalArgumentException("bytes capacity must >= 4") } result[0] = (this shr 24).toByte() result[1] = (this shr 16).toByte() result[2] = (this shr 8).toByte() result[3] = this.toByte() return result } fun ByteArray.toInt(): Int { if (this.size < 4) { throw IllegalArgumentException("bytes size must >= 4") } return ((this[0]....

August 19, 2021 · Chenhe

利用GHActions部署hugo博客到自己VPS

受够了 Wordpress 的臃肿以及对 markdown 的水土不服,受不了 ghost 主题的匮乏与对中文圈的态度。Hexo 用过一段时间,但实在太讨厌 NPM 了,只想安安静静写个博客,结果竟然还要配“开发环境”? 于是 —— Go 真香!迁移到了 Hugo。和 Hexo 一样作为一个静态网站生成器,集成 Github Pages 几乎是标配了,但是 GH 近期在大陆似乎不太如意,眼看着就差彻底断联了。所以还是更想放在自己的香港 VPS 上。作为踩坑记录,这篇文章出现了。 上传文件到 VPS 因为 hugo 生成本身非常容易,就一行命令的事,所以我们先来解决主要矛盾,那就是怎么把生成的文件放到 VPS 上。 rsync 当然,你大可以配一下 Hook,GH 生成完毕后打包传到 Release 或其他什么鬼地方,通知服务器,然后服务器再去拉取回来解压。显然,这不是一个「优雅」的方案。 我希望这一步尽可能地简单,简单到无序通知 VPS 进行额外操作,GH 可以单方面部署完成,这样就少了许多维护成本与不稳定因素。既然是文件传输,自然想到 FTP SFTP/SCP。这两个其实都行啦,不过这里都不用 😂,而且另一个更加适合此场景的东西——rsync。这是一个文件同步服务,可以进行差异比较只传输必要部分,和其他一堆现代化的特性,有兴趣自己查查看吧 标准的服务器系统应该预置了 rsync(不要告诉我你使用 windows),这东西用起来和 scp 很像——都是借用 ssh 进行传输,也使用系统账户进行认证。一条命令轻松实现需求 -a 表示递归同步,并且同步元数据 -v 打印一些信息 --delete 删除目标文件夹存在但本地不存在的玩意,不加这个参数就是增量同步。你一定不希望删掉某个不可描述的东西后实际上文件还在那吧 😄 rsync -av --delete source/ username@host:destination (才怪)难道你的服务器不要身份验证了? 你可以直接把 VPS root 的用户名密码,或者密钥拿过来使,又不是不能用。但是我 觉得 肯定这不是个好主意。新建个系统用户?然后 balabala…...

August 16, 2021 · Chenhe

Springdoc 生成 API 文档 — 迁移自 Springfox

傻傻分不清的近义词辨析 提到 Spring 自动生成 API 文档,多数人脑中就浮现出几个单词:Swagger, OpenAPI, Springfox… 所以首先有必要搞清楚他们的关系。 Open

June 19, 2021 · Chenhe

[译] Mocks 与 Stubs 的区别

原始链接:https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs 很多人经常会混淆这两个测试用的术语,要想完全理解测试替身(test doubles)的用法,我们就必须搞清楚 mocks 和其他术语的区别。当我们进行测试的时候,通常一次只关注一个元素,所以产生了一个术语叫单元测试。问题在于为了使得某个独立单元工作,通常需要其他单元的配合,因此在这个情况下我们需要某种类型的替代品。 在上文(见原文)提到的两个测试类型中,前者使用的是一个真实的对象,而后者使用的是一个 mock 对象,也就是非真实的。使用 mock 是在测试中避免使用真实对象的方法之一,同时也有其他形式的模拟手段。描述这些手段的词汇就很繁杂了,比如 stub, mock, fake, dummy。在这篇文章中,我使用 Gerard Meszaros 的书中所定义的词汇,虽然不是每个人都认可他,但我比较赞同。 Meszaros 使用 Test Double 这个术语来描述任何一个在测试中用于代替真实对象的虚拟对象,这个名称源于电影中替身演员的概念。随后 Meszaros 定义了五种典型的虚拟对象: Dummy 被传递但从不使用,通常只用于填充形式参数。 Fake 则具有可以正常工作的实现,但通常采用了一些不适合生产环境的便捷手段。(一个典型例子是内存数据库)。 Stub 在测试中总是返回固定的返回值,对于与测试无关的代码,通常直接忽略。 Spy 和 Stub 一样,但是它会记录自身被调用的情况。一个例子是邮件服务会记录发送了多少封邮件。 Mock 就是我们这里所谈论的:它根据预先编写的逻辑,基于调用者所期望的返回值。 在所有这些类型中,只有 mock 进行行为验证,而其他类型的虚拟对象通常只能进行状态验证。和其他类型一样,mock 在测试过程中也具有一些行为,以便让待测程序正常工作,但在设置和验证阶段有所不同。 为了进一步研究测试替身,我们需要扩展一下之前的例子。很多人只在真实的对象难以配合进行测试时才会使用测试替身。比如一个常见的用例:如果订单异常,那么就需要发送一封邮件通知。问题是在测试期间我们并不想真正给客户发一封邮件过去,所以我们为邮件系统创建一个我们可以控制操作的测试替身。 现在我们可以来研究 mock 和 stub 之间的区别了。假设我们正为发送邮件这一行为编写测试,代码大致如下: public interface MailService { public void send (Message msg); } public class MailServiceStub implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send (Message msg) { messages....

January 9, 2021 · Chenhe

互联网时代如何彻底拉黑一个人

现在账户太多啦噜,想彻底和一个人断绝关系还真是不容易。 所以这里就记录一下吧,以备不时之需。 以下所有情况均应当考虑到小号问题 常用部分 手机号:先加入黑名单(或者运营商云拦截黑名单),然后删除。 电子邮箱:加入黑名单。 微信:先拉黑后删除。 QQ:直接删除。 支付宝:先拉黑后删除。 淘宝:直接删除、删除相关收件地址。 其他服务 微博:直接拉黑。 百度网盘、贴吧:删除拉黑。 相册、云相册(QQ空间相册、微信朋友圈相册、百度网盘、时光相册、一刻相册):删除相关照片、退出相关共享影集。注意删除相关聊天的截图。 闲鱼:取消关注、拉黑。 京东:删除相关收件地址。 12306、携程、去哪、飞猪:删除相关旅客信息。 国际服务 Google:GMAIL 拉黑,PHOTOS 删除相关照片,退出家庭组。 Github:取消关注、取消星标。 Telegram:为对方删除聊天记录、删除联系人。 Facebook:拉黑。 Twitter:拉黑。 iCloud:拉黑、删除相关备份数据。

December 24, 2020 · Chenhe

详解三星OneUI后台与电池管理设置项

三星 OneUI 的应用自启与后台权限,以及电源管理一直比较乱(但关联关系做的比较智能)。其实也不仅是三星,Google 对大陆的流氓应用一直后知后觉,尽管近期多个系统底层更新不断收紧这方面政策,但脚步还是太慢,与此同时也造成不同系统版本(也称 API 等级)对后台的限制不一样,也就导致了许多云里雾里的设置。 这些本就零散的设置,再加上厂商对中国区的优化,还有翻译的不同,许多原因共同作用最终导致了 OneUI 这样的局面。其实如果能正确理解并应用这些设置,不仅能最大化省电,甚至在某些条件下还能够收到通知推送。我根据实验以及作为业余 Android 开发者的经验,总结下不同设置的实际意义。 **首先强调,网上目前大部分解读都是错误的,但依然感谢分享的同学为之做出的努力。**我也不能保证下面的解释完全正确,欢迎大佬指正。 设置项总览 以国行三星 S10 OneUI 2.5 为例。 三星与应用自启、后台、耗电优化相关的设置项入口一共有7个,他们分别是: 智能管理器 - 自动运行应用程序 设置 - 常规管理 - 电池 - 用电管理 - 自动运行应用程序 设置 - 应用程序 - 某个应用 - 电池 - 允许后台活动 设置 - 常规管理 - 电池 - 用电管理 - 深度休眠应用程序 设置 - 常规管理 - 电池 - 用电管理 - 让未使用的应用程序进入休眠 设置 - 应用程序 - 某个应用 - 电池 - 优化电池使用量 设置 - 应用程序 - 右上角菜单 - 特殊访问 - 优化电池使用量 这7个入口中实际上只有3个具体功能:其中 [1, 2, 3] 是一回事,暂且称之为自启与后台;[4, 5] 是一回事,暂且称之为休眠;[6, 7] 是一回事,称之为优化电池使用量。...

October 26, 2020 · Chenhe