0%

在 Laravel 5.8 以下的版本中,队列消费者处理消息超时的时候会静默失败,即使超过了重试次数,这就导致一个问题,超时的时候问题无法被及时发现。

在 5.8 及以上版本中,超时次数重试次数之后也会当作失败处理,会记录到 failed_jobs 表里面,而不像之前版本那样一直重试。

具体可以查看 \Illuminate\Queue\Worker::registerTimeoutHandler 方法。

不过在 5.8 以下的版本中,我们依然有办法可以得知队列超时,registerTimeoutHandler 里面在超时退出消费者进程之前,先 fire 了一个 WorkerStopping 事件,并且传递了参数 1。

也就是说,我们可以通过监听 WorkerStopping 事件,然后通过判断 WorkerStopping 的 status 状态字段是否为 1,如果是 1,则表明队列超时了,这个时候我们就可以采取一些行动,比如发送报警通知,及时告知开发者。

我们知道在 redis 中,有一个排他锁,set ... nx,但是这个锁有一个问题是,有可能造成所有请求阻塞在等待这个锁上。

如果是允许同时执行的,比如秒杀,是可以有多个请求成功的,那么可以尝试一下 redis 的乐观锁。

如何使用

  1. 利用 redis 的 watch 功能,监控这个 redis key 的状态值。
  2. 获取 redis key 的值
  3. 创建 redis 事务
  4. 修改这个 key 的值
  5. 执行这个事务,如果 key 的值被修改过则回滚,key 不修改。(如果没修改过,则执行成功)

示例

事务执行

1
2
3
4
5
6
7
8
9
10
➜  ~ redis-cli
127.0.0.1:6379> watch a
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set a 12
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
127.0.0.1:6379>

如果事务执行成功,exec 会返回 OK,如果执行失败,则会返回 nil。我们可以根据这个返回值来判断事务是否执行成功。

在使用 socket api 开发的时候,可能经常会遇到一个问题,停止 socket 服务器之后立即重启的时候,会提示端口被占用。

这是因为一般情况下,一个端口释放后得等待一会才能再被使用,而 SO_REUSEADDR 可以让端口释放后立即就可以被再次使用。

这样以来,调试的时候就不用担心停止 server 之后再启动就启动不了了。

  • 给排序字段加索引

需要注意:联合索引里面,一个字段的顺序和逆序是不一样的索引。比如

1
db.coll.createIndex({"a": 1, "b": 1})

1
db.coll.createIndex({"a": 1, "b": -1})

是两个不一样的索引

  • 使用 batchSize 选项批量获取数据

jenssegers mongodb 包默认情况下会获取 101 条记录,然后其他记录在底层通过 iterator_to_array 来获取,如果我们需要获取的数据量比较多,则会需要产生多次获取数据的操作。

所以,如果我们知道需要获取大批量数据的时候,可以指定一个比较大的 batchSize 从而减少网络往返次数。

  • 只获取需要的字段(针对大批量获取数据的情况)

主要目的:减少带宽占用,以及处理过程中可以减少内存占用。

  • 使用覆盖索引

覆盖索引的使用类似 MySQL,因为 MongoDB 的索引也是 B+ 树。如果我们在查询的时候只需要某一两个字段,可以在索引上跟查询条件组合在一起建立一个联合索引。

  • 使用 find 代替 aggregate

当我们尝试设置一个 null 变量的属性的时候,会报这个错:

1
2
$a = null;
$a->b = 1; // Creating default object from empty value

其实除了 null,值为 空字符串 或者 false 的变量,如果想设置其属性的时候也会报这个错:

1
2
$a = ''; // 或者 $a = false;
$a->b = 1; // Creating default object from empty value