又开车了到站啦

去年的这个时候,发布了最近的一个创造-又开车了。简单讲,这是一个汽车评测视频聚合订阅工具,当UP主更新视频的时候,通过微信公众号向你推送更新通知。可以理解为这是一个以微信公众号作为主动推送通道的RSS聚合订阅工具。

这是一个完全个人兴趣推动的side project. 没有设定止损的基线,也没有盈利的目标。而现在来总结这个项目,源于几天前,微信提醒认证续费。结论很简单,不想续费了,准备关闭这个项目。当然,我承认有本能的反感这种“很微信”的恶心做法。项目层面本身的情况也是时候做一个总结和了断了。

因为只在早期在自己的微信车友群做过推广,因此可以认为没有什么运营结果,也谈不上亮眼的运营数据。用户量级较低,且很多都是友情订阅,没有什么值得分析的数据。在吸引早期用户和提高用户活跃上,个人的有限经验可以总结为:找到合适的池子捞鱼,舍得花本钱搞活动抽奖。

这是否是一个伪需求?即使抛开被推荐算法信息流淹没的时代背景,主动整理和聚合自己的订阅早在Google关闭RSS订阅产品Google Reader就说明这是一个非主流的产品。但这不是一个伪需求的产品。从用户视角看,信息的消费是有成本的,成本由小达到依次是:推荐,推送,订阅,搜索。而这个产品的初衷其实就是希望将订阅的消费成本拉低到解决推送的消费成本。从这点看,需求是客观存在的,产品逻辑也是自恰的。

这是一个商业闭环合格的产品吗?我这里说的商业闭环不等于账面盈利,而是整个商业逻辑闭环是否能够持续有效运转。从这个标准看,显然不是。账面上,零星有用户友情打赏,但是肯定是不够服务器以及微信的认证税开销。但是产品的定位是非常垂直的汽车评测领域。而这个领域但凡是稍微有点观察和思考,都能发现者这是一个车厂主动补贴评测博主(特指国内)的市场。你看到的绝大部分汽车评测都是评测博主拿了车厂的俸禄后的“软文”,行业也叫做“恰饭”。这里两个关键词我都加了引号,只是“客观中立”的陈述这样一个行业事实😂。因此,作为一个该领域的聚合订阅工具,面对的又是C端用户,其实就是联合这些评测博主提高软文的分发效率。我的盈利模式是来自于整车厂吗?我没有足够多用户的前提下,基本是不用想了。虽然汽车评测的门槛看起来和做起来非常低,但是跪舔的姿势不是每个人都愿意学并且学得会的。我的盈利模式是基于订阅用户做增值吗?很难。普通用户买车一般两个渠道,4S店和汽车经销商,如果不是强运营,很难通过一个订阅工具影响用户的购买行为,从中赚取“介绍费”。汽车后市场电商导购有一定的潜力,从过去一年搞过的一些活动及带货量看:

  1. 尽量避免比较长尾保养三滤系列,内容生产成本较高,且很难持续。
  2. 中国车主用户的心智基本还是被4S店洗脑的状态,DIY水平普遍很菜、很差,普遍抠门。因此不要被“改装”相对较大的喊声欺骗,当前阶段,如果你没有线下实体店,不要跟4S店抢生意。两个案例可以参考:老司机和大家car里面的机油销量。
  3. 因此,车型无关的车用品是个不错的选择。从数据看,我自己做过的最好的一个带货案例也是落在这个品类。而且在没有推广的情况下,都是自然流量转换为下单购买。进一步的,可以尝试与车用品厂家联名推出1~2款爆款的商品。很遗憾,自己没有时间来尝试这个想法了。

现在要关闭这个项目有遗憾吗?坦率讲,真没有。作为一个just for fun的side project, 其实非常感谢这个项目,尤其是做这个项目的过程。过去的一年家里发生了许多事,五味杂陈。但是,做这个项目的编码和运营过程可以将这些事情串起来:还记得跟媳妇、女儿回老家,动车上和酒店里写下的许多代码片段,有时候不禁在代码的注释里写下编写这段代码的此情此景;还记得在去年那趟一直魂不守舍的江西之行,一路上的焦虑、无奈、失落,但是却在那个时候写完了项目的最后几行代码,合上电脑的那一刻,内心变得平和;还记项目正式发布的那个特殊时间,有些人离开了,但是这个项目在我意料之外的时间上线了。感谢做这个project的过程,让我有了很多难忘而深刻的回忆和体验。

这个项目真的就这样关闭了吗?是的。但是,这个方向并不是一个错误的方向。近期看到即刻回归,还是挺为他们感到高兴的。而基于这个项目所沉淀的思考、技术底座将被我应用到另外一个项目,希望以后可以再次总结和复盘该项目。而这个期限是多久呢?也许又是一年,管它呢,just for fun!

2020之Macbook Pro DIY 升级 SSD及Time Machine数据恢复

一直接受不了touchbar世代macbook的键盘和type-c接口,因此手上的工作主力依然是2013 late 的macbook pro 13 inch 和 2015 mid macbook 15 inch. 两台机器的硬盘都是256GB,实际可用约240G左右。经过多年使用下来,经常提示硬盘 almost full,严重影响使用心情。而这两款作为最后一代可以自行升级硬盘的macbook, 自然是不能放过苹果少有的bug福利,准备自行更换升级SSD.

哪些macbook支持自行升级SSD硬盘

2013 Macbook Pro A1493 A1502 ( MD864 MD865 MD293 Md294) SSD

2013 MacBook Pro retina A1398 A1502 (ME864 ME865 ME866 ME293 ME294) SSD

2013 Macbook Air A1465 A1466 ( MD711 MD712 MD760 MD761) SSD

2014 Macbook Air A1465 A1466 ( MD711 MD712 MD760 MD761) SSD

2014 MacBook Pro retina A1502 A1398 (MGX72 MGX82 MGX92 MGXA2 MGXC2) SSD

2015 MacBook Pro retina A1502 A1398(MF839 MF840 MF841 MGXA2 MGXC2) SSD

2015 MacBook Air A1465 A1466 (MJVM2 MJVP2 MJVE2 MJVG2) and Mac Pro ME253 MD878 SSD

及2016年份的AIR PRO 机器

机器型号可以通过把笔记本翻过来看背面的标识来确认。

也有一个简单方法来确认自己的macbook是否可以自行更换硬盘:2013~2016年购买,且A面带有苹果光环Logo的都是可以自行更换的。

选择什么样的SSD

虽然是苹果少有的福利,但是毕竟是一个bug福利,市面上的NVME SSD是没法直接在macbook上使用的。需要一块转接卡,将NVME的SSD转换为苹果的特殊接口,这个我们放在后面单独说。

市面上一般推荐的NVME SSD有 intel 760p, 三星 970 EVO, 三星 970 EVO Plus, 三星 970 Pro,还有最近比较火的海康 C2000 Pro. 因为作为日常主力机使用,因此我个人的考虑优先级是这样的:

  1. 兼容性和容量优先,容量1T起步,淘汰三星 970 EVO Plus 和 海康 C2000 Pro:
  2. 三星 970 EVO Plus: 看到有几个反馈兼容性问题,有解决方法,但不想没事找事。相对于 970 Evo唯一的提升是写入性能,但是在这个速度级别,这个提升我并不care了。
  3. 海康 C2000 Pro: 可能不应该把这货跟 760p 和 970 一起比较,不过架不住这货实在便宜呀。但是便宜是有代价的,缓存用的还是上古时代的DDR3,既不是低电压也不是DDR4, 差点意思,而且多个案例反馈睡眠唤醒也有点问题。
  4. 然后考虑SSD的寿命和质保,并且寿命 > 质保。这块淘汰760p, 只有144TBW,而970 EVO 有 600TBW。质保上,海康终身质保,不过数据无价,优先考虑先天体质较好的。
  5. 在高温与温度之间,倾向于低温,妥协性能。这点上 760p 比 970 EVO 更优。但无奈寿命和性能与 EVO 差异太大,价格也不占优势,最后1399的价格入了三星 970 EVO 1T. (当前SSD价格没有太大优势,不过再等等估计就只有QLC了…)

顺便多说一点,拆机后发现苹果原装的SSD也是三星提供的,因此特别担心兼容性问题的话,就直接看 970 系列吧。

NVME转接卡的选择

因为转接卡只负责NVME到苹果特殊接口的针脚线映射,没有任何芯片引入,因此这个小东西基本不存在兼容和坑。有些同学可能遇到了NVME速度跑不满的问题,那是因为13寸的macbook只能支持到PCI x2,15寸的macbook才能支持到PCI x4(俗称满血版)。但是相信我,即使是日常开发,你也用不出来区别,优先考虑升级SSD的容量和兼容性即可。

我选了一个15块包邮的绿色小板,因为的确没什么技术含量,做工不错,针脚映射也非常整齐。

备份数据

在拆机升级SSD之前,需要先备份数据。我使用 Time Machine 把全部数据备份到了一块320GB的移动硬盘。因为是上古时代USB 2.0速度的机械移动硬盘,因此大概花了5个小时备份200GB的数据,我估计USB 3.0或SSD移动硬盘能在2个小时内完成。

Time Machine 备份数据会把目标硬盘格式化为苹果文件系统格式,因此你需要拿一块可以格式化或者空的移动硬盘进行备份。备份占用空间与原数据占用空间基本是1:1. 此外,时间机器支持增量备份,在恢复的时候你可以选择需要恢复的时间点,跟windows 还原点的概念类似。

拆机更换SSD

整体没什么难度。讲几个大家关心的点:

  1. 转接卡插入苹果机器接口需要用力,听到咔哒一声才算完全插入。此时,你应该看不见转接口的金手指针脚。因此推荐的安装顺序是:a. 安装转接卡到机身;b. 安装NVME SSD到转接卡(这里轻轻一推即可);c. 安装尾部螺丝。
  2. 很多人说更换SSD需要断电,我……因为懒,没有断电,直接拆的旧硬盘和安装的新硬盘。其实机身的电源线挺难拆的,我试了几秒钟,没有拆下来,因此选择直接安装。
  3. 有人说970 EVO不带螺丝和散热片,比较小家子气。嗯,的确小家子气。不过如果你是升级macbook SSD这个场景,其实这两个根本就不需要:螺丝用原装的即可无缝安装,散热片那是给台式机准备的,macbook根本装不进去。

恢复系统和数据

上面说备份的时候,我们只提到了备份数据,恢复的时候,因为是全新的SSD,系统也是没有的。因此整个恢复过程可以分为恢复系统和数据两部分。因为我们上面备份的数据里面没有系统,因此实际上从 Time Machine 恢复的时候,是先从网络自动恢复系统,然后再恢复数据。由于需要从网络下载macOS, 因此推荐你使用有线网络连接macbook进行恢复。

几个关键步骤:

  1. 开机按住 Command (⌘)-R ,然后选择Disk Utility, GUID + APFS 方式格式化硬盘;
  2. 然后选择从时间机器备份恢复
  3. 整个时间分两部分:转地球部分是在下载系统,使用有线网络大概用了1个半小时;接下来是恢复备份数据,大概也是5个小时,跟备份时间相当😂
  4. 恢复完数据以后,根据官方指引重置RP
  5. 然后拔掉网线和硬盘,重新开机。如果你以前数据较多,第一次输入用户名密码以后,会出现黑屏,只能看见一个鼠标。不要着急,耐心等待10分钟即可。
  6. 备份和恢复数据时间比较长,我都是选择在晚上完成,早上起来点一下按钮。因此,即使你只有一台macbook作为主力机,更换升级SSD过程中也完全不会影响你白天的使用。

升级后使用感受总结

  1. 升级后SSD性能提升到写 2500MB/s, 读 3000MB/s, 比原装SSD提升了好几倍,但使用上体会不到区别。
  2. 没有修改任何设置的前提下,即没有睡眠问题也没有耗电问题。购入的三星 970 EVO 出厂日期是 2020年1月,因此,我推测凡是今年购入的 970 EVO 应该升级后都可以完美兼容。
  3. SSD温度问题没有专门关注过,因为跟原厂一样的使用感受,具体是什么温度就不care了。
  4. SSD容量扩大4倍以后,补充了几个需要使用但是频率不高的软件,尤其是安装了几个虚拟机。不考虑喜新厌旧的前提下,感觉还能再战3年。

记一次数据库bug故障恢复

从一件小事说起

最近一个月不知何故,博客的VPS IP无法ping通。提交ticket要求更换ip, 毫无意外的被拒绝了。于是直接从当前VPS clone 一台间接实现了IP的更换。clone的文章参考官方指引即可。因为是克隆操作,因此所有的环境和数据都保持不变,配置成本约定于0。整个过程加上修改DNS,10分钟搞定。正准备来杯清茶休息一下的时候,发现新机器的mysql挂了:

2020-03-21T12:00:03.913175Z 0 [Note] InnoDB: Apply batch completed
2020-03-21T12:00:04.016847Z 0 [Note] InnoDB: Removed temporary tablespace data file: “ibtmp1”
2020-03-21T12:00:04.016974Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2020-03-21T12:00:04.017051Z 0 [Note] InnoDB: Setting file ‘./ibtmp1’ size to 12 MB. Physically writing the file full; Please wait …
2020-03-21T12:00:04.020703Z 0 [Note] InnoDB: Starting in background the rollback of uncommitted transactions
2020-03-21T12:00:04.020779Z 0 [Note] InnoDB: Rolling back trx with id 35499526, 1 rows to undo
12:00:04 UTC – mysqld got signal 11 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
Attempting to collect some information that could help diagnose the problem.
As this is a crash and something is definitely wrong, the information
collection process might fail.

key_buffer_size=8388608
read_buffer_size=131072
max_used_connections=0
max_threads=151
thread_count=0
connection_count=0
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 68195 K bytes of memory
Hope that’s ok; if not, decrease some variables in the equation.

Thread pointer: 0x0
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong…
stack_bottom = 0 thread_stack 0x40000
/usr/sbin/mysqld(my_print_stacktrace+0x2c)[0xed2ebc]
/usr/sbin/mysqld(handle_fatal_signal+0x451)[0x7b4ea1]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x10340)[0x7f85fd1a5340]
/usr/sbin/mysqld(_Z32page_cur_search_with_match_bytesPK11buf_block_tPK12dict_index_tPK8dtuple_t15page_cur_mode_tPmS9_S9_S9_P10page_cur_t+0x168)[0xf89528]
/usr/sbin/mysqld(_Z27btr_cur_search_to_nth_levelP12dict_index_tmPK8dtuple_t15page_cur_mode_tmP9btr_cur_tmPKcmP5mtr_t+0x1121)[0x10b2d31]
/usr/sbin/mysqld(_Z22row_search_index_entryP12dict_index_tPK8dtuple_tmP10btr_pcur_tP5mtr_t+0x11f)[0xffd4ff]
/usr/sbin/mysqld[0x11cb0d6]
/usr/sbin/mysqld(_Z12row_undo_insP11undo_node_tP9que_thr_t+0x22b)[0x11cc0bb]
/usr/sbin/mysqld(_Z13row_undo_stepP9que_thr_t+0x405)[0x1019385]
/usr/sbin/mysqld(_Z15que_run_threadsP9que_thr_t+0x871)[0xfa97c1]
/usr/sbin/mysqld(_Z31trx_rollback_or_clean_recoveredm+0xcdc)[0x106c8dc]
/usr/sbin/mysqld(trx_rollback_or_clean_all_recovered+0x4e)[0x106d7ee]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x8182)[0x7f85fd19d182]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7f85fc6aa47d]
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.
2020-03-21T12:00:04.056733Z mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended

从错误信息 mysqld got signal 11 看,应该是启动过程是尝试fix table触发了bug,因此启动失败。

如何解决 mysqld got signal 11

既然是fix corrupted table导致的问题,那么思路自然是先把mysql启动起来,备份数据,然后找到存在问题的table, 再逐步恢复数据(我的mysql server版本是:5.7.23,不同版本可能稍有差异):

  1. 如果服务器未正常停止,先停止mysql: service mysql stop
  2. 备份文件/var/lib/mysql/ib*: mkdir /tmp/fixdb && cp -rp /var/lib/mysql/ib* /tmp/fixdb
  3. 在配置文件/etc/mysql/my.cnf中添加如下内容:

[mysqld]

innodb_force_recovery = 3

  1. 启动mysql: service mysql start. 如果启动失败,尝试改大步骤3的数字,直到启动成功。
  2. 备份数据表: mysqldump -A -uUSERNAME -p > dump.sql
  3. 删除所有用户数据库:

mysql -uUSERNAME -p

drop database xxx…

  1. 停止mysql: service mysql stop
  2. 删除ib文件:rm /var/lib/mysql/ib*
  3. 删除步骤3中添加的两行内容
  4. 启动mysql: service mysql start. 在mysql错误文件(/var/log/mysql/error.log)中应该可以看到最开始导致启动失败的corrupted table.
  5. 恢复数据:mysql -uUSERNAME -p < dump.sql. 如果恢复过程中出现 Tablespace exists错误,则尝试删除ibd文件,然后重新导入数据:

ERROR 1813 (HY000) at line 268: Tablespace ‘DBNAME.TABLENAME‘ exists.

rm /var/lib/mysql/DBNAME/*.ibd

mysql -uUSERNAME -p < dump.sql

终于大功告成。恢复过程中小紧张了一下,使用了10年的VPS终于满血复活。

参考文献