2021,继续向前

年终总结

2020年

过去一年,大幅调整了投资战略,与时俱进,下半年开始扭亏为盈,实现了27%的净利润。

2021年

2021年要获得同样的利润是非常困难的,业内普通都持有较低的收益预期,投资更加谨慎。
今年开始,更倾向于减少股票换手率,加大仓位集中度,选择若干十分确定的股票长期持有,选择两个品种长期做短线波段。
看好港股今年会走出牛市,实现大反弹,因此将调整部分资金用于购买港股ETF,或具有港股通等交易权限的LOF。
看好A股基金投资,今年将不再摊大饼,而是瞄准若干基金的重仓股票,跟随加仓,与基金经理、机构抱团。

投资思路

主要投资路线:

  1. 行业估值较低,但业绩、基本面与行业政策面不断改善,有开启估值修复迹象的标的,如香港银行股
  2. 自下而上选股,靠过硬的行业垄断、优秀的公司管理层、很好的赛道、最好是垄断行业,如福耀玻璃
  3. 跟投公募基金与机构的重仓,等待基民的钱来不断抬高股价,赚一大笔就跑,如赣锋锂业、宁德时代
  4. 对于一些不死不活的行业,未来长期可能处于震荡阶段的标的,可用来做波段,如传媒与基建行业
  5. 放弃努力,选择优秀的主动基金,把钱交给值得信赖的基金经理
    其次,要加大宏观研究,深入分析国家政策,并充分理解国家对证券市场的看法与实际做法,以此来控制好仓位与投资预期。

期望

2021年投资收益期望为15-20%。

投资笔记

2021.11.19

今年还仅剩40多天,投资收益期望几乎是不可能完成了。这一年,有挺多策略,看起来是不正确的,值得反思
一是估值修复并不靠谱,年初挣钱后,清仓掉了香港银行LOF,回过头来看,无疑是非常正确的决定,后续这个品种,没有任何上涨了。
二是自下而上的选股,还是受大行情的影响,在福耀玻璃上,虽然挣了几万块钱,但福耀玻璃的走势是不及预期的,一年之中还是反反复复,没有打开上涨通道,选择一个好公司,并且长期拿着,确实特别难。
三是机构可能会变心,并且机构的策略琢磨不透,机构一旦清仓就特别决绝。今年大部分的利润都亏在了中国平安和立讯精密上,并且截止今日,这两个股票还没有复苏的迹象。立讯已经及时止损,不必浪费机会成本。
四是不死不活的行业,没能坚持搞下去,行业轮动还是A股较大的机会点,个股的风险过大,交易费与成交量,都不如ETF实在,后续仍然可以持续关注各类板块ETF。
五是今年亏损的最大头,个股赚钱的利润,全部给几个主动混合基金亏掉了,但仍然维持继续看好主动基金的策略不变,这部分不打算变更。
总结以往经验,美股才是YYDS,持续加仓中概互联与纳斯达克指数,长期看好优秀资本市场。A股市场还是维持低手续费的ETF板块轮动策略,挣市场波动的钱,同时保留一些底仓,挣市场上涨的钱,其余的钱all in美股指数。

2021.03.07

今年的投资收益基本盈亏平衡,不赚不亏,但仍然看好今年的收益。
对于资产的配置有了较大的变化,不再看好港股,清仓了所有港股资产,投资港股的策略是失败的,自己并不够专业,没法战胜港股市场的机构投资者。
将原先港股的资产配置,转移至国富大中华,看好徐成的投资能力,维持一定的港股投资额度,并适度加大投资,不再直接配置。
看好福耀玻璃,可逢低加仓,随着新能源与光伏行业的发展,福耀会有不错的利润。
维持看好立讯精密,作为Apple的代工商,未来的利润不会太好也不会太差,但足以支撑当前的股价,并没有太大的泡沫,所以无需担忧。
剔除了中国中铁、中国平安、新华保险、香港银行等,剔除中国中铁的原因是,降低做T所需的成本,传媒ETF也拥有较强的周期性,并且交易费率更低,故仅通过传媒ETF来进行波段交易,未来考虑增加一个ETF用于波段操作。剔除其他个股的主要原因是降低持仓个股的数量,控制仓位与提高持仓集中度,投资更加聚焦。
持仓更加集中,本金部分90%仓位配置了主动基金,继续放弃努力,选好基金,选好基金经理,放手让基金经理去做好投资。

2021.03.07

要多写写一点东西,不能靠记忆,应当多记录一些问题。人性是有弱点的,应当忘记股票曾经到过什么价格,忘记当前的成本是多少,面向未来。买卖逻辑应自洽,买的时候和卖的时候,逻辑应该是一样的。
降低今年的换手率,降低杠杆率,减少调仓频次。

2021.05.16

已经好久没更新了,最近两个月净值有了一些回升,但效果并不显著,今年还是未能扭亏为盈,其中4月底接近扭亏,5月继续下滑,主要受立讯精密的回调和基金的回撤。
当初股市仍然处于震荡时期,重新启用网格波段策略,对一些特定的ETF,执行短线策略,挣回一些资金用于对冲融资费率的亏损。初步选用传媒ETF与300ETF,对于福耀玻璃与中国中铁,执行大波段策略,有较大跌幅的时候买入,较大涨幅卖出。

Investment

fund percent(Q3)
中概互联ETF 23.83%
兴全合润LOF 20.05%
兴全模式LOF 14.44%
中国平安 10.32%
富国天惠LOF 8.34%
基建50ETF 7.89%
纳指ETF 7.67%
泓德丰泽LOF 7.45%
电子ETF 0.01%
传媒ETF 0.00%

Investment Report

date mtd ytd net value share HS300 HS300 ytd
2020.01.01 / / 0.8707 0.6489 4121.35 /
2020.12.31 +3.29% +27.74% 1.1126 1.0182 5211.29 +26.45%
2021.01.01 / / 1.1126 1.0182 5211.29 /
2021.01.23 +9.28% +9.28% 1.2156 1.0454 5569.78 +6.88%
2021.01.29 +3.07% +3.07% 1.1468 1.0672 5351.96 +2.70%
2021.02.08 +1.66% +4.79% 1.1659 1.2387 5564.56 +6.78%
2021.02.28 -2.26% +0.74% 1.12086 1.2387 5336.76 +2.40%
2021.03.09 -9.93% -9.25% 1.0096 1.3517 4971.00 -4.61%
2021.05.14 +3.19% -6.35% 1.0419 1.3517 5110.59 -1.93%
2021.11.19 +5.87% -1.33% 1.0978 1.3517 4890.06 -6.16%

2020,面向下一个十年

今年是进入股市的第8年,多年来,没有认真盘点过自己的收益,只知道自己有挣钱,但并不知道挣了多少,因此想借这个机会,一是盘点当前的投资情况,二是合理制定面向未来的更合适的投资策略。

写在前面

回顾自己一年来的持仓变化,投资理念也发生了翻天覆地的变化,投资一些以前不会尝试的标的。一年以前,我更关注上市公司市净率、市盈率等财务指标,相信并等待他们价值回归。最近几年投资市场分化比较严重,深刻反思了自己的投资理念,完全是在财务指标是把自己困住了。不能拿着2013年的投资理念继续在2020年搞投资。应与时俱进,不断更新自己的知识面。
价值投资应该更关注企业的长期经营与盈利情况,好的管理层,对股东负责的管理层,不然财务数据再好也没有用,投资最重要的就是赚钱,先把钱赚了,再谈其他,不赚钱就是loser。

对基金的看法

过去我并不太看好主动混合基金,基金经理很难解决一个悖论,就是你这么牛逼,能挣这么多钱,你为什么要帮我挣,你怎么不自己搞投资,你为什么不去搞私募。2015年老鼠仓的情况非常严重,导致我对基金有非常不好的印象。这个印象回想起来,反而影响到了自己挣钱,不能因为被几个渣男欺骗了,就不相信爱情,不结婚了。
投资是一件很复杂的事情,需要一定的规模、优秀的投资策略、控制利润回撤的能力、高效的投研团队,是需要整个投资团队协作的。如果一个基金经理已经拥有5-10年的公募基金经历,并且有非常好的信誉、回撤控制与卓越的年化收益,我们有什么理由去怀疑他们。

对投资的思考

某一天,我统计了过往几年的盈利情况,发现我的年化收益远远不如头部基金的基金经理,我开始思索自己投资跑赢基金经理的可能性,毕竟人家是专业的,在这方面投入了大量的时间、精力,是拿钱干活的。
自2019年起,开始小幅增持了ETF、LOF,发现比起股票,ETF与LOF更加抗风险、不收印花税、分红不收税、手续费更低,拥有众多优势。也开始不断补充和完善自己的投资体系,提升自己的知识面,增加对多种投资工具的了解。深入研究和学习别人的投资策略与投资理念,取其精华,去其糟粕。
既然我过往几年的平均年化收益,都不能跑赢这些优秀的基金经理,我为什么不调整自己的思路,拥抱变化,选择优秀的基金经理,让专业的人去做专业的事情呢?
人的一生,就是不断认清现实的过程,认清自己自己的投资水平与能力,解放自己,不再幸苦做很多不必要的研究,我只需要研究好基金与基金经理,与优秀的基金经理为伍,基金经理们会让利润跑起来,会得到更大的投资回报。

转变

2020年3月开始,我陆续将重仓个股转换成ETF与LOF,调整增持了大批LOF,根据折价情况买入了若干封闭基金,7月份完成了所有仓位的转移。
伴随着较好的市场行情,投资收益也开始水涨船高,取得了不俗的成绩。
我将原先100%的个股仓位,转成100%仓位的LOF+封闭基金,封闭基金根据折价情况不断调仓轮动,LOF根据业绩表现与回撤情况不断优胜略汰,并不断去发掘一些优秀的基金,通过融资融券买入约30%的仓位沪深股票,作为申购新股的市值,一方面可以获得优质股票股价上涨的盈利,另一方面可以通过新股申购,达到一定年化收益,用于抵消融资的利息。

未来计划与执行

为了更好回顾投资计划的执行,定期调整分析、优化投资策略,我将按月记录自己投资的净值变化。
以2020年8月27日,作为基准日期,当日收盘权益净值计为1,后续增资、减资将影响持有份额,不影响净值,通过统计净值来回顾与优化当前的投资方案。

投资记录

2020.08.30

本月中签一只新股,在云南白药上获益颇丰,若干投资的基金都创下净值历史新高。支付宝的小额投资完成了50%以上的仓位调整,把亏损、盈利能力较差的基金淘汰,增持优秀的基金。

2020.09.18

本月所投资的基金遇到较为大幅的回撤,通过一些个股的波段操作,挽回了一些收益,总体的利润未产生大幅回撤。后续在个股的操作上考虑投入更大的资金,风格上可以更加激进。基金方面的投资保持现有策略不变,继续看好基金未来的收益

2020.10.15

本月再次中签一只新股,收益有了小幅增长,本月盈利较大的标有:兴全合宜、生物医药、富国天惠、兴全模式、鸿德丰泽、银华大盘、兴全趋势。大幅降低了仓位,移出富国天惠、银华大盘、兴全趋势,加仓地产与银行。

2020.10.31

本月仅实现了2个点的增长,月底最后一天有较大的回撤,在广州酒家操作上面过于谨慎,提前做了减仓处理,没有及时收盘时买回完成当日做T,导致错过了一次大涨。继续看好港股、银行、房地产行业,投入一定比例的资金,期望后续能带来可观的收益。11月的策略继续加仓基金与ETF,减少个股持有比例。11月美国大选结束,预期股市应该会解决当前的分化窘境,还是有希望走出箱体行情,更看好是上涨。保持中等仓位配置,做好大跌后加仓准备。

2020.11.14

本月投资较为顺利,利润回撤控制也挺好的,多个波段的仓位也获得了较理想的收益,净值再创新高。
反思今年个别股票亏损,成也仓位,败也仓位,一个是生物医药ETF追高了,后续仓位控制不够好,出现了较大幅的亏损,另一个是运营商,作为国企尽管事实上垄断,但受到政策面的压制以及工信部要求的普惠,故尽管业绩还行,但股价不涨,生物医药遇到暂时回撤,但相信还是有机会复苏,运营商由于仓位控制尚可,对部分仓位止损转移至恒生指数,及时计提损失并挽回了较大收益。回溯减仓操作,止损还是非常合理且有必要的,没必要把时间浪费在辣鸡的身上。
还有一个个股也是因仓位控制不好,加仓过早,目前还是-2%左右,预计下周可以回本后出掉一半,若无法回本也将出掉一半降低仓位。后续应该更加控制好仓位,不管是短期波段还是长期价值投资,都应当经过试验性仓位后,才会大幅加仓,不应在个股上押注过多。
看好港股内资银行与房地产行业未来发展,将适度扩大两行业的投资。

2020.12.06

本月持仓净值创出历史新高,所持有的若干个ETF与LOF都有较好的涨幅,短线波段的收益情况也比较理想,因此做了适度减仓,降低杠杆比例,基本全部偿还了所有负债,考虑继续加仓传媒与生物医药。卖出了所有富国天惠的持仓,该基金近半年的走势都比较糟糕,看不到亮点。继续研究并补充一些备选基金。

2020.12.31

本月清仓了鸿德丰泽,主要原因是成交量太低,很难卖出,根本没有交易对手,回过头来看,是一个错误的决定,每次清仓后,都会继续上涨一波。
尝试买入中芯国际,几天内先下跌10个点,后上涨16个点,卖出后,又上涨了7-8个点,结论是这类股票不适合自己持有,买的金额也不高,即便盈利比例很高,也没有太大意义。
本月先后买入了福耀玻璃、立讯精密,小赚了8个点,后拿不住卖出了福耀玻璃,此时利润1800多,后来仔细想了想,越看越喜欢,又立即买回来,并且加仓了一倍,本月也盈利1万多。
因此也能得出一个浅显的道理,选股票比择时更重要,好的股票可以长期拿着,几乎可以不用任何操作,就能跑赢一切。
本月香港银行有小幅度回撤,在预想范围之内,比较看好香港银行,但同时认为还需要拿较长时间才会有结果。传媒ETF也触及到了新低,传媒ETF本来就是用来做网格与波段的,有波动就是好事,逆势在低位多次加仓。
短线波段操作本月不太理想,主要是也没什么时间操作,中午午休的时间有限,最大一笔为三七互娱,买入后第二天冲涨停,卖出赚了一小笔其余股票都是小赚或亏点手续费。
受益于整体指数新高,本月最后一天净值也是全年最高。明年加油。
以后更倾向于减少股票换手率,加大仓位集中度,选择若干十分确定的股票长期持有,选择两个品种长期做短线波段。

投资比例分配

固定仓位

fund percent(%) plan(%)
香港银行 18 25
兴全合宜 16 25
兴全模式 15 20
泓德丰泽 10 10
上海A股 8 12
深圳A股 5 8

动态/波段仓位

fund percent(%) plan(%)
恒生ETF 0 10
H股ETF 0 10
传媒ETF 24 20
生物医药ETF 0 20
运营商 8 8
地产ETF 0 5
500ETF / /

Investment Report

date mtd ytd net value share HS300 ytd
2020.01.01 / / 0.8707 0.6489 00.00%(4121.35)
2020.08.28 +8.52% +19.30% 1.0396 1 14.02%(4727.29)
2020.09.18 -1.87% +17.15% 1.0201 1 12.50%(4636.64)
2020.10.15 +3.55% +21.32% 1.0564 1 16.73%(4810.78)
2020.10.30 +2.12% +19.65% 1.0418 1 15.90%(4776.47)
2020.11.05 +4.24% +24.72% 1.0860 1 18.53%(4885.11)
2020.11.15 +5.25% +25.93% 1.0965 1 17.84%(4856.85)
2020.11.27 +3.59% +23.95% 1.0792 1 20.85%(4980.77)
2020.12.16 -0.19% +23.72% 1.0772 1.0182 20.20%(4953.87)
2020.12.31 +3.29% +27.74% 1.1126 1.0182 26.45%(5211.29)

proxy_next_upstream 对POST无效

需要添加non_idempotent,官方文档的说明是:
normally, requests with a non-idempotent method (POST, LOCK, PATCH) are not passed to the next server if a request has been sent to an upstream server (1.9.13); enabling this option explicitly allows retrying such requests;
意思是如果不加上non_idempotent,对POST这些不幂等的方法,出错是不会重试的。

猜测

按照严格RESTful设计,PUT和POST都是对资源的修改,比如新增一个用户、修改某个信息、增加积分等等。GET请求一般用于查询资源的情况,一般情况下都是幂等的,意味着不管执行多少次,结果都是一样的。当遇到5xx的时候,POST的请求如果没有使用事务,可能结束了,也可能没有结束,即便用了事务,也可能一定的几率会执行成功了,但没有正确返回。POST如果是用来新增一些资源,proxy_next_upstream可能会导致出现一些业务逻辑上的异常。
但很多场景下,出于加密或者其他考虑(如:前端不好支持等等),有些业务并不是按照严格的RESTful来实现的,如果后端做了一些充分的容错处理,支持接口幂等。那么是可以对POST等接口做一个失败重试,相应的配置要加上non_idempotent,就会生效。

爬虫的抓取错误

前言

一个网站在处理百度爬虫抓取情况的时候,遇到了大量的抓取错误,记录一下解决问题的过程和思路。
百度的解释是当百度spider访问服务器,进行tcp通信的时候,socket读写发生异常,导致数据不能正常返回。请检查服务器连接状况和防火墙设置是否符合预期
首先列出该网站的特征信息:香港机房,HTTPS请求,后端server为nginx。
先通过另外的域名,位于广州机房的网站,抓取若干次,发现还是偶发socket错误,同时将香港机房的请求由https改为http,抓取50次没有任何问题。故可以得出结论一:

  1. 不是因为机房位置问题导致的,而是因为HTTPS引起的,而具体是因为server配置不正确,还是受到GFW等干扰而引起的,不得而知。(内心os:某网站爬虫真垃圾)
    根据结论一,可以得出一个兜底策略,可以不用https,直接改用http,别搞这些幺蛾子了。

深入分析

本着继续挖掘https引起的问题,故还是深入研究一下问题所在。
首先怀疑Cipher suites与ocsp等问题,把这些安全配置逐个去掉,发现没有起到作用,还是有错误。
尝试过千万种可能之后,都开始怀疑人生了,最终得出一个结论,只有可能是百度爬虫自己的问题。于是把服务器的server直接关掉,抓取几次应该是得到443 Connection refused,但通过百度爬虫抓取,还是得到了socket 读写错误。(我服务器都关掉了,还是有这个错误,这只有可能是百度自己的错误了)
本以为能发现什么大的问题,找到服务器有什么常年存在的错误,结果是这个原因。

Vagrant 如何压缩空间

Vagrant

vagrant是个很好用的工具,可以用来工作流构建和管理虚拟机环境,常用的命令也很简单易用,可以配合VirtualBox来启动各类的虚拟机,简单易用。vagrant主要是负责镜像的管理,尤其是对于Mac系统来说,虚拟机比起Docker Desktop或者brew要更加方便管理、迁移、分享,可以更专注于linux做好事情,减少系统差异。另一个场景是当一个线上环境需要安装大量的依赖,如何对新人更加友好,如何使得所有的变更都能迅速同步给所有同学,vagrant也可以用于多环境的情况。
可以养成定期备份快照的好习惯,如果某些文件被误删,或者需要回滚一些操作的时候,就非常方便了。

如何压缩空间

随着使用时间的增长,vagrant的容器体积会不断变大,有一天可能会把宿主机的磁盘都占满。vagrant的容器类似docker,我认为他应该是会不断叠加层级,因为从观察来看,新建一个文件,再删除掉这个文件,镜像的大小并没有减少。他会有一些空间回收,但往往不是那么及时,那么从使用者的角度来说,如何让他更快回收空间,并且确保镜像尽可能小呢。
我罗列出我常用的几个步骤,其中//为注释的说明内容。

1
2
3
4
5
6
7
8
9
// 虚拟机内执行
// 清除所有的没用docker

docker system prune --volumes -a
// 对镜像做磁盘空间擦除

sudo dd if=/dev/zero of=/EMPTY bs=1M
sudo rm -f /EMPTY
// 宿主机执行
// 打包镜像

vagrant package --output package.box.20200214

这时候,已经压缩好的镜像就生成好了,也可以将该box分享给其他同学,作为一个内部测试环境等等。
把原虚拟机销毁(vagrant destory,不熟练的话,请谨慎使用),然后修改Vagrantfile,将文件名修改为刚刚打包好的box,通过vagrant up,虚拟机就又重新焕发新生了。

写在2020年代的开篇

2020年1月28日,2019-nCoV还在持续爆发与扩散,中国国务院延长了假期,阿富汗塔利班击落了美国CIA的客机(美国军方表示质疑),众多错综复杂的消息也预示着,2020年将是一个不平凡的一年。不平凡的一年,这句话套用到任何年份都可以,就像基金经理人总要在年终总结的时候,告诉所有投资人,他今年做了哪些正确的决定,帮助大家创造了多大的效益。

成长,过去一年学到的知识

拥抱不确定

学会拥抱不确定性,不确定性过去有、现在有、将来还会有,过去面对不确定性,我总是想着去避免,去对冲,君子不立于危墙之下,就是这个道理。但另一个道理又告诉我们,富贵险中求,人生得意须尽欢。不确定性中往往蕴含着机遇,如果一味消极对待,其实不利于我们个人或者财富增长。反而面对不确定性,应该更加积极、主动。说不定能有一番作为呢。

更加乐观、主动

无论悲观还是乐观,生活总是要继续的,不能说因为我悲观,接下来的日子我就不过了。既然悲观和乐观的结果都是一样的,那么何不乐观一点,至少自己可以开心一点。面对再大的困难和不确定性,可以做好最坏的准备,但要乐观应对。

用长期预测抵御短期预测风险

2019年,如果你在年初买入沪深300,到了年末卖出,她能赚40%以上。而多少聪明的基金管理人、分析师,都远远达不到这个收益,因为短期的预测会让他们认为沪深300已经高估了,到达了卖出点了。在证券市场中,把时间拉长看,现在永远都是低点。在漫漫人生路上,把时间拉长,现在永远都是起点。
短期预期其实往往会不准确,因为干扰因素太大了,就像我们很难预测下周一天气怎么样,温度如何,我参加考试能不能通过。但如果把时间拉长,一个地方的温度,晴天数量和阴天数量是确定的,只要我坚持考试,是一定会通过的,只是时间长短问题。股市是一定会涨的,只要你买了,不放弃,终有一日他会给你意想不到的回报。
所有的分析师中,最受欢迎的永远都是那些看涨的,如果涨了,说明他预测对了,如果不涨甚至跌了,至少他给了你安慰,给了你信心。反而是那些看跌的分析师,真的跌了,大部分人可能并不会感激他。
你的预期差,实现必然就差,反而不如对未来客观一点,最坏的可能你都想到了,还能再差到哪里呢?

未来,多一些思考

我想,我等,我期待,未来却不能因此安排。我遇见谁,会有怎样的对白,我等的人,他在多远的未来。
这是孙燕姿的遇见,面向2020年代,我们得明确自己想要达成什么目标,想成为一个怎样的人。现在就要开始着手准备应对下一个10年了。
TODO…

回顾与展望 2020

展望2020

这一年,看书还是没有看多少,去图书馆的次数还是下降了,背英语单词还是依旧只坚持了一小段时间,早睡早起也没有形成习惯。
这一年,还是继续贯彻了极简生活的理念,丢弃了很多不是必须的物品。
这一年,去了杨千嬅演唱会,去了很多地方旅游,去了香港多次露营与游玩。
这一年,离开了广告行业,重新出发。

回顾过往,继续制定2020年计划。

2020计划

家庭生活计划

  • 周三美食日
  • 周六活动日
  • 周日学习日

活动日:执行旅游计划中的短期任务、爬山、远足,因不可抗力可调整为其他积极向上的活动)
学习日:看书、学习

娱乐休闲计划

  • 日本旅游
  • 深圳游玩
  • 香港游玩
  • 澳门游玩
  • 短期旅游

每日时间表

  • 早睡早起,早起运动,早起喝一杯白开水
  • 每天一杯牛奶,吃早餐
  • 每天下午茶
  • 早晚刷牙洗脸洗澡洗头
  • 定期(每月两次)执行超市采购计划,保证家里任何时候都有吃的

财富增长计划

  • 扩大港股持股比例(目前20%,争取一年内扩大至50%)
  • 建立长效投资与长期投资策略(通过ETF+个股+低估行业股,盈利5%以上方可卖出)
  • 扩大可转债投入(尝试增持部分可转债)
  • 继续申购新股
  • 研究新的盈利渠道(含技术相关与非技术相关)

行为习惯提升计划

  • 不断跳出心理舒适区
  • 多聆听,多接纳多方意见
  • 多赞扬肯定对方
  • 严格要求自己,对他人要多宽容
  • 态度要温和
  • 增加对未来10年的思考,明确自己想要达成什么目标,想成为一个怎样的人

每周细分计划

  • 看2本书(细化书单:豆瓣托管
  • 看1部电影(豆瓣托管
  • 1次跑步运动
  • 1次爬山或远足
  • 看1集美剧(定期刷新剧目)
  • 看1次以上指定节目(细化列表)

2019计划与总结

总结语

过去的2019年,各项计划完成的还不错,实现了一定程度的自我提升,希望再接再厉。

家庭生活计划

  • 周三美食日 (吃顿大餐)✓(完成度80%)
  • 周四总结日 (回顾本周计划执行情况)✓(完成度20%)
  • 周六活动日 (执行旅游计划中的短期任务、爬山、远足,因不可抗力可调整为其他积极向上的活动) ✓(完成度20%)
  • 周日学习日 (看书、学习) ✓(完成度30%)

娱乐休闲计划

  • 日本旅游 ×
  • 深圳游玩 × (去了,但不是游玩)
  • 香港游玩 ✓
  • 澳门游玩 ✓
  • 短期旅游 ✓ (广西南宁、湖南郴州、四川成都与峨眉山、湖南长沙、湖北武汉)

每日时间表

  • 早起运动,不能起太晚 ✓ (30%)
  • 早起喝一杯白开水 ✓
  • 刷牙听歌洗澡洗头 ✓
  • 出门上班,希望能直接骑共享单车到地铁站,不要坐公交换乘 ×
  • 地铁上通过Telegram阅读过去一天技术领域的发展与新闻 ✓
  • 上班做好每天工作计划 ×
  • 睡前喝杯牛奶,刷牙洗脸洗澡上床 ✓

财富增长计划

  • 提升技术能力,不断学习新技术,并在生产环境中实践 ✓
  • 在证券投资方面,继续原有的持股策略,继续加大投入,并获取更大的财富 ✓
  • 开通港股通,通过上交所买卖香港地区上市的股票 ✓
  • 控制流动资金的比例,并做好流动资金增长计划 ✓

行为习惯提升计划

  • 不断跳出心理舒适区 ✓
  • 多聆听,多接纳多方意见 ✓
  • 多赞扬肯定对方 ✓
  • 严格要求自己,对他人要多宽容 ✓
  • 态度要温和 ✓

体重增长计划

  • 定期执行超市采购计划,保证家里任何时候都有吃的 ✓ (70%)
  • 每天下午增加一个下午茶 ✓ (50%)
  • 要多吃,辅助定期运动 ✓ (已完成体重目标,60KG)

每周细分计划

  • 看2本书(细化) ×
  • 看1部电影 ✓
  • 1次跑步运动 ×
  • 1次爬山或远足 ×
  • 看1集美剧(定期刷新剧目) ×
  • 看1次以上指定节目(细化列表)

Go的CICD、Module、构建、测试

前言

最近在做一些项目的重构,将一些服务和功能逻辑逐渐迁移到Go,或者通过来来重写一遍。一是优化相关逻辑,删减部分代码和逻辑功能,二是之前的架构和服务的部署方式,已经远远落后于时代,不论是开发效率、代码检查、部署与发布上线等等,都消耗了大量不必要的时间,严重影响开发效率。

CICD有很多方案,如Drone、Jenkins、Gitlab等,过往的经历告诉我,不能单纯为了Go而使用Go,除非Go编写的服务确实好用,足够成果。从简单实现的角度,通过Gitlab来完成,公司的部署环境有些特殊,有安全层面的考虑,是不能直接访问外网的,包括但不限于docker pull、go get、go mod download等等。如何加快CI的执行速度,如何使得构建后的镜像最小,减少传输带宽,如何复用Go相关的package,减少多次构建需要重新下载等等,就这些问题分享一下我的思路和做法。

基本概念

CI的全称是Continuous Integration,表示持续集成。
在常见的开发场景中,开发人员可能会频繁地提交自己的代码,这些提交的代码,先通过提交Merge Request,再经过Code Review合并到主分支,最终经过测试、灰度,然后上线。
CI主要作用是保障Code Review之前的代码,通过一系列自动化测试验证代码的质量和Bug,提升代码质量,并根据测试结果,向开发人员或团队进行预警。
CI同时也会检查Merge之后的代码是否正常,符合一切预期。

CI的好处

减少Review代码同学的压力与工作量

假若有一个同学经常写bug,他的代码每次都能测出一大堆问题,他自己也没有意识主动去检查自己的代码能不能跑起来,全靠你帮他发现,有些变量名写错了又不好发现。你每次提醒他,他都能快速意识到自己的问题,但下次还是可能会遇到。你作为负责Review代码的同事,面对大量的改动,是否有些担心?

制定并维护团队代码规范

你是一个技术管理,你为团队制定了一系列规范,如上线前自测、各个模块要有相应的设计与说明文档、数据库的DDL变更要及时维护在代码库中、代码的测试用例覆盖率要达到50%。经过一段时间,你发现这些问题并没有很好的改善,如何能够让一起定下规范严格执行呢?

快速迭代,小步快跑

在开发过程中,当你需要改到一些你不是非常熟悉的模块,总担心自己会不会改错一些逻辑,当初写这个逻辑的同学可能也不在了,那么如何确保自己修改的内容有效呢?产品经理又催得紧要求今晚上线?

持续改进与提升

在开发中,你写了一个模块,当时是有较高的QPS,有正常的结果返回,结果随着项目的迭代,你发现该模块变得越来越慢。你发现当初大家约定的Code Style,慢慢也开始变样了,一个方法里面有多种实现,怎么办?

怎么做

CI可以代码库设置了一个较高的标准,所有不符合规范,有语法错误的代码,都可以直接拒绝合并至主分支。
根据不同语言,可以检查语法错误、变量定义但未使用、重复引入package、未格式化、scheme定义不正确、测试用例等等。

  • 代码提交之后,将会根据分支进行不同的自动化处理:
    • 代码常规检查(Code Style、代码底层实现Code Lint等,检测所有语法错误、告警、未使用代码等)
    • 自动化单元测试(输出结果与测试覆盖率,对代码逻辑检测)
    • 复杂用例覆盖测试(构造MySQL、Redis等数据,对业务逻辑检测)
  • 代码Review阶段,由于上一阶段已经对代码质量做了基本检查,相关reviewer只需要review逻辑和实现方案即可。
  • 合并待发布阶段,会自动检查是否冲突,没有冲突自动合并,有冲突则通知相关同学人工介入进行git rebase等处理。
  • 构建阶段,CI可以根据Dockerfile自动构建并将分支推送至镜像仓库。
  • 部署阶段,发布到测试环境、预发环境、线上环境,灰度上线等。

根据上述的过程,我们其实已经将各类简单的脚本变成了一系列自动化执行的流程,也带来了标准化,可以直接一键应用到所有的项目。这就是持续集成,在我们背后无声无息的进行着,减少了大量极其浪费资源的人工执行,对研发团队来说,解决了大量的资源,对研发同学来说,可以减少review代码、测试的时间,也可以更加自信上线,快速迭代,更加专注产品、业务打磨。

在研发流程中,每个人只需要关注自己开发的功能,并编写测试用例来确保自己的功能(逻辑)不受其他人提交的代码影响,同时确保自己没有影响到别人功能(逻辑),其他代码质量、逻辑检验由CI完成。

Gitlab Runner

Gitlab其实是能够关联一些很好的工具,比如一些需求管理、Wiki等等。其中Gitlab CI可以做一些代码检查、跑测试用例、自动构建等等工作。我们使用的代码仓库也是Gitlab,那么使用Gitlab直接做CI,是最顺其自然,最方便的事情了。
常见的大项目下面会有很多微服务,各个服务之间存在交叉影响,能够完善测试各个数据库、缓存之间的交互,模拟流量和数据,在一个小型环境中跑通全部测试用例,这对开发效率与自动化是非常有意义的。
Gitlab CI依靠Gitlab Runner来运行,Gitlab Runner可以通过docker容器来运行,可以配置最大任务数限制,当有git commit的时候,他就会拉取最新的代码,对代码做一些CICD,这些配置命令,可以写在.gitlab-ci.yml,Gitlab Runner会按这个配置来执行这些计划任务。当测试不通过的时候,会发送邮件到对应的邮箱。
对应的Dockerfile其实可以很简单,只需要加入配置文件即可:

1
2
3
FROM gitlab/gitlab-runner:latest
WORKDIR /
COPY ./config.toml /etc/gitlab-runner

Gitlab Runner的注册其实也很简单,可以先起一个空镜像容器,运行sudo gitlab-ci-multi-runner register,输入gitlab的链接、Token、Runner的名字、类型等等,就会生成一个如下的配置,这个配置可以保存下来,将其提交到镜像中,这个容器就可以发布到线上了。其中concurrent表示同时运行的任务数,pull_policy等拉取规则可以定制化修改一下。
需要特别留意的是,docker的sock文件是需要挂载进镜像的,以便Gitlab Runner能够运行各类docker镜像来跑Gitlab的CI。
配置参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
concurrent = 6
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "CI-name"
url = "https://git.y.cn/"
token = "xxxx"
executor = "docker"
[runners.custom_build_dir]
[runners.docker]
tls_verify = false
image = "golang:lastest"
memory = "4g"
cpus = "4"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
pull_policy = "if-not-present"
shm_size = 0
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.custom]
run_exec = ""

通过docker命令可以将gitlab runner启动docker run --net=host --rm -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest,这时候任何满足规则的commit都会触发Gitlab CI。可以根据不同的语言来配置不同的.gitlab-ci.yml,根据项目的特性来编写一些定制化的检查。如if-not-present等配置可以在docker不存在的时候,才拉取相关分支。

镜像构建

docker对大家来讲,已经非常常见了,并不是什么新潮的东西。但经常能看到大家构建出来的镜像,并不是最佳实践,构建出来的镜像包含了很多不必要的内容,尤其是如果这个镜像作为基础镜像需要给其他人使用的,那么这就很不负责任了。我只是跑一个简单的服务,你却需要我docker pull一个4GB的镜像,要花大量时间等待,尤其是网络不好的时候,编译发布也不方便。
如何构建出一个体积最小的镜像,这是我们需要对自己的基本要求,也是一个基本良心。

合并多个RUN语句

看过大量的Dockerfile都会发现,很多Dockerfile都用了一些奇怪的技巧,用了大量的&&,来替代多个RUN,因为根据docker镜像构建的原理,其实就和git commit一样,是逐层叠加的,层数越多,占用的空间也就会越大。

多阶段构建

若多个阶段使用同个镜像,那么多阶段构建等于压缩了中间多个层,将他们合并到一个层。如我们在git中add了一个较大的文件,然后下一次commit的时候把他删除了,虽然我们拉取这个git代码时,这个文件不在了,但是他一直存在在这个仓库,还是会占用较大的体积。所以我们做的ADD data ./RUN rm ./data,其实就是个障眼法,掩耳盗铃,这个data还是存在于镜像中。所以可以在移除掉之后,通过多阶段构建,将结果COPY一份,不需要中间过程产生的文件等。

1
2
3
4
5
6
7
FROM golang:1.12 as build-env
WORKDIR /go/src/y.cn/some
ADD . ./
RUN CGO_ENABLED=0 GO111MODULE=on go build -ldflags -o some y.cn/some
FROM golang:1.12
WORKDIR /go
COPY --from=build-env /go/src/y.cn/some/some ./

上述脚本已经将所编译的some,copy到一个新的镜像,这就是一个简单合并各个镜像层。

distroless

这是Google提供的一个容器库,支持多个主流语言,仅包含该语言所需的环境、二进制文件和脚本,他甚至shell都没有,所以你想attach进去容器都是不行的,当docker相关的日志和监控比较完善的时候,才有条件使用。

Alpine

Alpine是各类镜像使用最多的基础镜像,Alpine是一个轻量级、面向安全的linux发行版,也是比较实用的镜像中最小的一个,如最新的3.10版本,仅有5MB大小。如Go开发的脚本、服务,可以将二进制文件构建好后,copy到一个干净的Alpine镜像中,这样得到的镜像大小就特别小,约等于Alpine镜像大小+Go二进制包大小。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM golang:1.12 as build-env
WORKDIR /go/src/y.cn
RUN git clone git@y.cn:some.git --depth 1 \
&& cd some \
&& CGO_ENABLED=0 GO111MODULE=on go build -ldflags -o some y.cn/some

FROM alpine:3.10
RUN apk update \
&& apk upgrade \
&& apk add --no-cache \
ca-certificates \
&& update-ca-certificates 2>/dev/null || true
WORKDIR /data
COPY --from=build-env /go/src/y.cn/some/some ./
ADD conf.yml ./etc
ENTRYPOINT ["./SERVICE_NAME"]

这样就是得到了一个非常小的镜像,通常10~30MB的一个镜像就能将服务容器跑起来。因为Alpine是非常小的,所以并不支持gcc环境等,需要CGO_ENABLED=0关闭CGO,不然你会发现编译后的二进制包无法运行。

Go Module

Go Mod是Go新引入的一个包管理工具,实际上谈不上成熟,官方也没有推荐使用,但go mod毕竟还是未来,提前做好准备还是十分必要的。原先的GoVendor/GoDep的包管理,并未在部署上尝试特别大的问题。但由于go mod下载的package其实是放在你的$GOPATH/pkg/mod中,并没有加载到你的项目中,go mod vendor我执行之后也并未成果,暂时没找到什么原因。
所以使用go mod也带来一个挑战,事实上很多服务器的环境,并没有一个放开的公网网络,若 package之前未层使用过,go build或者go mod download的时候,都需要下载对应的package。意味着给Go项目的CICD、测试带来了一些影响。
在如何解决这类问题方面,分享一下我的看法,无非就是线上环境的$GOPATH/pkg/mod需要提前准备好相关package的问题。想到了可以通过golang:latest作为基础镜像,把项目git仓库ADD进去,go mod download下载所有所需的package,然后删掉git库,commit这个镜像到线上,那线上就有pkg/mod了。然后这个镜像就可以作为线上构建的基础镜像,包含所需的库,并且提供一些必备的工具脚本。

1
2
3
4
5
6
7
8
9
10
11
FROM golang:1.13 as build-env
WORKDIR /go/src/y.cn/some
COPY go.mod ./
RUN GO111MODULE=on go mod download
FROM golang:1.13
WORKDIR /go
RUN apt-get update && apt-get install -y mariadb-client > /dev/null
RUN go get golang.org/x/tools/cmd/goimports \
&& go get honnef.co/go/tools/cmd/staticcheck \
&& go get github.com/golangci/golangci-lint/cmd/golangci-lint
COPY --from=build-env /go/ ./

最近一些感想

最近还是提了离职,其实这个想法考虑了很长时间,也确实是经过慎重思考之后才决定的。时间不长不短,不到两年的时间内,对广告行业有了长足的认识,在期间也通过实际行动做到了用科技改变生活、促进流水提升,能制定适宜业务的技术实现方案、架构调整等等,2年来最大的收获不仅仅是技术能力的提升,更重要的是业务思维。离开广告行业其实也是有些不舍的,但套用另一个同事的话来讲,哪有什么不舍的,都是打工,找到自己最舒适、最开心的活法才是更重要的。
临走之际,其实往往都会有很多谈话。譬如聊聊你在公司觉得有哪些让你觉得不舒服的地方、你觉得可以改进的问题、你对这个业务的看法、离职的原因是什么,甚至会问问你有没有挽回的余地。离职的理由往往千万种,上班太早,领导太傻逼,工作太无聊,没啥成就感,工作安排不合理,业务太烦,高层不靠谱,不懂管理、看不到希望、钱没给够等等都是理由。
一份工作,主要靠三点来维持,相处的人、工作内容、薪酬,三者缺二不可,只要任意两点崩塌,就没法继续待下去了。2年前的一个同事群,一共9个人,现在已经只剩下2个人。这个行业流动性还是很高的,没有谁离了谁就不行了。
薪酬、职级没调整,是比较直接的原因之一,不少同事在有米的时间已经很长很长了,对这些同事而言,有米是第一份工作,也是倾注了蛮多情感的家,有米的技术栈其实都比较前沿,技术同学的能力都还不错,广州的技术公司并不多,圈子就这么大,有米的同学们还是很有市场竞争力。早些年的有米还是很不错的,弹性的考勤制度、双休、少加班(至少不强制),这种制度比较考验主动性,是建立在一个互相信任的基础上的,相对扁平化的管理,自由的环境。近两年公司的一系列战略性错误,对业务、产品的短视,不接底气的制度,都是近两年人才流失、业务方向迷失的根本原因。一个公司堕落的开始,都是注重考勤,开始过分关注员工的上班时间,加班情况,又缺乏激励,缺乏对自身实力与定位的了解,没有关注员工的自身发展,没有一个适宜的绩效评定。不懂业务的高层,不接地气的考勤制度,不尊重市场规律,朝更暮改的战略方向。高层想法变得太快,过于随意,普通同学其实是很累的,并不是大家不够努力,而且方向不对。有米并不是一个大公司,但似乎所有大公司有的弊病,都不少。
其实不管是平时的工作,还是离职的例行问答,我的回答都是很直接、直率的,也会经常与leader交换一下看法和意见,沟通所有关键问题的想法和gap,并解决这类问题。这些都是中层能直接解决的问题,并且都解决的不错,我们也找到很好的协作方式,确实做出了较好的成绩。但高层其实很少聆听他人的意见,不管是业务方向上还是公司经营方式,反馈最多的考勤问题,就直接置之不理,带着这种傲慢与偏见。广州的早高峰特别挤,挤到你怀疑人生,挤到你根本就不想去上班,然而你去到公司楼下,还要多排队15-20分钟等电梯,可能你会怀疑早到这点时间能做什么,毕竟同学们付出了大于半个小时通勤时间的成本。
广告行业其实是一个非常朝气蓬勃的行业,当你自己遇到问题了,可以了解市场和同行的情况,你应该反思自己是不是哪里做得不对,而不是责怪行情、市场,往往不是这个市场不行了,而是你不行了。看看别家的年会与年终奖,不要责怪大环境,经济再差也有大把赚钱的公司,好的技术根本不愁工作。找不到工作的都是各个行业的底层。

技术的价值

以前我一直在思考技术的价值在哪里,有哪些别人所不具备的优势,最近似乎得到了一些答案。纵观很多技术经理、技术总监,有的很懂业务,但缺乏技术架构认识,很难管住其他的技术,想法、关注点与实际也有些差距,就很难维持一个高效稳定业务系统,有的技术可能很强,但缺乏对业务的理解,重心放在技术代码的提升,如何规范化,如何提升技术的能力等等,但其实会发现,如果你缺乏对业务的了解,你的技术再好,方向错了,业务场景发生了变化,再多的努力都是无用功。做技术、做架构,我认为都不应该脱离业务思维,脱离了业务思维的架构师,往往会给你一个很高大上的架构,他确实很好,技术也很厉害,但不适合这个业务。
作为技术负责,如何使用有限的资源,做更多、更大的事情,这才是我们的价值体现。资源永远都是稀缺的,如果有1000个bug和100个紧急的业务需求,你如何判断哪50个是最重要、最迫切的。这要求你需要具备行业敏锐度,有判断能力,了解你的业务场景是面向哪些用户,你的用户群体最在意的是什么?你要建造的是一栋大厦,而不仅仅是一堵墙,这面墙有些瑕疵,但并不影响你这栋大楼的按期交付,别把大量的时间耗费在这些小事上面。
靠谱的程序员很难得,你交给他一个需求,他会先判断这个需求的合理性、场景,有争议部分事先充分沟通,制定一个适宜的方案,跟需求方确认这个方案的预期,开发,并且做足测试,确认功能的完整性,和需求方一起验收需求,通过数据回顾功能的作用,并能主动做出一些优化、提出一些建议。能做到这些的,都是非常靠谱的技术,你会很信任他,愿意把更多更重要的事情,交给他负责。

对海外市场看法

海外其实是一个非常有前景的市场,毕竟除了中国,其他的都算海外,市场够大(😄),尤其是新兴市场,你可以照搬你以往的成功经验,适当改造,通过一些接地气的方案,就能在一个新的市场收割一波。再从汇率角度考虑,比如你在美国市场赚2美元,换回来就是14元了,比起外国公司,坐拥廉价的中国劳动力,还能在美国、欧洲等这些海外市场同台竞争,这就是一种网络倾销。
只要你的业务广,这就像是一个风投,多方押注,总会有一个成功的,东方不亮西方亮,这个市场不成功,换一个市场再尝试一次。成功一个就能收回一切成本,并且大赚一笔,而且没有什么市场准入、政策风险。

回顾与展望 2019

2018年总结

这一年的目标还是没有实现,看书没有看多少,甚至去图书馆的次数也少了很多,背英语单词坚持了小半年,但没有坚持下去。早睡早起也没有做好,还是比较迟才睡觉,这里有工作的原因,也有自己生活习惯的原因。但在极简方面做得还是不错,减少了很多不需要、多余的物品。演唱会没有去,这一年去了日本旅游,也去了成都旅游,在峨眉山看雪,也去了香港若干次,其中两次在香港徒步与露营,走了香港比较著名的麦理浩径,也去了香港最南的蒲台岛。
这一年也取得了一些不便公开的成果。这一年在业务上更加深入了,对广告行业也有了一定的了解,但感觉在技术上感觉没有特别大的进步、成就感,所以接下来要加强技术学习。

回顾过往,继续制定2019年计划。

2019计划

家庭生活计划

  • 周三美食日 (吃顿大餐)
  • 周四总结日 (回顾本周计划执行情况)
  • 周六活动日 (执行旅游计划中的短期任务、爬山、远足,因不可抗力可调整为其他积极向上的活动)
  • 周日学习日 (看书、学习)

娱乐休闲计划

  • 日本旅游
  • 深圳游玩
  • 香港游玩
  • 澳门游玩
  • 短期旅游(城市本地景点活动探索)

每日时间表

  • 早起运动,不能起太晚
  • 早起喝一杯白开水
  • 刷牙听歌洗澡洗头
  • 出门上班,希望能直接骑共享单车到地铁站,不要坐公交换乘
  • 地铁上通过Telegram阅读过去一天技术领域的发展与新闻
  • 上班做好每天工作计划
  • 睡前喝杯牛奶,刷牙洗脸洗澡上床

财富增长计划

  • 提升技术能力,不断学习新技术,并在生产环境中实践
  • 在证券投资方面,继续原有的持股策略,继续加大投入,并获取更大的财富
  • 开通港股通,通过上交所买卖香港地区上市的股票
  • 控制流动资金的比例,并做好流动资金增长计划

行为习惯提升计划

  • 不断跳出心理舒适区
  • 多聆听,多接纳多方意见
  • 多赞扬肯定对方
  • 严格要求自己,对他人要多宽容
  • 态度要温和

体重增长计划

  • 定期执行超市采购计划,保证家里任何时候都有吃的
  • 每天下午增加一个下午茶
  • 要多吃,辅助定期运动

每周细分计划

  • 看2本书(细化)
  • 看1部电影
  • 1次跑步运动
  • 1次爬山或远足
  • 看1集美剧(定期刷新剧目)
  • 看1次以上指定节目(细化列表)