赞!ruby gems 也有国内镜像就好了,gems.ruby-china.org 太慢了,而且经常出现下载 gem 失败的情况,搞得我只能用 vendor/cache 的方案来做部署,有点小麻烦。
自己用 errbit 搭一套服务,它的数据格式兼容 airbrake,客户端 sdk 就有 airbrake, 薄荷现在是这么做的。
很赞!选对了方向,努力才有效果,不要用战术的勤奋掩盖战略的懒惰,每天都要留够思考的时间。这次收听 robbin 大牛的分享很有收获。
谢谢支持,欢迎再次到薄荷坐一坐,:)
如果执行周期很频繁,比如每分钟执行一次,可以用 sidekiq-cron,这样能避免频繁加载 rails 环境,提升效率。如果周期很长,我觉得还是用 crontab 比较好,干净独立,依赖少,不会有干扰。
用 rake 任务 + crontab
,使用 whenever
管理部署。
需要注意的是,处理逻辑不要全堆在 rake 文件里,而是放在 model 或者 service 中,rake 只作为调度控制,这样容易写测试。然后是日志和异常监控,日志最好打到单独文件,不要和 web 日志混在一块,异常监控可以用第三方服务或自建 errbit。
好用,刚刚设置了一下,立竿见影。
整体策略有问题,应该在数据库层面做过滤,而不是把数据拉到 Ruby 进程做过滤。 把几百万的数据拉回来过滤,涉及到网络传输,分配大量内存建立对象,难以优化。如果在数据库层面做过滤,配合好的索引,速度有数量级的提升。
很棒的分享!深入浅出,有实际的例子和执行结果为证,很有说服力。 ruby fiber 特性偏底层,大部分情况都接触不到,所以看起来会比较吃力的,得趁机再去温习基础知识。如果要在实际项目中利用,估计得封装成 gem,屏蔽一些底层东西。
最重要的不是工具,而是意识和方法。我认为保障 Ruby 代码质量最有效的两个措施,一是单元测试,二代码 review。
我们自己做过 Mongodb 到 MySQL 的迁移,过程十分痛苦,而且到现在还没有完全做完。
可以简单使用 source_location 方法获取某个方法定义的文件和位置。
比如你有一个对象 bar,里面有一个方法 foo,bar 的定义比较复杂,搞不清 foo 在哪儿定义的,可以用下面方法打印位置
puts bar.method(:foo).source_location
这个主题好,我也尽量参加 +1
最好不要在 model 中使用 view 的方法,MVC,VC 对 M 的依赖应该是单向的,这样比较简单,假如让 M 依赖 V,会带来不少麻烦。
一个可能的解决方法是,view 层在调用 model 层,通过参数把数据(对象)传给 model。
改成这样就可以了
Rails.cache.fetch("rand_products", expires_in: 1.day) do
Product.order('RAND()').limit(20).to_a
end
因为你原先缓存的 Product.order('RAND()').limit(20)
是一个 ActiveRecord::Relation
对象,直到使用数据的时候才进行实际查询,
使用 to_a
方法之后,会真正查询数据库,返回数据对象。
@quakewang 原来 ruby 和 @ 还有这等神奇用法,涨姿势了
Rails log 里就可以粗略看到(log 调成 debug 模式),也可以用 newrelic 做简单的 profiling,另外还有 ruby-prof。 Ruby 中的 Profiling 工具 https://ruby-china.org/topics/25856 Ruby Profiler 详解之 ruby-prof(I) https://ruby-china.org/topics/25959
每个请求中,几大块的时间分别是多少(比如 controller, render, database, redis)? 有做 profiling 吗? 我猜效果不好的原因是:很大一块时间是在(controller + database)上,你目前使用缓存的方法只是减少了 render 的时间。
:plus1: 关注是一个挺麻烦的问题,特别是当数据量上去之后,很容易出现性能瓶颈,为了解决这个问题薄荷用了不少方法,这篇文章里提到了 2 个比较有效的做法,但不仅限于此。
@rei 考虑过分批处理。从逻辑上分析一定可以提升速度的,但是有些大 V 关注量实在太大,比如说 500 万,如果分成 100 批同时处理,估计频繁数据库读写瞬间对系统造成大的冲击,所以后来没有采用这种方法。
@lithium4010 这个问题和你聊的的问题有些不一样。那个是解决大批量用户的系统广播问题,不过一样的地方在于:当数据量并发量上去之后,看似简单的设计很容易出现瓶颈,必须使用一些算法策略解决。
文章里没有提到的一个大招是,区分活跃用户和僵尸用户(大部分互联网系统中,海量用户至少一半以上是僵尸用户),优秀处理活跃用户数据,尽量避免处理僵尸用户数据,如果僵尸用户再次造访,通过一个任务更新他的数据。
#15 楼 @lithium4010 我重新改正代码跑了测试,和你的结果不一样啊,缓存服务器在本机时数据如下:
user system total real
1-1 0.550000 0.230000 0.780000 ( 1.133004)
2-1 1.280000 0.330000 1.610000 ( 1.757418)
10 0.430000 0.050000 0.480000 ( 0.512793)
30 0.330000 0.030000 0.360000 ( 0.383506)
50 0.320000 0.020000 0.340000 ( 0.349198)
100 0.290000 0.010000 0.300000 ( 0.310068)
在局域网内,如下:
user system total real
1-1 0.660000 0.620000 1.280000 ( 4.236520)
2-1 1.400000 0.750000 2.150000 ( 5.674942)
10 0.450000 0.100000 0.550000 ( 1.114594)
30 0.420000 0.070000 0.490000 ( 0.772291)
50 0.410000 0.060000 0.470000 ( 0.678551)
100 0.380000 0.060000 0.440000 ( 0.560123)
多个单次读和批量读差异还是挺明显的。
#15 楼 @lithium4010 非常感谢指出 benchmark 代码中的一个问题,请原谅我的疏忽。我修正了代码,重新跑了 benchmark,缓存服务器同在一台机器时差异不太多,在远程时差异还比较明显,但是没有上百倍的差距。