专栏名称: 算法与数学之美
从生活中挖掘数学之美,在实践中体验算法之奇,魅力旅程,从此开始!
目录
相关文章推荐
九章算法  ·  降息了!码农的好日子回来了… ·  3 天前  
九章算法  ·  LeetCode刷题小分队,day2:10月 ... ·  3 天前  
九章算法  ·  Meta E5据说顶包 ·  5 天前  
九章算法  ·  终极版捡漏!大厂system ... ·  6 天前  
51好读  ›  专栏  ›  算法与数学之美

湾区日报是如何运作的?

算法与数学之美  · 公众号  · 算法  · 2017-03-12 21:34

正文

来源:湾区日报

编辑:Gemini


这篇文章第一版是2015年5月份写的,现在看来有点“过时”了。是的,几个月的时间是能改变很多事情的。所以我决定每隔一段时间把这篇文章更新一次。


湾区日报是什么?

湾区日报是一个在旧金山工作的工程师运营的个人博客。该博客每天挑选5篇他主观认为高质量的文章,针对每篇文章拟一个中文标题写一两句简单评论,通过将近10个渠道(比如网站,iOS app,微博,微信,Twitter等)推荐给读者们。


写这篇文章的“我”就是这个工程师。湾区日报不是一个公司,也不是一个创业项目。只是我的一个 side project。从2014年8月6日发第一期以后,运营至今。


看上去很简单,对吧?我一开始做的时候也觉得很简单,很没技术含量,任何有高中文凭具有简单电脑知识的人都能运营这种博客。但为什么同一道命题作文,每个人写的内容不一样,有人能写离题有人能写满分作文?为什么大家都会写字,有人“竟然”能成为作家并靠写字为生?


每天的内容是如何发出的?

我在每天利用零散时间发现新文章,然后直觉认为是好文章的就收藏在Pocket 里。发现新文章的渠道很多,排名不分先后:Hacker News,Medium,Quora,我订阅的很多博客的RSS,各种社交网络上看到的文章,头脑中突然对某个主题感兴趣临时搜来的文章,与同事交谈中得知的文章等。


我也利用白天的各种零散时间读一两篇文章。但一般都是晚上回家吃完晚饭后,再开始用完整的时间专心读。每天读的文章数量不一定,有时候一天读20几篇,勉强挑出5篇;有时候一天读了5篇,但都觉得很不错,就不读其他的了。这个过程一般要花1到3个钟头。


我一般用 iPad 读文章,然后多任务打开 Slack,在里面跟我的小机器人(wanqu-ops)对话,有点像程序员工作的时候敲命令行一样。我会告诉小机器人,这是一篇文章的链接,然后它会自动提取文章的标题,url的slug,图片等信息,最后插入到后台数据库;每5篇文章自动生成新的一期,自动生成当天的日期(北京时间)以及当天的期号(比如第502期)。总之,我只要把链接扔给这个小机器人,它就能帮我做这些繁琐的事情了 --一个普通网站的小编会怎么做?会用CMS,然后一项一项手动输入,这个过程不会花太多时间,可能每天十几分钟吧;但我实在太懒了,连每天花这十几分钟都不舍得。


下一步要写简评。我也是跟小机器人对话,比如 “wq post 2672 title 这是一篇好文章” ,就是告诉它:我要把编号 2672 的文章标题改成 “这是一篇好文章”。同理,可以录入文章简评等内容。下图是我在 iPad 上读文章然后用 Slack 写简评: 



凑足5篇文章后,我最后给小机器人下达命令:把这期的内容发出。然后它就自动把内容更新到网站,消息推送给 iOS app 的用户,自动发布到微博,Twitter,Facebook等社交平台。


总之,手动操作的部分主要是读文章与写简评。剩下的繁琐的操作,都是由程序自动完成的。同一道命题作文,程序员的写法是和普通网站小编不一样的;不同程序员的写法也会不同。


背后的技术

我为湾区日报这个 side project 写了一些代码。由于只是 side project,我对它的期望不高,力求用最简单的做法,花最少的时间,用最“快糙猛”的方法实现我想要的功能。


网站与后台架构

2014年8月份,湾区日报只是处于”闹着玩”的阶段,没有严肃要做的意思。所以那个时期的湾区日报网站只是一些静态网页,用 Pelican 生成的。


之后的网站换成了 Wordpress。换了几个不同的主题。甚至还花了些钱买了 Product Hunt 的主题。


到了2015年3月份的某个周末,我也不知道哪根筋接错了,就宅在家里一天,从头写了现在的这个网站。主要用 Python/Django,Celery,RabbitMQ 以及 Postgres 搭建的。


为什么用Django?为什么能在一天做一个网站?很简单,我在过去两三年自己写了大大小小10几个 Web App,都是写着玩的 side project,都是用 Django/Postgres 搭建的,只是一个套路而已。将自己以前写的代码复制粘贴,当然可以很快拼凑一个网站出来了。


所有网站基本都能简化成这个架构:Web App,Database,Async Worker,Task Queue,以及 Scheduler。其中,Web App就是跑网站代码接受用户的访问请求,所有耗时间的task(比如发邮件,发微博,数据统计等)都扔到Task Queue上,然后Async Worker从Task Queue抓task过来离线处理;而Scheduler就是定时跑程序,很多网站直接用的Cron。


对于湾区日报,Web App就是Django App,用uwsgi跑N个进程,用supervisord 来管理进程,前面挂一个 nginx 当 load balancer。Database用的是Postgres。Task Queue是用RabbitMQ。Scheduler用的是Celery Beat。而Async Worker是Celery。下图是湾区日报后台简单的架构: 

湾区日报的所有这些后台的大大小小20几个进程是跑在3台 DigitalOcean 的虚拟机上(每个月花$40多)。按照访问量的增长速度,这样的架构估计至少可以支撑到2020年。当然,我在这3台虚拟机上也跑了其他的 side project,也不算浪费计算资源。


iOS App

2015年5月份的时候,用了一个周末写了 iOS App。完完全全用 Swift 写的,很不错的体验。前面说了,这只是一个 side project,所以期望不高,我是可以厚着脸皮上线质量低劣的一个周末写的 app 的,反正也没什么人用,以后慢慢改进就是了。


后台的 Api 也是 Django App(抽象出一些通用的内部 api 与网站共用),也是跑了 个 uwsgi 进程然后用 nginx 做 load balancer。

在开发第一版 App 的那个周末,除了完成基本的功能(浏览文章)外,还加入:


  • Crash report(用 Crashlytics),第一时间通知我用户的 app crash 了,方便我调试;

  • Google Anlytics,监测用户使用 app 的情况,比如多少人在线,哪个页面比较多人访问,哪个按钮比较多人点击等;

  • Appirater,提醒那些使用了几次 App 的用户去 App Store 给个好评;

  • PSUpdateApp,提醒用户有新版本了,快及时更新。


这些都只是套路而已。尽管不是 iOS 开发人员,但至少要有这么一个意识。上线一个产品,最基本的东西都要有:收集 metrics,收集 crash 的信息,更新提醒等 --开始做 app 之前有跟同事打听了一下应该用哪些工具,少走了不少弯路。详见这篇博文:两天四夜上线一个 App


发布系统

湾区日报这个博客有很多推送的渠道。现代博客与10年前的博客不同:10年前的博客就是一个网站,而现代的博客形式多样,同一份内容会以不同的形式通过不同的渠道出现在读者面前。


前面介绍到我用 Slack 与机器人对话。这机器人就是 Hubot -- 它解析我发出的命令,然后调用我在 Django App 里提供的 REST api 发布文章;当文章的状态由 pending 变成 published后,将触发一些 Celery tasks;每个 task 负责一个渠道的发布任务,比如一个task发布到微博,一个task发布到reddit等。


微博:调用微博 api 发布。凡是微博的帖子底部有 “来自 湾区日报BayArea” 字样的,都是由发布系统自动发布的。 



微信:理论上,成为认证用户后,可以调用 api 自动发消息给订阅者们。但我没有成为认证用户,只能手动发布。Hubot会生成每期需要发布的文字,我只要复制粘贴就能发出消息了。对于微信,我基本是放弃了,完全不上心;因为湾区日报这种分享链接的模式很不适合在微信这种平台做。


Twitter:调用 Twitter 的 api 发布。Twitter 的 api 做得不错。

Facebook:调用 Facebook 的 Graph API 发布。

Reddit:调用 Reddit 的 api 发布的。难道有中文用户上 Reddit?我不确定。我只是把 Reddit 当作一种 SEO 的手段而已。

Google+:Google提供的api很难用,我不愿意花时间研究,于是就用 Buffer自动同步 Twitter 上发的内容。

邮件订阅:用 MailChimp 自动读取 RSS,每天定时自动发布。

iOS App 推送:没什么好说的,就是 APNS。

RSS:老旧的,但仍然很有用的 RSS。你会很惊讶,现在很多线上媒体不提供 RSS订阅。


很多读者注意到了,湾区日报在各个社交媒体上不断炒冷饭,重复发布几个月前发过的文章。我在 FAQ 里有详细说明原因。简单说,半年后,湾区日报有一半的读者没有读过我以前推荐过的文章,“旧”的文章对他们而言是“新”的。


怎么炒冷饭呢?Celery Beat 每个钟头会有一定概率(不同时段的概率不同)发布一篇旧文到微博,Twitter,Facebook等社交媒体上,比如这条微博。


数据统计

如果你经常使用湾区日报的 iOS app 或者网站,你就会发现我竟然公开了湾区日报的运营数字:访问量,app下载量,app打开消息推送的用户数,app的付费用户数等。下图告诉你在哪里可以找到湾区日报的各种运营数据: 



湾区日报毕竟不是一个公司,我也不跟任何人合作,所以我说的算。我觉得中文的互联网上能找到运营网站的实战案例很少。一个对互联网感兴趣的人,当然希望能看到一个真实的运营案例以及真实的数据,作为一个学习材料 -- 有点像教科书上的案例分析。


这些数据分别从 App Annie 的 api,Google Analytics 的 api,以及我自己的后台数据库去抓去。Celery Beat 每小时开启一个 job 更新一下这些数据。


对于湾区日报的 iOS App,我最关心的数字是有多少用户开启了 push notification;只有开启了 push notification,用户才能及时得知当天的湾区日报的更新。每当有一个新用户开启了 push notification 或付费了,我的 Slack 就得到通知。下图是我 Watch 上来自 Slack 的通知,告诉我此刻有一个新用户下载了 App 并且打开了 push notification: 



关于 Slack 与 Hubot,详见这篇博文:湾区日报的第一个“员工”:Slack/Hubot


搜索功能

网站与 iOS app 上都可以关键词搜索往期的文章。我原来想用 ElasticSearch 来做一下,但想着要多管理一个ElasticSearch就不爽,这样就多了一个 failure point,运维上可能得多花点时间,不划算。


后来受到这篇文章的启发,用一个晚上的时间直接利用 Postgres 做全文索引,并实现了网站与 app 的搜索功能,真是快糙猛的做法。


广告运营

光靠情怀与热情去做湾区日报是没法长久的,毕竟我只是一个普通人,也会有懈怠、厌倦的时候。所以为了鼓励我继续长久做下去,为了湾区日报能可持续发展,我尝试引入赞助商广告( wanqu.co/ads )、增加一点收入,但愿这种经济上的刺激能让我这个普通人坚持运营下去。


广告形式主要是文字与图片,都是 html,很简单。


支付用的是 Stripe,但只支持刷信用卡。但国内的广告商一般都没法刷卡,只好用银行转账。


跟踪广告的表现(浏览量、点击量)我是直接写到 Redis 里,然后每 1 个小时自动更新报表。这是一份真实的广告报表:https://wanqu.co/ads/4yH00IncS7HTKupxlvJ6llYotkUnHbWeV5HE7uivWrji7b2mm1OvyKZGyaPBESCH/stats

与广告商的沟通主要是通过电子邮件或者微信(wanqu_w)。


运维

我一般每星期发布一次新版本的 iOS App。每次的更新其实很有限。我每星期一般只能花不到一小时来写 app 的代码。


网站后台代码的更新主要通过 Slack。仍然是与小机器人对话:“wq deploy”。它就会 checkout 网站的 git repo 的最新 master branch,然后重启相关进程。我用 symlink 做了版本控制,所以如果发现严重的bug,要 rollback 到前一个版本的话,只需要切换一下 symlink,几秒钟的事情。


发布代码变得轻松愉快,且充满自信,这就鼓励了开发人员(我)勇于尝试各种新奇的 idea,勇于快速迭代,快速部署小更新。所以湾区日报一直在进化。湾区日报的今天没有比昨天好多少,但这个季度肯定比上个季度改进了不少。


监控网站是否挂了,我用的是 Pingdom;如果网站挂了,我会收到短信提醒。监控服务器各种计算资源的使用情况,我用的是 Datadog(2年前去开Dockercon 的时候,在他们摊位聊了很久,才知道有这么个东西)--理论上,monitoring 与 alerting 都可以自己用开源软件搭建,但是,湾区日报只是一个 side project 而已,有现成可以凑活着用的SaaS方案,就不必花时间自己做了;而且自己做的肯定不如人家专业的。


网站域名的 DNS 管理,我用 CloudFlare。使用 CloudFlare 还有其他的好处,比如它帮我挡住了不少恶意请求,帮我缓存了各种静态文件。


客服

每天都有读者来信。当然,大部分的问题都能在 FAQ 里得到解答。但也有很多来信给了我很多鼓励,知道你们从湾区日报推荐的文章里学到了东西得到了成长,我真的很高兴。

微博与微信上的读者来信,大部分都能得到关键词匹配的自动回复,算是缓解了我手动回复的压力。而花时间去写 FAQ页面则省去了回复大部分邮件的时间。


代码管理与新功能的开发

湾区日报有3个 git repo(网站后台,iOS app,以及运维相关的脚本),都放在 Bitbucket 上,不对外公开。使用 Bitbucket 而不用 GitHub 的原因是为了省钱;如果要在 GitHub 上使用 private repo,得交钱;而 Bitbucket 我个人用的话,可以有无限数量的 private repo。


我比较倾向于 commit 小段代码,出问题了也可以比较小粒度地 revert。一般一个 commit 包含的代码量不多于 100 行。很显而易见的代码修改我直接在 master branch 上操作,然后直接 push master;比较 tricky 的代码修改我会建立一个新的 branch,然后给自己发 pull request,自己 review 一遍自己写的代码。


我经常上线没有写完的代码,然后 wrap 在 feature switch 里面。我这种小破 project 大部分的方案都是土办法,不用太学术派不用太杀鸡用牛刀,意思一下就行了。所以一个 feature switch 其实就是 Postgres 里的一个表格里的一行。湾区日报99.999%的workload是 read-only 的,所以网站上很多页面其实都是缓存在内存然后走CDN的,数据库访问不会太 crazy。


顺便提一下,有一些年轻的读者(学生或者刚工作不久的年轻人)发邮件过来逼我开源湾区日报的代码,让我有点哭笑不得。详见 FAQ 第18条 ( wanqu.co/about )。


开发环境

我用家里的 iMac 写代码。Mac OS X 下运行虚拟机 Vagrant + VirtualBox。虚拟机里跑的是 Ubuntu,与 production 里用的操作系统一样。然后通过 Vagrant 的 synced folders 在 Mac OS X 与虚拟机之间共享代码的文件夹。在 Mac OS X 上用 PyCharm 写代码,利用 PyCharm 里的 Vagrant 的支持,在虚拟机里跑服务器。


数据备份

有一个每天自动执行一次的 job 把所有数据 dump 出来,压缩一下,按日期命名,最后上传到某个地方。上传到哪里呢?任何提供API的云存储服务都行(Dropbox、Box之类的)。


对于 PostgreSQL 里的数据,我用 Django 的 dumpdata 命令把所有数据 dump 成一个 json file,然后 gzip 一下。


对于 Redis 里的数据,直接 gzip 一下 disk 上的 dump.rdb。

详情见这篇博文:湾区日报是如何备份数据库的?


运营成本与收入

湾区日报网站的这个页面 wanqu.co/cost 会更新每个月的运营成本。最近这个月的运营成本是 $698.61。其中 $98.61 是花在租服务器、买域名、各种 SaaS 的费用,而剩下的 $600 是人工成本。


$600 的人工成本是如何计算出来的?我每天花在湾区日报的时间是 1~3 小时,周末有时候可以腾出半天时间写代码、更新 iOS app。就当每天平均工作 2 个小时吧,乘以加州最低时薪 $10,再乘以 30 天一个月;所以每个月人工成本 $600。


湾区日报是有一些收入的,但整体来讲是亏本经营。收入来源主要有三个:


1,来自 Google Adsense (网站)、 Google AdMob (iOS app)以及 Amazon Affiliate 的收入。这部分收入几乎可以忽略不计。每个月大概就 $50 左右吧。

2,来自 iOS app 内购的收入。App 内购的定价相当于请我喝半杯咖啡;这个价钱说多也多,说少也少,因人而异了。让我很欣慰的是,下载了 app 的人里,有 7.4% 的人愿意掏钱请我喝这半杯咖啡:)

3,来自赞助商的广告。这是最新开辟的收入手段,不是每天都有赞助商的,所以收入还不是很稳定,大概每月几百到一千多不等。


创业公司需要养一帮人,要发全职的工资,要租办公室,还要做营销,相当烧钱。而湾区日报是小 side project,业余时间做就行了,运营起来不会花太多钱。所以湾区日报一时半会儿是不会因为钱的问题而倒闭的:)


处理负面情绪

当然,任何人、任何事、任何一句话、任何作品都不可能让世界上每个人都一致认可的。任何有微博帐号的公司、组织、小有名气的人,必然要接受网友讽刺、辱骂的。湾区日报的传播变广了后,也偶尔会有无理挑衅、攻击的声音;我脸皮还算厚,平常心对待,专注于每天推荐的5篇文章就是了。


如果你做的东西没有任何批评的声音,如果没有人嫉妒眼红,如果没人模仿抄袭盗版,那么你做的东西要嘛没意思,要嘛知名度还太低。


总结

如果把这篇文章给2014年8月6日的我看,我肯定不会做湾区日报这个 side project 了,太花时间了 -- 竟然要做网站,要做发布系统,要学 Swift 然后写 iOS app,还要每周发布 app 新版本,还要管理好几个发布渠道,还要做客服回邮件,还要每天花1到3个钟头读文章写简评。


幸亏写这篇文章的时候,大部分困难的工作已经完成了。这就是互联网时代的产品迭代,是一个循序渐进的过程,是个人与产品共同成长的过程。你不能期望一夜成功 -- 其实,你也可以一夜成功,只是这一夜发生在第1000天甚至第3600天。


运营湾区日报是没什么经济上的回报的,尽管有一些广告收入与app内购的收入,但与投入的时间(再乘以一个哪怕是实习生的时薪)相比,相当微不足道。之所以我还能继续做下去,是看中知识的积累与个人的成长。这些运营经验以及从每天5篇文章里学到的东西,是完全可以运用到我其他的项目上的。就算最后真的什么都没做成,也是一段美好的回忆。临死的时候,回顾一生,至少我还能说,我做过一个叫湾区日报的博客,每天有那么几万个读者(我也是读者之一),我们每天都在进步。这就够了。


有 impact 的东西,未必是有技术含量的。


如果湾区日报让世界上某个角落的陌生人拓宽了视野,甚至是得到启发进而更热爱工作、热爱生活,我觉得这就算有 impact 了。至少我对这个世界还是有点用处的。