LeeYzero的博客

业精于勤,行成于思

0%

有些人在碰到问题时,就想:“我知道,我可以使用正则表达式。”现在,他们就有了两个问题。
– by Jamie “jwz” Zawinski, 1997年 8月

什么是正则表达式

正则表达式(Regular Expression),通常缩写为regex或regexp,是一种在文本中进行搜索和替换的模式描述语言。它使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。正则表达式是由普通字符(例如:字母和数字)以及元字符组成的。

这篇slide 描述正则表达式的发展历史。
regular-expressions是学习正则表达式的一个非常好的网站。

初识正则表达式

我们在日常中可能已经使用过正则表达式,比如我们在电脑中查找所有doc文档时,会使用*.doc搜索,这个就是正则表达式。其中*为元字符,表示可以匹配任意字符。.doc是普通字符,表示后续为.doc的文档。

当然这是一个比较简单的例子,正则表达式的功能非常强大,它提供了很多的特性,非常灵活。

在自己的日常开发过程中,有两种场景使用正常表达式比较多:

  • 使用Linux命令,如grepsedawk中的提供的正则表达式能力查询日志。
  • 使用各语言,如PythonPHPGo中提供的正则表达式库在大文本中查找目标字符串。

熟练掌握正则表达式,在处理字符匹配的问题上可以事半功倍。

Read more »

工欲善其事,必先利其器。作为一个曾经的资深vim党,在使用过CodeServer后,基本上不再使用vim了。CodeServer作为vscode的云端IDE,再也不用搭建本地开发环境了。之前介绍了 CentOS搭建CodeServer环境,只需要几步,就可以搭建自己的云端IDE,非常方便。

vscode-go是vscode中针对Go语言的扩展,提供了丰富的特性,包括:

  • 智能感知(IntelliSense)
  • 代码导航(Code navigation)
  • 代码编辑(Code editing)
  • 诊断(Diagnostics)
  • 增强的测试和调试支持(Enhanced support for testing and debugging)

vscode提供了语言无关的调试适配协议 Debug Adapter Protocol,使用各语言可以基于vscode的扩展实现各自的调试器。对于Go语言,其实现为dlv-dap

本文主要介绍在vscode如何使用vscode-go提供的debugging能力对go代码进行调试。

Read more »

缘起

最近出现一例json.Unmarshal导致的精度丢失引发的线上问题,虽然这个问题在被及时发现,未对业务造成损失,但细挖这个问题的原因仍然比较有意思。这篇文章会从技术层面深入分析json.Unmarshal精度丢失的原因以及处理建议,以避免后续开发过程中再次踩坑。

Part1 中,我们着重说明了json.Unmarshal处理大整数可能出现精度丢失的问题,但遗留了一个问题,即大整数置换成浮点数时,为什么会造成精度丢失,在这篇文章中我会详细解释原因。

Go语言对浮点数的处理遵循IEEE-745标准,该标准规定了浮点数在计算机中的二进制表示以及舍入方式,下面先补充一些基础知识,然后再结合 Part1 中的case,分析精度丢失的原因。

十进制与二进制

十进制用0-9表示,逢十进一,同时二进制用0和1表示,逢二进一。而每个位可以使用位的值乘以位的权重表示,直接看例子:

十进制12.34可以表示为:
12.34 = 1×101 + 2×100 + 3×10−1 + 4×10−2 = 12.34

同理二进制101.11也可以表示为:

101.11 = 1×22 + 0×21 + 1×20 + 1×2−1 + 1×2−2 = 4 + 0 + 1 + 1/2 + 1/4 = 5.75

十进制小数点向左移动1位相当于将该数除以10,向右移动1位相当于将该数乘以10。
例如:123/10 = 12.3,12.3×10 = 123。

同理,二进制小数点向左移动1位相当于将该数除以2,向右移动1位相当于将该数乘以2。

例如:11/2 = 1.1,1.1x2 = 11

Read more »

缘起

最近出现一例json.Unmarshal导致的精度丢失引发的线上问题,虽然这个问题在被及时发现,未对业务造成损失,但细挖这个问题的原因仍然比较有意思。这篇文章会从技术层面深入分析json.Unmarshal精度丢失的原因以及处理建议,以避免后续开发过程中再次踩坑。

在分析这个问题的过程中,发现涉及Go对浮点数数值的处理,又涉及IEEE-745标准中的一些细节,放在一篇文章中会增大文章的阅读难度,故拆分成了两个部分:

  • Part1: 引出json.Unmarshal处理大整数可能出现精度丢失的问题,并浅层次分析原因以及解决办法。
  • Part2: 先补充IEEE-745的背景知识,然后解释为什么json.Unmarshal处理大整数可能会出现精度丢失。

示例

这个问题的现象是,原始json string是一个字典,其中包含了一个大整数,在业务场景中,需要向该字典中追加一些字段,然后再序列化后进行存储。为了使用上的方便,代码中使用map[string]any去接收json.Unmarshal的结果,然后再使用json.Marshal序列化,结果发现序列化后的大整数跟原始大整数不致。

下面代码片段做了一些简化,同时忽略错误处理细节:

1
2
3
4
5
6
7
str := `{"id":16505201442738640729}`

var m map[string]any
json.Unmarshal([]byte(str), &m)

data, _ := json.Marshal(&m)
fmt.Println(string(data))

上面代码片段输出:

1
{"id":16505201442738640000}

原始json string中,id的值是16505201442738640729,经过json.Unmarshal和json.Marshal后,id的值变成了16505201442738640000,看起来出现了精度有丢失。

Read more »

虽然PHP做业务后端逐步在被Go等语言替代,但使用PHP做简单业务封装和数据组装时,开发效率依然是比较高效的。使用Nginx运行PHP的常用方法是FastCGI模块。PHP-FPM (FastCGI进程管理器)极大地提高了你的Nginx+PHP环境的性能,所以这对高负载的网站很有用。本教程介绍在CentOS8上安装Nginx并配置PHP-FPM的步骤,以便后续参考。

依赖环境

  • CentOS8
  • 拥有sudo权限
  • 更新dnf
1
sudo dnf update 

Step1 安装Nginx

Nginx在仓库中已经存在,可以使用dnf工具直接安装:

1
sudo dnf install nginx

启动Nginx服务,同时让Nginx服务在系统启动时自动启动。

1
2
sudo systemctl enable nginx
sudo systemctl start nginx

检查nginx是否已启动

1
sudo systemctl status nginx

如果您的系统上启用了防火墙,请确保打开HTTP端口以供远程系统访问。HTTP为80端口,HTTPS,为443端口。

1
2
3
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --reload

在浏览器使用ip访问主机器,看是否能访问到nginx的默认页面了呢?

Read more »

最近半年主要在对一个10余年的商业化系统进行重构。对于商业化系统来讲,普遍存在状态多、链路长、业务逻辑复杂等特点。加上系统设计之初并未考虑到后续业务的发展形态,在承接业务需求时,不断打补丁,存在很多ad hoc方案,系统最终变成了一个”大泥球“,导致的问题是业务迭代效率低,代码变更故障率高。这篇文章主要对如何解决复杂问题谈谈自己的一些思考,供大家参考。

思考框架

首先谈谈什么是复杂问题。复杂问题是一个系统性问题,它的特点是规模大、维度多、关系复杂。在面对大型或复杂问题时,我们需要先找一样思想武器,或者说思考框架,可能简单归结为:分治知识抽象

分治可以把问题分割为规模更小且易于处理的若干子问题,这样就可以运用相似的知识来解决这些子问题,而使用抽象有助于进行推理和判断。分治、知识和抽象的有效性在于它们能够帮助我们在不变的智力条件理解和解决不断增长的问题

Read more »

charles

Charles 是一个功能强大的网络代理工具,常用于抓包、分析网络请求、模拟网络环境等操作。本入门指南将帮助你快速上手 Charles,掌握其基本用法和常用功能。

注: Charles是付费软件,白嫖党自行搜索破解教程。

下载安装

访问 Charles 官方网站下载对应操作系统的安装包,按照提示完成安装。

配置Charles

Mac端配置

1、链接Wifi,正常上网

2、安装Charles根证书

Help > SSL Proxying > Install Charles Root Certificate

3、信任Charles根证书

打开钥匙串,搜索刚才安装好的Charles根证书,点击Charles Proxy CA,展开的Trust一栏,点击Always Trust

4、开启SSL代理

Proxy > SSL Proxying Setting > SSL Proxying > Enable SSL Proxying

5、开启HTTP代理

Proxy > Proxy Settings > 将HTTP端口号设置为8888

6、打开Charles,开启录制

Proxy > Start Recoding

移动端设备端配置

1、移动设备和Mac端链接到同一Wifi,确保它们在同一网段。

2、查看Charles代理服务器地址和端口

Help > SSL Proxying > Install Charles Root Certificate > Install Charles Root Certificate on a Mobile Device or Remote Browser

charles

3、配置代理

找到链接的Wifi > 设置(i圆圈图标) > 配置代理 > 手动 > 填写第2步中服务器地址和端口号

charles

移动设备端链接到代理服务器后,Mac端会出现链接认证提示,点击允许。

4、打开Safari,并输入网址chls.pro/ssl,下载证书

5、手机的设置 > 通用 > 描述文件与设备管理,找到Charles,点击验证

6、手机设置 > 通用 > 关于本机 > 证书信任设置,确认Charles Proxy CA的信任开关处于打开状态

抓取HTTPS包

Mac端为指定请求设置代理

Proxy > SSL Proxying Setting > SSL Proxying > Enable SSL Proxying > Add > *:443

过滤网络请求

通常情况下,我们需要对网络请求进行过滤,只监控向指定服务器上发送的请求。

Proxy > Recording Settings > Include > Add > 填写要过滤的主机地址(域名)和 端口号。

限制网速

Charles可以模拟慢速网络或者高延迟的网络。

Proxy > Throttle Setting > 勾选 Enable Throttling > only for selected host 可以设置指定的主机访问进行限制网络

Map

Charles的Map功能分 Map RemoteMap Local 两种。Map Remote 是将指定的网络请求重定向到另一个网址请求地址,Map Local 是将指定的网络请求重定向到本地文件。

Map Remote

需要分别填写网络重定向的源地址和目的地址,对于不需要限制的条件,可以不填。这个功能在做Web开发是特别有用,可以比较方便地将移动设备的请求转发至后端服务器,比如开发机。

Tool > Map Remote > Enable Map Remote > Add

Map Local

对于 Map Local 功能,我们需要填写的重定向的源地址和本地的目标文件。对于有一些复杂的网络请求结果,我们可以先使用 Charles 提供的 “Save Response…” 功能,将请求结果保存到本地(如下图所示),然后稍加修改,成为我们的目标映射文件。

然后将一个指定的网络请求通过 Map Local 功能映射到了本地的一个经过修改的文件中。

Tool > Map Local > Enable Map Local > Add

Rewrite

Map Local 有一个潜在的问题,就是其返回的 Http Response Header 与正常的请求并不一样。这个时候如果客户端校验了 Http Response Header 中的部分内容,就会使得该功能失效。解决办法是同时使用 Map Local 和 Rewrite 功能,将相关的 Http 头 Rewrite 成我们希望的内容。

Rewrite 功能是对某一类网络请求进行一些正则替换,以达到修改结果的目的。

参考资料

channel是一种数据结构,在Go语言中用于协程间通信,是Go语言区别于其它语言的重要特性。Go语言原生支持channel,配合Go语言原生对并发的支持,让并发编程变得简单。正如Share Memory By Communicating对Go并发编程的建议:

Do not communicate by sharing memory; instead, share memory by communicating.

和传统并发编程使用同步原语共享内存不同,Go并发编程强调通过channel在协程间通信来共享内存,这实际上是对CSP(Communicating Sequential Processes)并发模型的一种实现。

从应用层面来讲,channel和协程(goroutine)是配合使用的,本文主要从实现层面介绍channel的内部原理,但不会涉及太多协程管理调度相关的知识。本文先介绍channel的基本用法,然后介绍channel内部数据结构以及实现原理,最后介绍使用channel时应该注意的一些问题。

Read more »

map又称映射表或关联数组,是一种常用的数据结构。它由一组<key, value>组成,每个key只出现一次。Go语言原生支持了map数据结构,正如 Go maps in action 中所说:

One of the most useful data structures in computer science is the hash table. Many hash table implementations exist with varying properties, but in general they offer fast lookups, adds, and deletes. Go provides a built-in map type that implements a hash table.

简单来说就是因为 hash table 是非常有用,并且提供了快速的查找、添加、删除特性,所以Go语言提供了map类型,它的底层是使用的hash table

刚接触Go语言时,有两点比较困惑:

  • 对map排序时,需要先对取出map中所有的key,对key排好序后,通过排好序的key查找value。
  • 遍历map时,每次得到的结果顺序都不一样。

随着对Go语言的了解,虽然这两个问题早以有了答案,但仍然想要了解一下map的内部实现原理,于是便有了这篇文章。

在这篇文章中,先简要介绍map的基本用法,再深入map的内部实现原理,最后介绍使用map时需要注意的问题。

Read more »

今年最后一天上班,下午没啥事,总结下Go语言的接口。接口是Go语言区别与其它语言的重要语言特性,也是我最喜欢的Go语言特性之一。Go的接口除了提供多态的能力外,它还是Go反射的基础。Go是一门静态语言,Go接口能够在编译期检查语法规则,同时具备像动态语言那样使用 ducking typing 实现接口。

我一直比较好奇Go的接口内部是如何实现。看了几篇文章,也看了runtime包中的部分实现。发现大部分文章都是从汇编的角度去分析,对我来说,我对汇编了解的不多,也不需要深入那么细节,我最终的目的是想通过了解Go接口的内部实现,让自己避免一些语言上的坑,同时能够写出更高效的代码。最终发现还是 Russ Cox 的文章 Go Data Structures: Interfaces 在一个相对高的层次介绍了Go的接口特性,但又没有深入汇编细节,比较容易理解,也达到了我的目的。

本文通过示例介绍接口的基本用法,然后引出接口的内部数据结构,再介绍接口的动态类型转换和接口派发原理以及效率,最后介绍一些需要注意的问题。

接口初识

接口是对实现的抽象。在Go语言中,接口是一组方法签名,使用interface关键字表示,Go中接口具有如下特点:

  • 接口实现是隐式的。
  • interface{}是一种静态类型。
  • 接口类型可以动态检查和转换
Read more »