Apache APISIX 和 Kong 都是开源的微服务 API 网关,那么在这两者之间,如何去做比较和选择呢? 这两个项目都有完善的文档和测试来覆盖,也有不少的生产用户在使用,所以不用去担心稳定性和它们的可持续发展,本文会从功能和性能这两个最直接和可验证的角度去做下对比。
功能从 API 网关核心功能点来看,两者均已覆盖:
功能
Apache APISIX
KONG
动态上游
支持
支持
动态路由
支持
支持
健康检查和熔断器
支持
支持
动态 SSL 证书
支持
支持
七层和四层代理
支持
支持
分布式追踪
支持
支持
自定义插件
支持
支持
REST API
支持
支持
CLI
支持
支持
更详细的比较:
功能
Apache APISIX
KONG
项目归属
Apache 软件基金会
Kong Inc.
技术架构
Nginx + etcd
Nginx + postgres
交流渠道
微信群、QQ 群、邮件列表、GitHub、meetup
GitHub、论坛、freenode
单核 QPS (开启限流和 prometheus 插件)
18000
1700
平均延迟
0.2 毫秒 ...
Apache APISIX 是一个很年轻的项目,2019 年 6 月份开源,7 月份加入到 CNCF 全景图,10 月份进入 Apache 孵化器,所以我会和大家分享一下 APISIX 是如何从 0 到 1,进入 Apache 孵化器的。
Apache APISIX 现在有 17 个 committer,分别来自 16 家不同的公司,是一个非常社区化的项目。每个 committer 有一票,决定版本的发布、选举新的 committer 和 PPMC 等比较重大的事情。
Apache WayApache Way 是大家都比较熟悉的概念:社区大于代码。烂代码可以改,Apache 的导师并不会指导你怎么写出更高水平的代码,他们更关心的是社区是否在健康的发展,只要有一个好的社区,烂代码一定会有更高水平的人进行重构,变成更好的代码。所以只要社区在,那这个项目就能够一直存活下去,这在 Apache 是最重要的。
邮件列表优先是另一个重要的点,没有在邮件列表中出现过的,就当做不存在。这在中国其实是一个非常大的挑战,大家在文化上和习惯上都不太喜欢用邮件:第一是时间不够及时,可能发一封邮件后隔 1-2 ...
wctype.hwctype.h 提供 ctype.h 里面函数的宽字符版本。
宽字符类型判断函数下面函数判断宽字符的类型。
iswalnum() 测试宽字符是否为字母数字
iswalpha() 测试宽字符是否为字母
iswblank() 测试这是否是一个宽空白字符
iswcntrl() 测试这是否是一个宽控制字符。
iswdigit() 测试这个宽字符是否是数字
iswgraph() 测试宽字符是否是可打印的非空格字符
iswlower() 测试宽字符是否为小写
iswprint() 测试宽字符是否可打印
iswpunct() 测试宽字符是否为标点符号
iswspace() 测试宽字符是否为空格
iswupper() 测试宽字符是否为大写
iswxdigit() 测试宽字符是否为十六进制数字
wctype(),iswctype()iswctype()是上一节各种宽字符类型判断函数的通用版本,必须与wctype()配合使用。
1int iswctype(wint_t wc, wctype_t desc);
iswctype()接受两个参数,第一个参数是一个需要判断类型的宽字符,第 ...
wchar.h宽字符使用两个或四个字节表示一个字符,导致 C 语言常规的字符处理函数都会失效。wchar.h 定义了许多宽字符专用的处理函数。
类型别名和宏wchar.h 定义了一个类型别名 wint_t,表示宽字符对应整数值。
wchar.h 还定义了一个宏 WEOF,表示文件结束字符 EOF 的宽字符版。
btowc(),wctob()btowc()将单字节字符转换为宽字符,wctob()将宽字符转换为单字节字符。
12wint_t btowc(int c);int wctob(wint_t c);
btowc()返回一个宽字符。如果参数是 EOF,或转换失败,则返回 WEOF。
wctob()返回一个单字节字符。如果参数是 WEOF,或者参数宽字符无法对应单个的单字节字符,则返回 EOF。
下面是用法示例。
123456789wint_t wc = btowc('B'); // 输出宽字符 Bwprintf(L"Wide character: %lc\n", wc);unsigned char c = wctob(wc);// 输出单字节 ...
time.htime_ttime_t 是一个表示时间的类型别名,可以视为国际标准时 UTC。它可能是浮点数,也可能是整数,Unix 系统一般是整数。
许多系统上,time_t 表示自时间纪元(time epoch)以来的秒数。Unix 的时间纪元是国际标准时 UTC 的1970年1月1日的零分零秒。time_t 如果为负数,则表示时间纪元之前的时间。
time_t 一般是32位或64位整数类型的别名,具体类型取决于当前系统。如果是32位带符号整数,time_t 可以表示的时间到 2038年1月19日03:14:07 UTC 为止;如果是32位无符号整数,则表示到2106年。如果是64位带符号整数,可以表示-2930亿年到+2930亿年的时间范围。
struct tmstruct tm 是一个数据结构,用来保存时间的各个组成部分,比如小时、分钟、秒、日、月、年等。下面是它的结构。
1234567891011struct tm { int tm_sec; // 秒数 [0, 60] int tm_min; // 分钟 [0, 59] int tm_hour; ...
string.hstring.h主要定义了字符串处理函数和内存操作函数。
字符串处理函数以下字符串处理函数,详见《字符串》一章。
strcpy():复制字符串。
strncpy():复制字符串,有长度限制。
strcat():连接两个字符串。
strncat():连接两个字符串,有长度限制。
strcmp():比较两个字符串。
strncmp():比较两个字符串,有长度限制。
strlen():返回字符串的字节数。
strchr(),strrchr()strchr()和strrchr()都用于在字符串中查找指定字符。不同之处是,strchr()从字符串开头开始查找,strrchr()从字符串结尾开始查找,函数名里面多出来的那个r表示 reverse(反向)。
12char* strchr(char* str, int c);char* strrchr(char *str, int c);
它们都接受两个参数,第一个参数是字符串指针,第二个参数是所要查找的字符。
一旦找到该字符,它们就会停止查找,并返回指向该字符的指针。如果没有找到,则返回 NULL。
下面是一个例子。
12345 ...
stdio.hstdio.h是 C 语言的标准 I/O 库,用于读取和写入文件,也用于控制台的输入和输出。
标准 I/O 函数以下函数用于控制台的输入和输出。
printf():输出到控制台,详见《基本语法》一章。
scanf():从控制台读取输入,详见《I/O 函数》一章。
getchar():从控制台读取一个字符,详见《I/O 函数》一章。
putchar():向控制台写入一个字符,详见《I/O 函数》一章。
gets():从控制台读取整行输入(已废除),详见《I/O 函数》一章。
puts():向控制台写入一个字符串,详见《I/O 函数》一章。
文件操作函数以下函数用于文件操作,详见《文件操作》一章。
fopen():打开文件。
fclose():关闭文件。
freopen():打开一个新文件,关联一个已经打开的文件指针。
fprintf():输出到文件。
fscanf():从文件读取数据。
getc():从文件读取一个字符。
fgetc():从文件读取一个字符。
putc():向文件写入一个字符。
fp ...
stdlib.h类型别名和宏stdlib.h 定义了下面的类型别名。
size_t:sizeof 的返回类型。
wchar_t:宽字符类型。
stdlib.h 定义了下面的宏。
NULL:空指针。
EXIT_SUCCESS:函数运行成功时的退出状态。
EXIT_FAILURE:函数运行错误时的退出状态。
RAND_MAX:rand() 函数可以返回的最大值。
MB_CUR_MAX:当前语言环境中,多字节字符占用的最大字节数。
abs(),labs(),llabs()这三个函数用于计算整数的绝对值。abs()用于 int 类型,labs()用于 long int 类型,llabs()用于 long long int 类型。
123int abs(int j);long int labs(long int j);long long int llabs(long long int j);
下面是用法示例。
12345// 输出 |-2| = 2printf("|-2| = %d\n", abs(-2));// 输出 |4| = 4printf("|4 ...
stdint.h固定宽度的整数类型stdint.h 定义了一些固定宽度的整数类型别名,主要有下面三类。
宽度完全确定的整数intN_t,比如int32_t。
宽度不小少于某个大小的整数int_leastN_t,比如int_least8_t。
宽度不小于某个大小、并且处理速度尽可能快的整数int_fastN_t,比如int_fast64_t。
上面所有类型都是有符号的,类型名前面可以加一个前缀u,表示无符号类型,比如uint16_t。
C 语言标准要求至少定义以下类型。
int8_t uint8_t
int16_t uint16_t
int32_t uint32_t
int64_t uint64_t
int_least8_t uint_least8_t
int_least16_t uint_least16_t
int_least32_t uint_least32_t
int_least64_t uint_least64_t
int_fast8_t uint_fast8_t
int_fast16_t uint_fast16_t
int_fast32_t uint_fast32_t
i ...
signal.h简介signal.h提供了信号(即异常情况)的处理工具。所谓“信号”(signal),可以理解成系统与程序之间的短消息,主要用来表示运行时错误,或者发生了异常事件。
头文件signal.h定义了一系列宏,表示不同的信号。
SIGABRT:异常中止(可能由于调用了 abort() 方法)。
SIGFPE:算术运算发生了错误(可能是除以 0 或者溢出)。
SIGILL:无效指令。
SIGINT:中断。
SIGSEGV:无效内存访问。
SIGTERM:终止请求。
上面每个宏的值都是一个正整数常量。
signal()头文件signal.h还定义了一个signal()函数,用来指定某种信号的处理函数。
1signal(SIGINT, handler);
signal()接受两个参数,第一个参数是某种信号的宏,第二个参数是处理这个信号的函数指针handler。
信号处理函数handler接受一个 int 类型的参数,表示信号类型。它的原型如下。
1void (*func)(int);
handler函数体内部可以根据这个整数,判断到底接受到了哪种信号,因为多个信号可以共用同 ...
