Lua GC算法中是否存在“循环引用”问题

前几周到北京参见Openresty 2017大会,在会上分享了Lua 5.1 GC原理相关的内容。

其中提到,Lua采用的扫描标记算法,较之Python等使用的引用计数算法,不会出现循环引用问题。会后,有人问我其中的原因,一时之间想不太清楚,最近终于有了空闲的时间,可以来整理一下思路了。

还是以代码来说明问题:

--启动gc回收并打印回收结果函数
function memColl()
    print("now collect")
    collectgarbage("collect")
    local c1 = collectgarbage("count")
   

线上存储服务崩溃问题分析记录

上周我们的存储服务在某个线上项目频繁出现崩溃,花了几天的时间来查找解决该问题。在这里,将这个过程做一下记录。

加入调试信息

由于问题在线上发生,较难重现,首先想到的是能不能加上更多的信息,在问题出现时提供更多的解决思路。

首先,我们的代码里,在捕获到进程退出的信号比如SIGABRT、SIGSEGV、SIGILL等信号时,会打印出主线程的堆栈,用于帮助我们发现问题。

但是在崩溃的几次情况中,打印出来的信息并不足以帮助我们解决问题,因为打印的崩溃堆栈只有主线程,猜测是不是在辅助线程中发生的异常,于是采取了两个策略:

  1. ulimit命令打开线上一台服务器的coredump,当再次有崩溃发生时有core文件产生,能够帮助发现问题。
  2. 加入了一些代码,用于在崩溃的时候同时也打印出所有辅助线程的堆栈信息。

在做这两部分工作之后,再次发生崩溃的情况下,辅助线程的堆栈并无异常,core文件由于数据错乱也看不出来啥有用的信息来。

复现问题

由于第一步工作受挫,接下来我的思路就在考虑怎么能在开发环境下复现这个问题。

我们的存储服务在其他项目上已经上线了有一段时间了,但是并没有出现类似的问题。那么,出现问题的项目,与其他已经上线的服务有啥不同,这里也许是一个突破口。

经过咨询业务方,该业务的特点是:

  • 单条数据大:有的数据可能有几KB,而之前的项目都只有几百字节。
  • 读请求并发大,而其他业务是写请求远大于读请求。

由于我们的存储服务兼容memcached协议,出现问题时也是以memcached协议进行访问的,所以此时我的考虑是找一个memcached压测工具,模拟前面的数据和请求特点来做模拟压测。

最后选择的是twitter出品的工具twemperf,其特点是可以指定写入缓存的数据范围,同时还可以指定请求的频率。

有了这个工具,首先尝试了往存储中写入大量数据量分布在4KB~10KB的数据,此时没有发现服务有core的情况出现。

然后,尝试构造大量的读请求,果然出现了core情况,重试了几次,都能稳定的重现问题了。

有了能稳定重现问题的办法,总算给问题的解决打开了一个口子。

首次尝试

此时,可以正式的在代码中查找问题的原因了。

来大概说明一下该存储服务的架构:

  1. 主线程负责接收客户端请求,并且进行解析。
  2. 如果是读请求,将分派给读请求处理线程,由这个线程与存储引擎库进行交互,查询数据。此时该线程数量配置为2。
  3. 存储引擎库负责存储落地到磁盘的数据,类似leveldb,只不过这部分是我们自己写的存储引擎。
  4. 在读线程从存储引擎中查询数据返回后,将把数据返回给主线程,由主线程负责应答客户端。

Codis架构笔记

Codis是起源于豌豆荚的redis Proxy项目,其主要目的是为了解决redis使用中的两个痛点:

  1. 难以动态的平行扩展增加新的redis服务.
  2. 难以运维管理.

它主要的架构是这样的:

系统扩展的三种维度

经常提到一个系统的扩展性,只谈到垂直扩展和水平扩展,其中垂直扩展是提高系统内单个系统的处理能力,比如给机器加内存,换性能更高的机器等;水平扩展通俗一点说就是加更多的机器来处理请求,而不是试图提高单机的处理能力.

<<可扩展的艺术>>一书,将一个系统的可扩展性做了更多的划分和分析,它将一个系统的扩展性划分为以下三种维度:

No Comments »

灰度发布系统的实现(续)

上周写完灰度发布系统相关的博文之后,有朋友表示灰度系统的实现太过简单了,因为我目前接触的系统确实比较简单,很多复杂的东西没有考虑周全,如果更大型的业务系统,涉及到的服务更多,还有如果掺杂着数据的迁移,就更复杂了.这里就把当时讨论的内容提取出来,主要的贡献者为滴滴的沈佳伟.

1.调用链上有多个业务服务的场景

考虑这样一个业务场景,假设对外提供了服务A给客户端访问,服务A后面会调用服务B,C,D,此时需要上线一个功能,这个功能涉及到了服务A,C的修改,但是服务B,D不需要变动,换言之,我们的意图是,如果一个客户端请求,走到了新的灰度服务A,那么最终这个请求也应该走到这次和A一起灰度的服务C上.

这里的处理策略,可以给客户端请求进行tag打标记的方式,比如经由新版本服务A处理的请求,全部打上tag

灰度发布系统的实现

灰度发布,已经不是一个很新的概念了.一个产品,如果需要快速迭代开发上线,又要保证质量,保证刚上线的系统,一旦出现问题那么可以很快的控制影响面,就需要设计一套灰度发布系统.

灰度发布系统的作用在于,可以根据自己的配置,来将用户的流量导到新上线的系统上,来快速验证新的功能修改,而一旦出问题,也可以马上的恢复,简单的说,就是一套A/BTest系统.

它大抵的架构,应该是类似这样的:

Paxos原理与实现(二)实现与实践篇

上一部分描述了Paxos算法的原理,这部分根据 MIT 6.824 lab3 的内容,展开来讨论一下Paxos算法实现的过程中遇到的问题,以及如何将它运用到一个实际的K-V系统中.
我把这部分代码放在了github上.
这个实验包括两部分,第一部分是实现一个Paxos算法库,第二部分是基于这个Paxos库实现一个KV存储系统.

新申请了微信公众号

赶一赶时髦,开通了微信公众号,会同步一些这个博客的文章到上面去,公众号名字是”codedumpnote”.

Paxos原理与实现(一)原理篇

几年之前学习zookeeper的时候,就断续的学习过Paxos算法,对其中的原理和如何运用到实际环境中一知半解似懂非懂,以至于后面断断续续又花了不少时间在这上面,每一次的返工都没有达到自己想要的效果.直到最近,开始做

再谈同步/异步与阻塞/非阻塞

几年前写过一篇描写同步/异步以及阻塞/非阻塞的文章,今天回头来看bug不少,于是需要重新整理一下原来的描述.

同步/异步
首先来解释同步和异步的概念,这两个概念与消息的通知机制有关.

Pages: 1 2 3 4 5 6 7 8 9 Next