golang 规则引擎      2023-02-12

写在前面

目前反作弊项目的核心项目是规则引擎,实现规则引擎在类似 python/php/javascrip 之类的解释型语言中可以直接通过 eval 之类的函数来模拟实现,但是在编译型语言比如 Go 实现就没那么容易了。

原因在于解释型语言本身就是动态解释执行的,可以在运行时把输入的文本作为语言本身去解释执行,但是编译型语言是去运行编译之后的机器码,此时能动态执行的内容非常有限且必须依靠语言特性。比如在 Go 语言内只能通过反射实现一些有限的动态执行,反射是完全依靠 interface 的内部实现。

解释器过程

规则引擎其实可以看作一个简化的单行脚本语言,所以要通过 Go 实现一个规则引擎其实就是使用 Go 实现一个简化版的脚本语言解释器。

我们来看看实现一个解释器的基本流程:

解释器流程

词法分析(Lexical analysis)

词法分析**(**lexical analysis)是计算机科学中将字符序列转换为单词(Token)序列的过程。

完成词法分析任务的程序称为词法分析程序或词法分析器或扫描器,核心任务是扫描、识别单词且对识别出的 Token 给出定性、定长的处理。

词法分析器一般从左至右地对源程序进行扫描,按照语言的词法规则识别各类 Token 。

Token

Token 是用于描述与归类从文本中分解出来的最小描述单元的一种结构。

词法分析器通常只识别Token ,但是不会关心 Token 之间的关系。例如:词法分析器能够将括号识别为单词,但并不保证括号是否匹配。

Token 序列本身并没有实际意义,必须通过语法分析将 Token 作为输入进行语法分析来保证 Token 的可用性和有意义的。

语法分析(Syntax analysis)

在计算机科学中,语法分析(syntactic analysis)是根据某种给定的形式文法对由 Token 序列构成的输入文本进行分析并确定其语法结构的一种过程。

语法分析器(parser)通常是作为编辑器或者解释器的组件出现的,它的作用是进行语法检查、并构建由输入的 Token 组成的数据结构,比如抽象语法树(AST)等层次化的数据结构。

实现 INI 解析

无12      2021-10-28

历史背景

受限于技术栈积累,以前后端服务技术栈全部使用 PHP 实现,采用标准 的lnmp架构。

但是随着流量及用户的迅速增长和业务复杂度的不断增高,我们尝试将 PHP 单体服务逐个拆分成多个独立的PHP子服务,部分上解决了业务复杂度上升导致的服务不可维护问题,但是因为 PHP 的动态语言特性导致的一些的问题无法解决:

  1. 运行效率较低,随着用户和流量的不断攀升,PHP 服务所依赖的资源增长迅速,甚至在一段时间出现了每天都要扩容线上资源的情况。在流量较低时成本问题一般不会引起重视,但是在流量十倍百倍增加时所增加的成本情况就不容乐观了。
  2. 部署流程越来越繁琐,随着机器数量的增加,即使使用了自动化部署,部署时间也越来越久。
  3. 动态语言因为没有类型约束等原因,在项目复杂度上升团队扩大时导致的协作效率成本和维护成本也在不断升高。

为什么选择 Golang?

基于以上原因,所以我们开始调研并尝试将部分核心业务使用Golang 进行重构。选择 Golang 的理由如下:

  1. 强类型语言及 gofmt等工具带来团队协作效率提升的同时降低后期维护成本。
  2. 简单好记的关键字和语法,不会带来太高的学习成本。团队成员在学习一段时间后即可上手开发项目。
  3. golang 因为静态语言特性带来极高的执行效率提升同时因为其极快的编译速度也不会引入额外的编译时间成本。
  4. 跨平台交叉编译,编译后的二进制几乎无任何平台依赖,真正实现一处编译处处运行,极高的提升了代码部署效率。
  5. 强大的标准库,golang标准库基本覆盖了开发网络应用的大部分基础能力,标准库没有的功能也可以找到三方库支持,避免重复造轮子。
  6. 原生并发支持,一个 go 关键字即可享受到 golang 的协程并发能力。另外得益于管道等的加持,极大简化了并发编程时引入的各类数据共享同步问题。

另外还有 足够轻量的协程,支持GC,内嵌C 支持,提供足够丰富简编的工具链 等优点,这里就不一一罗列了。

重构服务迁移

在流量快速增长的项目内替换核心服务,用网上一句流行的话来说就是『开着飞机换发动机』,替换的同时需要确保业务稳定性不受影响。

因为我们的 App端一直保持着双周迭代的节奏,所以采用了跟随 APP 迭代节奏小

golang context 协程      2020-12-18
### 由"并发控制"开始 golang语言层面提供了协程支持为我们开发高并发程序带来巨大便利,但是就因为太容易开辟协程引入了一个大部分时候我们都容易忽视的问题:协程泄露。 阅读下以下代码: ```go func main() { r := gin.Default() r.GET("/run", func(c *gin.Context) { for { fmt.Println
gdb mac golang      2020-08-21
## mac 下 gdb 安装及错误排查 ### 使用 brew 安装 gdb ```brew install gdb``` ### gdb签名 安装后直接使用会提示『Unable to find Mach task port for process-id』错误。这是因为 macos 下gdb 没有权限去访问其他进程,此时需要使用自签名系统证书并给 gdb 程序签名。 1. 在钥
golang redis 分布式 定时任务      2018-11-08
### 背景 最近项目中的定时任务越来越多,为了防止任务重复执行曾经使用过的方案: - 只启用了一个节点。 - 固定循环间隔,使用分布式事务锁。 第一种方案没有容错机制,当单个节点宕机,所有定时任务都无法正常执行。 第二种方案不能跟cron一样灵活设定时间,比如需要设定每天1点执行就必须借助数据库或者其他存储手段去轮询,非常低效。 在对比了市面上主流的分布式定时任务库后,发现要不就是过
php laravel ioc 服务容器      2018-06-07
Container可以说是Laravel框架的核心。文档上称其为『服务容器』,顾名思义通过维护一个类容器来实现类的IoC控制反转。 ## ioc实例 在解读源码前需要了解IoC。Ioc全称Inversion of Control,意为控制反转。 这里用一个最常见的支付场景来举例。 ```php //支付类 class Pay{ private $payway;
php 进程 进程通信      2017-09-18
### 一,引言 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是,在系统调度多个cpu的时候,一个程序的基本单元。进程对于大多数的语言都不是一个陌生的概念,作为"世界上最好的语言PHP"当然也例外。 ### 二,环境 php中的进程是以扩展的形式来完成。通过这些扩展,我们能够很轻松的完成进程的一系列动作。 - pcntl扩展:主要的进程扩展,完成进程创建于等待操作
php 函数 二进制      2017-04-18
摘要: PHP作为一门为web而生的服务器端开发语言,被越来越多的公司所采用。其中不乏大公司,如腾迅、盛大、淘米、新浪等。在对性能要求比较高的项目中,PHP也逐渐演变成一门前端语言,用于访问后端接口。或者不同项目之间需要共享数据的时候,通常可以抽取出数据层,通过PHP来访问。

PHP作为一门为web而生的服务器端开发语言,被越来越多的公司所采用。其中不乏大公司,如腾迅、盛大、淘米、新浪等。在对性能要求比较高的项目中,PHP也逐渐演变成一门前端语言,用于访问后端接口。或者不同项目之间需要共享数据的时候,通常可以抽取出数据层,通过PHP来访问。

写在前面的话

本文介绍的是通过二进制数据包的方式通信,演示语言为PHP和Golang。PHP提供了pack/unpack函数来进行二进制打包和二进制解包。在具体讲解之前,我们先来了解一些基础知识。

什么是字节序

在不同的计算机体系结构中,对于数据(比特、字节、字)等的存储和传输机制有所不同,因而引发了计算机领域中一个潜在但是又很重要的问题,即通信双方交流的信息单元应该以什么样的顺序进行传送。如果达不成一致的规则,计算机的通信与存储将会无法进行。目前在各种体系的计算机中通常采用的字节存储机制主要有两种:大端(Big-endian)和小端(Little-endian)。这里所说的大端和小端即是字节序。

MSB和LSB

  • MSB是Most Significant Bit/Byte的首字母缩写,通常译为最重要的位或最重要的字节。它通常用来表示在一个bit序列(如一个byte是8个bit组成的一个序列)或一个byte序列(如word是两个byte组成的一个序列)中对整个序列取值影响最大的那个bit/byte。

  • LSB是Least Significant Bit/Byte的首字母缩写,通常译为最不重要的位或最不重要的字节。它通常用来表明在一个bit序列(如一个byte是8个bit组成的一个序列)或一个byte序列(如word是两个byte组成的一个序列)中对整个序列取值影响最小的那个bit/byte。

  • 对于一个十六进制int类型整数0x12345678来说,0x12就是MSB,0x78就是LSB。而对于0x78这个字节而言,它的二进制是01111000,那么最左边的那个0就是MSB,最右边的那个0就是LSB。

大端序

  • 大端序又叫网络字节序。大端序规定高位字节在存储

字符串 ascii php 函数      2017-04-18
最近遇到字符串编码相关的一些问题(比如部分字符串echo后显示为乱码,需要用到bin2hex转换为16进制显示),发现对部分ascii相关的字符串函数还是理解不够透彻,所以在此整理记录下。 ##ord函数 ```ord(sting) ``` ord()函数用来取字符串的**首个字符**的 ASCII 值 ##chr函数 ``` string chr() ``` chr()函数从指定的 ASCI
heka elk 架构 日志      2017-04-17
目前主流的后端日志都采用的标准的elk模式(Elasticsearch,Logstash,Kinaba),分别负责日志存储,收集和日志可视化。 不过介于我们的日志文件多样,分布在各个不同的服务器,各种不同的日志,为了日后方便二次开发定制。所以采用了Mozilla仿照Logstash使用golang开源实现的Heka。 #### 整体架构图 采用Heka,ElasticSearch和Kiba