最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

亿级用户 PC 主站的 PHP7 升级实践

  • 2017-01-11
  • 本文字数:8049 字

    阅读完需:约 26 分钟

伴随业务的增长,系统压力也在不断增加,再加上机房机架趋于饱和,无法更加有效应对各种突发事件。在这样的情况下,PC 主站升级为 PHP 7,有哪些技术细节可以分享?

背景

新浪微博在 2016 年 Q2 季度公布月活跃用户(MAU)较上年同期增长 33%,至 2.82 亿;日活跃用户(DAU)较上年同期增长 36%,至 1.26 亿,总注册用户达 8 亿多。PC 主站作为重要的流量入口,承载部分用户访问和流量落地,其中我们提供的部分服务(如:头条文章)承担全网所有流量。

随着业务的增长,系统压力也在不断的增加。峰值时,服务器 Hits 达 10W+,CPU 使用率也达到了 80%,远超报警阈值。另外,当前机房的机架已趋于饱和,遇到突发事件,只能对非核心业务进行降低,挪用这些业务的服务器来进行临时扩容,这种方案只能算是一种临时方案,不能满足长久的业务增长需求。再加上一年一度的三节(圣诞、元旦、春节),系统需预留一定的冗余来应对,所以当前系统面临的问题非常严峻,解决系统压力的问题也迫在眉急。

面对当前的问题,我们内部也给出两套解决方案同步进行。

  • 方案一:申请新机房,资源统一配置,实现弹性扩容。
  • 方案二:对系统进行优化,对性能做进一步提升。

针对方案一,通过搭建与新机房之间的专线与之打通,高峰时,运用内部自研的混合云 DCP 平台,对所有资源进行调度管理,实现了真正意义上的弹性扩容。目前该方案已经在部分业务灰度运行,随时能对重点业务进行小流量测试。

针对方案二,系统层面,之前做过多次大范围的优化,比如:

  • 将 Apache 升级至 Nginx
  • 应用框架升级至 Yaf
  • CPU 计算密集型的逻辑扩展化
  • 弃用 smarty
  • 并行化调用

优化效果非常明显,如果再从系统层面进行优化,性能可提升的空间非常有限。好在业界传出了两大福音,分别为 HHVM 和 PHP7。

方案选型

在 PHP7 还未正式发布时,我们也研究过 HHVM(HipHop Virtual Machine),关于 HHVM 更多细节,这里就不再赘述,可参考官方说明。下面对它提升性能的方式进行一个简单的介绍。

默认情况下,Zend 引擎先将 PHP 源码编译为 opcode,然后 Zend 解析引擎逐条执行。这里的 opcode 码,可以理解成 C 语言级的函数。而 HHVM 提升性能方式为替代 Zend 引擎将 PHP 代码转换成中间字节码(HHVM 自己的中间字节码,通常称为中间语言),然后在运行时通过即时(JIT)编译器将这些字节码转换成 x64 的机器码,类似于 Java 的 JVM。

HHVM 为了达到最佳优化效果,需要将 PHP 的变量类型固定下来,而不是让编译器去猜测。Facebook 的工程师们就定义一种 Hack 写法,进而来达到编译器优化的目的,写法类似如下:

复制代码
<?hh
class point {
public float $x, $y;
function __construct(float $x, float $y) {
$this->x = $x;
$this->y = $y;
}
}

通过前期的调研,如果使用 HHVM 解析器来优化现有业务代码,为了达到最佳的性能提升,必须对代码进行大量修改。另外,服务部署也比较复杂,有一定的维护成本,综合评估后,该方案我们也就不再考虑。

当然,PHP7 的开发进展我们也一直在关注,通过官方测试数据以及内部自己测试,性能提升非常明显。

令人兴奋的是,在去年年底(2015 年 12 月 04 日),官方终于正式发布了 PHP7,并且对原生的代码几乎可以做到完全兼容,性能方面与 PHP5 比较能提升达一倍左右,和 HHVM 相比已经是不相上下。

无论从优化成本、风险控制,还是从性能提升上来看,选择 PHP7 无疑是我们的最佳方案。

系统现状以及升级风险

微博 PC 主站从 2009 年 8 月 13 日发布第一版开始,先后经历了 6 个大的版本,系统架构也随着需求的变化进行过多次重大调整。截止目前,系统部分架构如下。

从系统结构层面来看,系统分应用业务层、应用服务层,系统所依赖基础数据由平台服务层提供。

从服务部署层面来看,业务主要部署在三大服务集群,分别为 Home 池、Page 池以及应用服务池。

为了提升系统性能,我们自研了一些 PHP 扩展,由于 PHP5 和 PHP7 底层差别太大,大部分 Zend API 接口都进行了调整,所有扩展都需要修改。

所以,将 PHP5 环境升级至 PHP7 过程中,主要面临如下风险:

  • 使用了自研的 PHP 扩展,目前这些扩展只有 PHP5 版本,将这些扩展升级至 PHP7,风险较大。
  • PHP5 与 PHP7 语法在某种程度上,多少还是存在一些兼容性的问题。由于涉及主站代码量庞大,业务逻辑分支复杂,很多测试范围仅仅通过人工测试是很难触达的,也将面临很多未知的风险。
  • 软件新版本的发布,都会面临着一些未知的风险和版本缺陷。这些问题,是否能快速得到解决。
  • 涉及服务池和项目较多,基础组件的升级对业务范围影响较大,升级期间出现的问题、定位会比较复杂。

对微博这种数亿用户级别的系统的基础组件进行升级,影响范围将非常之大,一旦某个环节考虑不周全,很有可能会出现比较严重的责任事故。

PHP7 升级实践

1. 扩展升级

一些常用的扩展,在发布 PHP7 时,社区已经做了相应升级,如:Memcached、PHPRedis 等。另外,微博使用的 Yaf、Yar 系列扩展,由于鸟哥 (laruence) 的支持,很早就全面支持了 PHP7。对于这部分扩展,需要详细的测试以及现网灰度来进行保障。

PHP7 中,很多常用的 API 接口都做了改变,例如 HashTable API 等。对于自研的 PHP 扩展,需要做升级,比如我们有个核心扩展,升级涉及到代码量达 1500 行左右。

新升级的扩展,刚开始也面临着各式各样的问题,我们主要通过官方给出的建议以及测试流程来保证其稳定可靠。

官方建议

  • 在 PHP7 下编译你的扩展,编译错误与警告会告诉你绝大部分需要修改的地方。
  • 在 DEBUG 模式下编译与调试你的扩展,在 run-time 你可以通过断言捕捉一些错误。你还可以看到内存泄露的情况。

测试流程

  • 首先通过扩展所提供的单元测试来保证扩展功能的正确性。

  • 其次通过大量的压力测试来验证其稳定性。
  • 然后再通过业务代码的自动化测试来保证业务功能的可用性。

  • 最后再通过现网流量灰度来确保最终的稳定可靠。

整体升级过程中,涉及到的修改比较多,以下只简单列举出一些参数变更的函数。

(1)addassocstringl 参数 4 个改为了 3 个。

复制代码
//PHP5
add_assoc_stringl(parray, key, value, value_len);
//PHP7
add_assoc_stringl(parray, key, value);

(2)addnextindex_stringl 参数从 3 个改为了 2 个。

复制代码
//PHP5
add_assoc_stringl(parray, key, value, value_len);
//PHP7
add_assoc_stringl(parray, key, value);

(3)RETURN_STRINGL 参数从 3 个改为了 2 个。

复制代码
//PHP5
RETURN_STRINGL(value, lengthdup);
//PHP7
RETURN_STRINGL(value, length);

(4)变量声明从堆上分配,改为栈上分配。

复制代码
//PHP5
zval* sarray_l;
ALLOC_INIT_ZVAL(sarray_l);
array_init(sarray_l);
//PHP7
zval sarray_l;
array_init(&sarray_l);

(5)zendhashgetcurrentkey_ex 参数从 6 个改为 4 个。

复制代码
//PHP5
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex ({1}
HashTable* ht,
char** str_index,
uint* str_length,
ulong* num_index,
zend_bool duplicate,
HashPosition* pos);
//PHP7
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(
const HashTable *ht,
zend_string **str_index,
zend_ulong *num_index,
HashPosition *pos);

更详细的说明,可参考官方 PHP7 扩展迁移文档: https://wiki.PHP.net/PHPng-upgrading。

2. PHP 代码升级

整体来讲,PHP7 向前的兼容性正如官方所描述那样,能做到 99% 向前兼容,不需要做太多修改,但在整体迁移过程中,还是需要做一些兼容处理。

另外,在灰度期间,代码将同时运行于 PHP5.4 和 PHP7 环境,现网灰度前,我们首先对所有代码进行了兼容性修改,以便同一套代码能同时兼容两套环境,然后再按计划对相关服务进行现网灰度。

同时,对于 PHP7 的新特性,升级期间,也强调不允许被使用,否则代码与低版本环境的兼容性会存在问题。

接下来简单介绍下升级 PHP7 代码过程中,需要注意的地方。

(1)很多致命错误以及可恢复的致命错误,都被转换为异常来处理,这些异常继承自 Error 类,此类实现了 Throwable 接口。对未定义的函数进行调用,PHP5 和 PHP7 环境下,都会出现致命错误。

复制代码
undefine_function();

错误提示:

复制代码
PHP Fatal error:  Call to undefined function
undefine_function() in /tmp/test.PHP on line 4

在 PHP7 环境下,这些致命的错误被转换为异常来处理,可以通过异常来进行捕获。

复制代码
try {
undefine_function();
}
catch (Throwable $e) {
echo $e;
}

提示:

复制代码
Error: Call to undefined function undefine_function() in /tmp/test.PHP:5 Stack trace:
#0 {main}

(2)被 0 除,PHP 7 之前,被 0 除会导致一条 E_WARNING 并返回 false 。一个数字运算返回一个布尔值是没有意义的,PHP 7 会返回如下的 float 值之一。

  • +INF
  • -INF
  • NAN

如下:

复制代码
var_dump(42/0); // float(INF) + E_WARNING
var_dump(-42/0); // float(-INF) + E_WARNING
var_dump(0/0); // float(NAN) + E_WARNING

当使用取模运算符( % )的时候,PHP7 会抛出一个 DivisionByZeroError 异常,PHP7 之前,则抛出的是警告。

复制代码
echo 42 % 0;

PHP5 输出:

复制代码
PHP Warning:  Division by zero in /tmp/test.PHP on line 4

PHP7 输出:

复制代码
PHP Fatal error: Uncaught DivisionByZeroError: Modulo by zero in /tmp/test.PHP:4 Stack trace: #
0 {main}
thrown in /tmp/test.PHP on line 4

PHP7 环境下,可以捕获该异常:

复制代码
try {
echo 42 % 0;
} catch (DivisionByZeroError $e) {
echo $e->getMessage();
}

输出:

复制代码
Modulo by zero

(3)pregreplace() 函数不再支持 “\e” (PREGREPLACEEVAL). 使用 pregreplace_callback() 替代。

复制代码
$content = preg_replace("/#([^#]+)#/ies", "strip_tags('#\\1#')", $content);

PHP7:

复制代码
$content = preg_replace_callback("/#([^#]+)#/is", "self::strip_str_tags", $content);
public static function strip_str_tags($matches){
return "#".strip_tags($matches[1]).'#';
}

(4)以静态方式调用非静态方法。

class foo { function bar() { echo ‘I am not static!’; } } foo::bar();

以上代码 PHP7 会输出:

复制代码
PHP Deprecated: Non-static method foo::bar() should not be called statically in /tmp/test.PHP on line 10
I am not static!

(5)E_STRICT 警告级别变更。

原有的 ESTRICT 警告都被迁移到其他级别。 ESTRICT 常量会被保留,所以调用 errorreporting(EALL|E_STRICT) 不会引发错误。

关于代码兼容 PHP7,基本上是对代码的规范要求更严谨。以前写的不规范的地方,解析引擎只是输出 NOTICE 或者 WARNING 进行提示,不影响对代码上下文的执行,而到了 PHP7,很有可能会直接抛出异常,中断上下文的执行。

如:对 0 取模运行时,PHP7 之前,解析引擎只抛出警告进行提示,但到了 PHP7 则会抛出一个 DivisionByZeroError 异常,会中断整个流程的执行。

对于警告级别的变更,在升级灰度期间,一定要关注相关 NOTICE 或 WARNING 报错。PHP7 之前的一个 NOTICE 或者 WARNING 到了 PHP7,一些报警级变成致命错误或者抛出异常,一旦没有对相关代码进行优化处理,逻辑被触发,业务系统很容易因为抛出的异常没处理而导致系统挂掉。

以上只列举了 PHP7 部分新特性,也是我们在迁移代码时重点关注的一些点,更多细节可参考官方文档 http://PHP.net/manual/zh/migration70.PHP。

3. 研发流程变更

一个需求的开发到上线,首先我们会通过统一的开发环境来完成功能开发,其次经过内网测试、仿真测试,这两个环境测试通过后基本保证了数据逻辑与功能方面没有问题。然后合并至主干分支,并将代码部署至预发环境,再经过一轮简单回归,确保合并代码没有问题。最后将代码发布至生产环境。

为了确保新编写的代码能在两套环境(未灰度的 PHP5.4 环境以及灰度中的 PHP7 环境)中正常运行,代码在上线前,也需要在两套环境中分别进行测试,以达到完全兼容。

所以,在灰度期间,对每个环节的运行环境除了现有的 PHP5.4 环境外,我们还分别提供了一套 PHP7 环境,每个阶段的测试中,两套环境都需要进行验证。

4. 灰度方案

之前有过简单的介绍,系统部署在三大服务池,分别为 Home 池、Page 池以及应用服务池。

在准备好安装包后,先是在每个服务池分别部署了一台前端机来灰度。运行一段时间后,期间通过错误日志发现了不少问题,也有用户投诉过来的问题,在问题都基本解决的情况下,逐渐将各服务池的机器池增加至多台。

经过前期的灰度测试,主要的问题得到基本解决。接下是对应用服务池进行灰度,陆续又发现了不少问题。前后大概经历了一个月左右,完成了应用服务池的升级。然后再分别对 Home 池以及 Page 池进行灰度,经过漫长灰度,最终完成了 PC 主站全网 PHP7 的升级。

虽然很多问题基本上在测试或者灰度期间得到了解决,但依然有些问题是全量上线后一段时间才暴露出来,业务流程太多,很多逻辑需要一定条件才能被触发。为此 BUG 都要第一时间同步给 PHP7 升级项目组,对于升级 PHP 引起的问题,要求必须第一时间解决。

5. 优化方案

(1)启用 Zend Opcache,启用 Opcache 非常简单, 在 PHP.ini 配置文件中加入:

复制代码
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1"

(2)使用 GCC4.8 以上的编译器来编译安装包,只有 GCC4.8 以上编译出的 PHP 才会开启 Global Register for opline and execute_data 支持。

(3)开启 HugePage 支持,首先在系统中开启 HugePages, 然后开启 Opcache 的 hugecodepages。

关于 HugePage

操作系统默认的内存是以 4KB 分页的,而虚拟地址和内存地址需要转换, 而这个转换要查表,CPU 为了加速这个查表过程会内建 TLB(Translation Lookaside Buffer)。 显然,如果虚拟页越小,表里的条目数也就越多,而 TLB 大小是有限的,条目数越多 TLB 的 Cache Miss 也就会越高, 所以如果我们能启用大内存页就能间接降低这个 TLB Cache Miss。

PHP7 与 HugePage

PHP7 开启 HugePage 支持后,会把自身的 text 段, 以及内存分配中的 huge 都采用大内存页来保存, 减少 TLB miss, 从而提高性能。相关实现可参考 Opcache 实现中的 accel_move_code_to_huge_pages() 函数。

开启方法

以 CentOS 6.5 为例, 通过命令:

复制代码
sudo sysctl vm.nr_hugepages=128

分配 128 个预留的大页内存。

复制代码
$ cat /proc/meminfo | grep Huge
AnonHugePages: 444416 kB
HugePages_Total: 128
HugePages_Free: 128
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB

然后在 PHP.ini 中加入

复制代码
opcache.huge_code_pages=1

6. 关于负载过高,系统 CPU 使用占比过高的问题

当我们升级完第一个服务池时,感觉整个升级过程还是比较顺利,当灰度 Page 池,低峰时一切正常,但到了流量高峰,系统 CPU 占用非常高,如图:

系统 CPU 的使用远超用户程序 CPU 的使用,正常情况下,系统 CPU 与用户程序 CPU 占比应该在 1/3 左右。但我们的实际情况则是,系统 CPU 是用户 CPU 的 2~3 倍,很不正常。

对比了一下两个服务池的流量,发现 Page 池的流量正常比 Home 池高不少,在升级 Home 池时,没发现该问题,主要原因是流量没有达到一定级别,所以未触发该问题。当单机流量超过一定阈值,系统 CPU 的使用会出现一个直线的上升,此时系统性能会严重下降。

这个问题其实困扰了我们有一段时间,通过各种搜索资料,均未发现任何升级 PHP7 会引起系统 CPU 过高的线索。但我们发现了另外一个比较重要的线索,很多软件官方文档里非常明确的提出了可以通过关闭 Transparent HugePages(透明大页)来解决系统负载过高的问题。后来我们也尝试对其进行了关闭,经过几天的观察,该问题得到解决,如图:

什么是 Transparent HugePages(透明大页)

简单的讲,对于内存占用较大的程序,可以通过开启 HugePage 来提升系统性能。但这里会有个要求,就是在编写程序时,代码里需要显示的对 HugePage 进行支持。

而红帽企业版 Linux 为了减少程序开发的复杂性,并对 HugePage 进行支持,部署了 Transparent HugePages。Transparent HugePages 是一个使管理 Huge Pages 自动化的抽象层,实现方案为操作系统后台有一个叫做 khugepaged 的进程,它会一直扫描所有进程占用的内存,在可能的情况下会把 4kPage 交换为 Huge Pages。

为什么 Transparent HugePages(透明大页)对系统的性能会产生影响

在 khugepaged 进行扫描进程占用内存,并将 4kPage 交换为 Huge Pages 的这个过程中,对于操作的内存的各种分配活动都需要各种内存锁,直接影响程序的内存访问性能。并且,这个过程对于应用是透明的,在应用层面不可控制, 对于专门为 4k page 优化的程序来说,可能会造成随机的性能下降现象。

怎么关闭 Transparent HugePages(透明大页)

(1)查看是否启用透明大页。

复制代码
[root@venus153 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

使用命令查看时,如果输出结果为 [always] 表示透明大页启用了,[never] 表示透明大页禁用。

(2)关闭透明大页。

复制代码
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

(3)启用透明大页。

复制代码
echo always > /sys/kernel/mm/transparent_hugepage/enabled
echo always > /sys/kernel/mm/transparent_hugepage/defrag

(4)设置开机关闭。

修改 /etc/rc.local 文件,添加如下行:

复制代码
if test -f /sys/kernel/mm/redhat_transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi

升级效果

由于主站的业务比较复杂,项目较多,涉及服务池达多个,每个服务池所承担业务与流量也不一样,所以我们在对不同的服务池进行灰度升级,遇到的问题也不尽相同,导致整体升级前后达半年之久。庆幸的是,遇到的问题,最终都被解决掉了。最让人兴奋的是升级效果非常好,基本与官方一致,也为公司节省了不少成本。

以下简单地给大家展示下这次 PHP7 升级的成果。

(1)PHP5 与 PHP7 环境下,分别对我们的某个核心接口进行压测(压测数据由 QA 团队提供),相关数据如下:

同样接口,分别在两个不现的环境中进行测试,平均 TPS 从 95 提升到 220,提升达 130%。

(2)升级前后,单机 CPU 使用率对比如下。

升级前后,1 小时流量情况变化:

升级前后,1 小时 CPU 使用率变化:

升级前后,在流量变化不大的情况下,CPU 使用率从 45% 降至 25%,CPU 使用率降低 44.44%。

(3)某服务集群升级前后,同一时间段 1 小时 CPU 使用对比如下。

PHP5 环境下,集群近 1 小时 CPU 使用变化:

PHP7 环境下,集群近 1 小时 CPU 使用变化:

升级前后,CPU 变化对比:

升级前后,同一时段,集群 CPU 平均使用率从 51.6% 降低至 22.9%,使用率降低 56.88%。

以上只简单从三个维度列举了一些数据。为了让升级效果更加客观,我们实际的评估维度更多,如内存使用、接口响应时间占比等。最终综合得出的结论为,通过本次升级,PC 主站整体性能提升在 48.82%,效果非常好。团队今年的职能 KPI 就算是提前完成了。

总结

整体升级从准备到最终 PC 主站全网升级完成,时间跨度达半年之久,无论是扩展编写、准备安装脚本、PHP 代码升级还是全网灰度,期间一直会出现各式各样的问题。最终在团队的共同努力下,这些问题都彻底得到了解决。

一直以来,对社区的付出深怀敬畏之心,也是因为他们对 PHP 语言性能极限的追求,才能让大家的业务坐享数倍性能的提升。同时,也让我们更加相信,PHP 一定会是一门越来越好的语言。

作者简介

侯青龙,微博主站研发负责人。2010 年加入新浪微博,先后参与过微博主站 V2 版至 V6 版的研发,主导过主站 V6 版以及多机房消息同步系统等重大项目的架构设计工作。致力于提升产品研发效率以及优化系统性能。


感谢韩婷对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-01-11 16:065969

评论

发布
暂无评论
发现更多内容

龙蜥社区高性能存储技术 SIG 11 月运营回顾 | 龙蜥 SIG

OpenAnolis小助手

开源 高性能 存储 龙蜥社区 sig

成果版本支持追溯,代码来源有迹可循|ModelWhale 版本更新

ModelWhale

人工智能 机器学习 数据分析 团队协同 编程建模

政企数智办公潮水里的融云「答卷」

融云 RongCloud

办公 数智化

cleanmymac2023体验版功能讲解

茶色酒

CleanMyMac CleanMyMac X2023

手把手搭建视频查重系统

Zilliz

Milvus Towhee

大厂10年经验,我对Java高并发问题方案的总结,堪称教科书级

钟奕礼

Java 程序员 java面试 java编程

我凭借这1000道java真题,顺利拿下京东、饿了么、阿里大厂offer

钟奕礼

Java 程序员 java面试 java编程

【分布式技术专题】「架构设计方案」盘点和总结秒杀服务的功能设计及注意事项技术体系

洛神灬殇

分布式架构 秒杀架构 12月日更

这400道面试题,决定了你去BAT还是TMD

钟奕礼

Java 程序员 java面试 java编程

CodeArts如何保证客户代码和应用安全?

科技怪授

华为云

2022鸿蒙开发者大赛应用创新赛道收官,中国赛区21个优秀作品获奖

Geek_2d6073

鸿蒙开发实例|对象关系映射数据库

TiAmo

华为 华为云 12月月更

前端工程师leetcode算法面试必备-二分搜索算法(下)

js2030code

JavaScript LeetCode

CleanMyMac试用版4.12.1下载教程

茶色酒

CleanMyMac X CleanMyMac X2023

BI智慧仓储,带你体验数字化仓储物流管理

葡萄城技术团队

Redis的数据被删除,占用内存咋还那么大?

码哥字节

redis 数据 内存

用javascript分类刷leetcode3.动态规划(图文视频讲解)

js2030code

JavaScript LeetCode

【MyBatis】mybatis中#{}与${}的区别

No8g攻城狮

MySQL mybatis sql

阿里三面,这200道面试题免费发放,赶紧拿去收藏

钟奕礼

Java 程序员 java面试 java编程

Zebec获BNB Chain生态大力支持,ZBC通证将陆续登录一线平台

西柚子

《程序员修炼手册》,这521道阿里Java面试真题!真的不来看看?

钟奕礼

Java 程序员 java面试 java编程

美团四面Java岗,终获offer,我是这么回答面试官的

钟奕礼

Java 程序员 java面试 java编程

阿里P8裸辞真实心路历程,他底气来源于Java高阶面试合集

收到请回复

Java 程序员 面试 编程语言

黄金三月,跳槽旺季稳拿40k月薪,java资料免费送

钟奕礼

Java 程序员 java面试 java编程

一块RTX 3090加速训练YOLOv5s,时间减少11个小时,速度提升20%

OneFlow

人工智能 深度学习 模型训练

如何使用记事本编写 java 程序(从零开始学 Java 系列课程)

千锋IT教育

你需要知道的 14 个常用的 JavaScript 函数

千锋IT教育

Redis 为什么这么快,你知道 I/O 多路复用吗?

C++后台开发

redis 多线程 后端开发 C++开发 I/O 多路复用

什么是CodeArts?

科技怪授

华为云

前端工程师leetcode算法面试必备-二分搜索算法(中)

js2030code

JavaScript LeetCode

【12.02-12.09】写作社区优秀技术博文回顾

InfoQ写作社区官方

热门活动

亿级用户PC主站的PHP7升级实践_PHP_侯青龙_InfoQ精选文章