• Data Service 设计分享 at 2017年02月20日

    #4 楼 @huacnlee 感谢指教。

    学习了一下 second_level_cache, data service 的确做了一些和 second_level_cache 类似的事情,场景的区别主要因为我们前后端项目分离后,Write-Through 在 ruby, Read-Through 需要在 node 端发起. 在单体 ruby 项目中 SecondLevelCache 是个非常不错的选择!

    不过有些场景还是不能容忍数据在缓存中 miss 后再去触发生成,这个节点容易造成 5XX, data service 主要就是加强缓存异步刷新,在 redis 数据没有 expire 之前去刷新数据。

  • Data Service 设计分享 at 2017年02月20日

    #5 楼 @i5ting 感谢指教. 这里和直接 RPC 还是有点区别,在文中的最后一张图「周内 TP 变化情况」, 该页面是在 22 号之前很多数据是走的 http/thrift RPC, 22 号之前的很多不可用 (超时/5XX) 都是因为 RPC 调用偶尔的失败导致,而 22 后接入了 data service 后,基本保证所有数据在 redis 中都有,基本不会发生 miss 的情况,页面很稳定。

    对比 RPC 封装缓存和 data service 采用的异步更新,忘了哪里看来的比喻还挺形象的:

    1. 发现缓存过期时,线程都去获取并更新缓存,容易引发雪崩,5XX 的原因:

      5 个工人(线程)去港口取同样 Key 的货(get),发现货已经过期被扔掉了,这时 5 个工人各自分别去对岸取新货,然后返回

    2. 异步更新数据:

      5 个工人(线程)去港口取同样 Key 的货(get), 货一直存在,即使货过期了也不会扔掉 (很长的有效期). 但港口的货物还是比较新鲜,因为对岸有个家伙在不时更新着货物,这个家伙在 data service 中就是 ruby 端的 after_commit 或者定时 rake

  • Data Service 设计分享 at 2017年02月20日

    #1 楼 @huacnlee 看了代码,目前的确是用的after_commit 感谢提醒~ 稍后更新文档。

    1) 数据更新有 2 种途径:

    对于需要实时更新的数据,使用after_commit+sidekiq , 只是稍微进行了封装,调用方式形如:Monitor.watch(Product, SomeSidekiqWorker, :title, :price) 会给 Product 加上after_commit, after_commit中判断如果 title 或 price 有变化,会扔到 sidekiq 中更新. 对于旧数据有一定容忍度的业务,采用 rake 定时更新。

    2) 缓存存储前面需要有一个应用服务,两者都可能成为瓶颈,Redis 自然高效,应用服务使用 node 的好处之一在于异步 IO:

    let data = yield {
      '商品':  dataService.fetch(...),
      '广告':  dataService.fetch(...),
      '友情链接': dataService.fetch(...),
    }
    

    dataService.fetch返回的是 promise, 3 次 IO 的时间为:max(查商品时间,查广告时间,查友链时间)

    如果采用阻塞 IO 的实现,时间将是:查商品时间 + 查广告时间 + 查友链时间

    3) 缓存时间是各模型必须设置的,是在 redis cluster 中的缓存时间,我们有用 varnish 作为反向代理,主要用于页面缓存。

    Data Service 的目的在于管理那些可缓存的数据,Data Service 提供的数据,前端在 Node 中还可能进行加工再展示,这也是之前引入 node 的一个原因--前端希望管理 view 层。

    另外不同页面的 Data Service 数据可以在 node 端方便的组合,比如很多页面都需要「友情链接」的数据,在 Data Service 中只需要存一份。

    采用 redis 的另一个原因是可以比较容易的进行分布式扩展,可选哨兵 + 主从或者 cluster.

  • 记一次 Rails 项目异常排查 at 2017年01月24日

    #16 楼 @killernova 2 个 puts 之间其实有 200 多行代码,篇幅原因,在文章中省略掉了中间代码。当时是希望通过 singleton_methods 去判断类方法是否加上了,意外发现了第二个 puts 没有输出。

  • 信渊格格,得永生