• Data Service 设计分享 at 2017年2月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年2月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年2月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.

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

  • 信渊格格,得永生