Skip to main content

3 posts tagged with "php"

View All Tags

· 7 min read

美图 PHP 业务团队在使用 php-memcached 扩展陆陆续续遇到一些隐蔽的 ”坑”,而这些坑在 php-memcached 也是比较容易踩到。其中有如 TCP_NODELAY 这类常见的坑,也有一些 php-memcached 本身设计带来的问题。这里分享出来希望可以给遇到类似问题或者正在坑里的同学带来一些帮助。

· 5 min read

知道或者熟悉 kafka(不是写小说的那个卡夫卡), 那么一定知道它有 producer 和 consumer 这两种角色。producer 用来生产消息,consumer 用来消费消息。

1) 可用性

下面是来自维基百科的解释:

在一个给定的时间间隔内,对于一个功能个体来讲,总的可用时间所占的比例

比如我们以年为单位来量化一个服务的可用性。假设一年 365 天当中有 364 天服务是正常服务的,那么我们就说这个服务的可用性是 364/365(用计算器口算了一下约 99.72%)。

我们常用几个 9 来衡量一个服务的可用性,两个 9 就是 99.99%,三个 9 即 99.999%, 四个 9 即 99.9999% ... 以此类推。

可用性每年宕机时间
99.9%8 个小时
99.99%1 个小时
99.999%5 分钟
99.9999%30 秒

2)消费者的可用性

一般来说 producer 是嵌入到业务程序,那么可用性就由业务程序来保证。而 consumer 一般就是以独立的程序存在,那么就要自己来保证。

所以想让 consumer 做到 99.99% 以上的可用性,意味着一年内服务挂掉的时间不能超过一个小时。假设我们没有实现一些高可用的机制,部分 consumer 在半夜挂了,而你(或者运维)刚好干完一些不可描述的事情之后倒头大睡而没有注意到报警,这个系统的可用性就达不到要求。

当前 scala, java, golang, c 版本的做法都是监听 group 的 consumer 列表,如果有 consumer 进入或者退出都会触发重新分配分区,把分区均衡到各个 consumer。所以理论上我们 php 版本也可以这样做。现在已有的开源里面有 kafka 和 zookeeper 的客户端扩展和依赖库,但没有实现自动平衡的逻辑(也可能是我没看到), 所以这部分需要自己来做。

3) 尴尬的 php

这里必须先承认 php 是世界上最好的语言。

php 要实现 consumer 的高可用有三中选择:

  • 开启 php 线程扩展
  • c 实现 group 逻辑
  • 不使用多线程,边消费边监控

第一种方案,因为我们线上 php 环境都是没有打开线程安全, 所以如果要使用这个扩展需要重新编译 php 核心代码并重启所有服务,这个基本是无法接受的。

第二种方案,可以不用重新编译 php, 性能好。但开发成本比较高,风险大。

第三种方案, 纯 php 实现,代码简单可控,但性能会比较差一些。

最后我们选择了第三种方案,单进程空跑(只拉消息不处理)的性能是 7w+/s, 这个是可以接受的。

4) 功能和代码说明

  • 分区变化时可自动重新分配分区
  • 消费进程退出或者加入时可自动重新分配分区
  • 自动管理 offset
  • 兼容标准的 consumer group 路径,方便已有的工具监控
  • 接收用户信号,平滑进入和退出 group
  • 允许冗余的消费进程作为备份

github 地址: https://github.com/meitu/php-kafka-consumer

当前我们公司(美图)内部已经有不少业务已经在线上使用,当前版本已经比较稳定。

5)最后

前一段时间发现线上 consumer 内存不断上升的情况,经排查,最终定位并验证是依赖库的 php-zookeeper 有内存泄漏。现在已经反馈以及合并到社区的 master, 具体见 pr

如果使用 release(建议) 版本的 php-zookeeper, 需要手动 patch 这个 bug,否则会造成内存泄漏。

如果有问题或者任何意见,欢迎 issue 或者 pr。

· 4 min read

长连接可以减少建立连接的过程, 使用长连接可以提高服务的性能。php 很多扩展都支持长连接,如 redis, memcache, mysql 的主流扩展都支持。

我们知道长连接就是一次建立连接,使用之后不会马上释放,而是把这个连接放到连接池。那么引发的一个问题就是,我们下次使用时如何知道这个连接是否已经被关闭。