我这4年都做了什么
为什么要写这篇文章
我理解的P5大佬应该具备的能力
公司要求和我的理解
- 作为事业部内公认的某方面的专家,能够解决较复杂的问题或领导大中型项目;
- 前面半句比较抽象,也不好自我证明
- 后面半句更具体一些,我理解要么就是解决某一个专业方向的业界技术难题,以我略懂的云计算领域来举例,你要可以解决底层虚拟化性能问题,优化之后能达到业界领先水平,或者在提升计算资源利用率方面做到业界领先,或者在网络方面性能水平达到业界领先(而不是仅仅用开源跑起来),存储领域你就要对标业界主流开源项目的性能和可靠性(最好可以超越),或者你可以成为某个大型开源社区的core developer,甚至某个子模块的maintainer,或者中小型但比较流行的开源社区的maintainer
- 就是要领导过大中型项目,这个我理解你要带领团队开发过一个完整的项目,我理解中型项目标准应该是5w行以上业务代码,核心功能模块3个或以上,大型项目则要超过10w行。这个标准可能实际还会更高一些。
- 在本专业某主要领域具有精通、全面的知识和技能,是集团内公认这一领域的专家,在多个子领域的技术能力在集团内领先,在集团内作出显著创新;
- 还是后半句更具体,我理解多个子领域的技术能力在集团内领先,这一点就要做到你主导的项目在集团内没有比你更好的解决方案,如果有,则表示你的技术能力不够领先;有一些公司有内部赛马机制(也有叫红军蓝军的),这种情况下就很容易体现出你的项目是否在集团内领先了
- 在集团内作出显著创新,这方面参考创新奖申报条件,如果是集团外部或者业界已经用了比较长的时间或者成熟的方案,你只是在集团内部最先引入或者稍加改进,这不能算创新,创新要引领业界趋势,而不是简单的跟随
- 技术成果对所在事业部的成功是重要的依赖因素;
- 这个也容易理解,你负责的项目是否对事业部OKR有很好的支撑效果,项目的成功对事业部OKR会产生较大的正面影响,项目不成功会导致严重的负面影响。如果这个项目对事业部的OKR来说可有可无,那就要考虑项目存在的必要性和价值了,这方面做维护性的项目肯定是吃亏的
- 能够解决复杂的问题或领导大中型项目;
- 与第一条重复
- 能够把握本专业的发展趋势,并是与本专业发展规划与业内发展趋势相吻合;
- 这一点比较抽象,比较难自证,但是可以参考第二点,技术能力在集团内领先,并作出显著创新,如果不能把握本专业的发展趋势,就很难做到显著创新
- 可以指导本专业内的一个子系统有效运行。
- 参考第一点,能领导大中型项目应该就满足这条
我的不足
- 在多个子领域的技术能力在集团内领先,在集团内作出显著创新;
- 创新这块应该有些子领域做的还不错,还有个别领域正在做,但是落地成果还没有很好的体现,目前还处于推广初期
- 能够把握本专业的发展趋势,并是与本专业发展规划与业内发展趋势相吻合;
- 这方面跟上面一条有点关联,推广顺利的话就能证明趋势把握的是正确的,否则就比较难说
- 绩效不算好,近几年一直都是B+,原因我理解主要包括:
- 前两年做开发,产出和落地不明显,抖动问题解决了之后,由于规模比较大,升级本身也会造成IO抖动,因此需要非常长的升级上线时间,当时效果还没有体现,并且Ceph项目是维护项目,确实也比较难出高绩效
- 项目带的不好,主要是Curve这块,近两年一直都在开发新的文件存储功能,近期才刚刚开始落地,项目价值还没有很好的体现出来;另外块存储的性能优势也没有达成质的飞跃
- NOS项目我认为做的还算不错,虽然也是维护项目,线上故障也有几次,但是近两年一直在进行微创新
- Curve项目发展不达预期,尤其是开源社区建设方面,外部用户数量还不太多,这个原因有很多,最根本的还是我们内功没练好,功能也比较欠缺,用户想用也用不起来
怎么弥补
- 尽快把不足的子领域的推广落地效果拿出来,展示出来项目在集团内或者业界的创新成果和给事业部带来的收益。
- 某些子领域项目的研发进度有些略低于预期,这与项目的复杂度和团队成员的构成有一定关系,也与个人的项目管理能力有一定关系,这2个方面要继续加强,提升团队战斗力和个人项目管理能力
- 复盘,思考改进方向
基本信息
工作经历
申请理由
- Ceph项目(2020年开始主导):
- 参与Ceph成本优化项目,2020年成本下降到2018年的1/6
- 参与Ceph块存储优化项目,通过规范运维标准化及配套工具,优化集群监控报警,块存储近4年未出现较大故障,基本没有SLA损失,云盘抖动情况显著改善,同时节省SA半个人力
- 参与并主导cephfs容器场景产品化项目,填补了k8s RWX PVC存储的空白,解决了传媒,严选,云音乐等部门共享文件存储的痛点,集群数量达到10+,业务数据达到xxPB+
- Curve项目(2020年开始主导):
- 推动Curve块存储业务规模发展,2年内集团内部存储数据容量从不到xxxTB增加到超xxPB,同时发展外部用户数家;近2年未发生集群级故障,性能和稳定性相比Ceph云盘有了极大提升了
- 带领团队完成了Curve文件存储的规划、设计及开发,数据和元数据相关性能均达到开源存储项目的领先水平,目前正在推广落地中
- Curve开源社区建设方面,推动Curve加入CNCF基金会sandbox项目、信创认证、PG数据库社区共建等社区建设工作,目前已有数位外部贡献者,以及数家外部用户,测试中用户10+
- NOS项目(2020年开始主导):
- 通过技术架构升级推动NOS内部降本,相比xx云OSS 9折甚至更低;开发上线1.2副本低频存储(xxPB)及冷归档存储(xxPB),为业务方节省大量成本
- 持续进行业务拓展(xx、xx、xx等),年营收增长达30%以上
- 通过主动为业务降本及共建等手段,持续提升业务方满意度,上半年更创新高;近2年SLA均超过99.5%
- 带领Ceph团队支撑近千台规模Ceph块存储和文件存储产品,对Ceph进行较多定制化开发和性能优化,快速响应解决多次开源社区bug导致的故障
- 带领Curve团队持续优化性能并相比开源竞品保持领先优势;在Curve文件存储架构设计和开发落地、开源社区建设等方面成果显著
- 带领NOS项目通过内部降本、主动的为业务优化成本,项目的满意度提升显著,年存储数据增量30%以上,容量翻番达xxPB,为基础平台实现收支平衡贡献了较多的营收和利润,同时也获得了xx、xx内部新增大客户,以及外部商业化项目xx
业务贡献
Ceph优化
- 成本优化:机柜整合,存储池整合,容量均衡,空间清理(社区bug导致集群topo信息额外占用了大量存储空间)
- IO抖动优化:ceph的io抖动问题对业务影响非常大,而且很频繁,一直是业务抱怨最多的痛点问题,18~19年花了很大力气去优化,这几年已经有了极大改善(当然也有一部分原因是个别业务方做了一些日志异步打印等方面的改造)
- 运维优化:ceph的运维工作,经历了3个阶段,首先是ceph开发团队自己运维,之后是sre/sa运维,最后又回归到了ceph开发团队,切换给sre/sa的原因是研发团队想专注做开发工作,运维毕竟不是研发团队的强项,后来又切到ceph开发团队的原因,也是ceph运维具有极高的复杂性和问题紧急分析处理能力,如果对ceph不够熟悉,定位分析时间长还只是一方面,严重的话会导致把问题放大进一步恶化,又扯远了。。。总之这块就是把之前要人肉凌晨2点操作的日常运维工作,全部实现了自动化无人值守(之前sre也做过类似工具,但是因为对ceph技术细节了解不够深入,导致了线上事故就没有继续使用),并且做到了不会造成IO抖动,这一点我认为是非常值得ceph团队骄傲的
- cephfs共享文件存储产品化:ceph团队最开始只有块存储(rbd)项目在做,但共享文件存储需求在k8s集群的部分业务场景下是强需求(RMX的PVC),比如AI训练、机器学习、web服务端共享存储、分布式视频处理等,但是公司内部没有团队提供相关的存储系统,19年的时候ceph团队就把cephfs这个存储系统给产品化了,解决了多个业务团队的需求,后面还跟云音乐机器学习平台共建了几个高级特性,目前有10多个业务方生产集群在跑
- ceph性能优化:通过改造ceph底层引擎以及增加扩展接口,提升ceph性能
- ceph生产环境故障处理:面对几十个集群,这几年我们遇到过多次线上生产环境的故障,基本都是社区bug导致的(我们ceph团队开发的功能和运维操作,可以说没有引入过线上事故),从发现事故到业务快速恢复,即考验对ceph的掌控程度,也考验紧急情况下的团队合作能力,这一点我对ceph团队的小伙伴非常满意
- ceph商业化项目支撑:ceph团队给轻舟、低代码、easyAI等业务也提供了很多poc甚至生产环境的L2支持(主要形态是共享文件存储和对象存储),帮助相关团队解决了不少技术问题;甚至还做了rgw对象存储的商业化尝试,另外也有一些集团内部业务自己部署的ceph集群遇到问题也会找我们解决
背景和必要性
- 成本优化:这方面的必要性不用细述,都能理解,集团这几年的重点考核要求之一
- IO抖动优化:这个涉及到业务方满意度甚至基础设施部的SLA,也是基础设施团队的重点考核要求之一
- 运维优化:节省人力(否则每周2次的日常运维,都是人肉在凌晨2点做,通常耗时半小时以上,ceph团队一共就3个人肯定吃不消),另外可以减少人为操作导致的故障和IO抖动(运维流程标准化、工具化、可回溯),这也是团队经过长期运维实践总结出经验固化到工具里,工具刚开始用的时候也是人肉观察调整了一个多月才敢无人值守,就怕造成抖动或事故
- cephfs产品化:这个也不用多解释,从0到1,解决了共享文件存储的业务需求
项目挑战
挑战1:IO抖动问题优化
- 部署问题:ceph monitor服务是整个集群唯一的中心化服务,正常情况下他不会对IO时延产生影响,但是由于最开始选型的同事没考虑到在异常场景下会导致恢复时间过长带来IO抖动
- ceph本身架构问题:多副本强一致导致任何一个节点或磁盘的响应时间超过3s就会造成IO抖动,如果是彻底挂掉还好(配置的心跳超时时间在7s左右,IO抖动时间也基本如此),就怕心跳还偶尔半死不活,这种情况就会一直抖动,我们也尝试从代码逻辑层面做了一些优化(遇到半死不活就自杀),不过发现其他策略效果还不错,并且这种问题发生的概率比较低(也有规避手段),就没有打开相关配置(主要怕大面积误杀)
- ceph代码实现问题:pg锁问题,peering流程问题,monitor负载问题等等
- 运维操作流程问题:如果不能自动化运维,为了不造成抖动就要进行各种微调,导致运维耗时非常长,自动化才能解决此类问题
- ceph底层性能问题:filestore存储引擎在大量删除文件和写入大量小文件之后的性能问题等等,因此后续我们上线的cephfs和nos ceph-ec集群全部都切换到了bluestore,也取得了良好的效果(当然也顶住了数据可靠性的风险,其实是偷偷上的,当时的团队负责人担心bluestore数据可靠性有问题不同意使用,在这一点上我们ceph团队的小伙伴还是非常给力的,做到了不给后来人挖坑)。
- 部署优化:把monitor节点使用的hdd盘换成更高性能的ssd,并把大规模集群的混部的monitor服务独立到单独的服务器上,提升monitor单点性能,减少心跳上报、多副本之间peering过程中的排队现象,缩短异常场景或者运维操作过程中IO中断时间
- 代码优化:peering流程优化,减少不必要的流程,极大降低了流程耗时
- 日志和命令行工具优化:新增日志和命令行查询工具,精确定位抖动原因和所在磁盘,便于快速恢复和事后分析
- 工具迭代优化:自动化运维工具迭代式优化,根据日志发现抖动问题是运维工具不完善造成的之后,持续微调工具操作流程细节(有人可能会问为啥不线下测试好再上线,如果线下小规模环境能复现,问题也就不那么难解决了),直到趋于完美
- 引擎性能优化:我们基于filestore也做了很多的性能改进尝试,配置调优都已经上线,也取得了一些效果,但代码修改和缓存盘方案受限于文件系统性能限制,以及线上集群升级困难(数据已经在那里了,动不了),最终并没有落地
- 监控告警完善:这个比较容易理解,我们基于日志和命令行工具,配合专用打桩机,对每个存储池、每台服务器、每块盘,都在哨兵上做了很多新的监控项,这些监控项配合哨兵告警能帮助我们第一时间发现抖动问题,及时进行处理,从此以后,再也没有出现抖动超过几分钟还没找到问题原因的情况,基本做到了抖动发生的几秒钟内就能发现原因
挑战2:超百万行ceph代码的掌控问题
- 从遇到的问题入手,把问题涉及到的代码流程吃透,并尽可能扩散覆盖到更多的流程
- 从核心流程入手,把核心IO流程的代码吃透,遇到相关问题时可以快速深入问题细节,找到解决方案或者规避手段
- 从版本社区已知bug入手,定期去社区bug tracker平台分析我们使用的版本新报告的bug,并深入分析bug产生的场景和相关代码流程,合入补丁时做到心中有数、举一反三
- 代码责任田,每个人负责一块,比如monitor、mds、mgr、osd等
- 团队内知识分享,每次解决的问题或bug都有详细的分析报告,并组织团队内部讨论分享,并通过学习分享这块考核进行牵引
项目成果
- 参与Ceph成本优化项目,2020年成本下降到2018年的1/6
- 参与Ceph块存储优化项目,通过规范运维标准化及配套工具,优化集群监控报警,保障了近xx个块存储集群x百台服务器xPB业务数据,近4年未出现较大故障,基本没有SLA损失,云盘抖动情况显著改善,同时节省SA半个人力
- 参与并主导cephfs容器场景产品化项目,填补了k8s RWX PVC存储的空白,解决了传媒,严选,云音乐等部门共享文件存储的痛点,集群数量达到xx,存储机x百台,业务数据达到xxPB+
总结复盘
Curve项目
背景和必要性
功能类别
|
功能项
|
juicefs
|
cephfs
|
cubefs
|
curvefs
|
备注
|
基础功能(主要对标)
|
POSIX 兼容
|
是
|
是
|
是
|
是
|
|
CSI插件
|
是
|
是
|
是
|
否*
|
curvefs csi插件开发中
|
|
元数据管理
|
第三方组件
|
是
|
是
|
是
|
||
数据一致性
|
close-to-open
|
强一致
|
close-to-open
|
close-to-open*
|
JuiceFS 确保了数据的高可靠性,在文件关闭时会将其同步上传到对象存储。curve一致性目标处在规划中
|
|
S3兼容引擎
|
是
|
自有S3组件
|
自有S3组件
|
是
|
juicefs为各家对象存储厂商提供了独立的驱动层(用的是各家的专有SDK,curve用的是aws s3的sdk对接所有厂商)
|
|
客户端缓存
|
内存、硬盘
|
无客户端缓存
|
3.0版本支持内存、硬盘缓存、3副本引擎
|
内存、硬盘、3副本引擎
|
juicefs商业版本支持单副本的读缓存
|
|
自有存储引擎
|
无
|
有
|
有
|
有
|
||
多挂载
|
是
|
是
|
是
|
是
|
||
目录配额
|
是*
|
是
|
是*
|
否*
|
juicefs、cubefs支持volume级配额,curvefs规划支持配额功能
|
|
多文件系统
|
是
|
是*
|
是
|
是
|
cephfs多文件系统支持不完善,目前以单文件系统用法为主
|
|
开发语言
|
Go
|
C++
|
Go
|
C++
|
||
认证、权限管理、多租户
|
否*
|
是
|
是
|
否*
|
curvefs规划支持,juicefs没有看到相关文档(操作过程中也没有看到类似参数)
|
|
扩展功能
|
内置stat工具
|
是
|
是
|
否?
|
否
|
|
文件锁
|
是
|
是
|
否?
|
否*
|
curvefs规划支持
|
|
HDFS兼容引擎
|
是
|
否
|
否
|
否
|
curvefs是否要支持待定
|
|
NFS协议
|
是
|
插件支持
|
否
|
否
|
curvefs规划支持
|
|
S3协议
|
是
|
是
|
是
|
否
|
curvefs规划支持,优先级低
|
|
HDFS协议
|
是
|
否
|
否
|
否
|
curvefs是否要支持待定
|
|
CIFS协议
|
是
|
插件支持
|
否
|
否
|
curvefs是否要支持待定
|
|
ceph rados引擎
|
是
|
是
|
否
|
否
|
curvefs规划支持,优先级低
|
|
fsck数据校验
|
是
|
是
|
否?
|
否
|
curvefs规划支持
|
|
对象分片合并
|
是
|
否
|
否
|
是
|
同一个文件反复随机写入的碎片整理
|
|
垃圾对象清理
|
是
|
否
|
否
|
否
|
需要调研与分片合并的区别(目前看是游离分片数据的清理功能)
|
|
内置benchmark工具
|
是
|
是
|
否?
|
否
|
||
多桶写入
|
是
|
/
|
/
|
否*
|
curvefs规划支持同一集群配置多个后端存储桶
|
|
元数据备份恢复
|
是
|
是
|
是?
|
否*
|
curvefs规划支持
|
|
高级特性
|
主动目录缓存
|
是
|
否
|
否
|
否*
|
juicefs为warmup命令,curvefs规划支持
|
数据加密(传输、静态)
|
是
|
是?
|
否
|
否
|
curvefs是否要支持待定
|
|
数据压缩
|
是
|
否?
|
否
|
否
|
curvefs是否要支持待定
|
|
跨集群数据同步
|
是
|
否
|
否
|
否
|
是指将阿里云oss(或其他对象存储厂商)某个桶中的数据同步到aws s3(或其他对象存储厂商)的某个桶,与文件系统本身的关系不大,类似rclone等第三方数据同步工具
|
|
快照
|
否
|
是
|
否?
|
否*
|
curvefs规划支持快照功能
|
|
回收站
|
是
|
否
|
否?
|
否*
|
curvefs规划支持回收站功能,https://juicefs.com/docs/zh/community/security/trash
|
|
内核态客户端
|
否
|
是
|
否
|
否*
|
curvefs是否要支持待定,https://juicefs.com/docs/zh/community/metadata_dump_load , juicefs支持自动定期备份
|
|
冷热数据分层
|
否
|
是
|
是
|
否*
|
curvefs规划支持,ceph cache tire更适合对象存储场景,cubefs 3.0版本支持了3副本和ec的分层存储
|
|
数据生命周期管理
|
否
|
否
|
否
|
否*
|
curvefs规划支持
|
项目挑战
挑战1:技术架构和应用场景
- 高性能
- 高性价比
- 支持公有云部署
- 支持混合云部署
- 支持冷热数据分层存储及数据生命周期管理
- 支持多级缓存
- 完整的POSIX兼容性
挑战2:如何保证Curve具备高性能优势
- 全链路瓶颈梳理
- 大文件顺序读写性能优化
- raft相关优化
- 高性能硬件适配
- 元数据性能优化
- 数据面性能优化
- FUSE优化
- 多级缓存
挑战3:如何提升Curve的易用性
- ansible本身的安装就比较复杂,依赖比较多的python库,而且我们还对ansbile的版本有依赖,导致用户安装指定版本ansible遇到了很多问题
- ansible部署方式是通过二进制包方式安装curve,无法适配到不同的操作系统版本(依赖的glibc等基础库可能不兼容),要么在各个发行版上编译不同的二进制或者安装包,并且需要进行非常复杂的测试验证,工作量巨大
- 安装过程易出错,不同用户环境下的Curve依赖没有办法全面检查到,我们内部使用的问题比较少,因为我们的操作系统和相关配置等都非常的标准化,外部用户则有非常大的差异性;并且出错之后定位分析困难,需要频繁的与用户进行沟通等待用户反馈,解决问题的效率太低
- 扩容、升级等高级运维操作步骤繁琐易出错,不支持周边组件如tgt、pfs等的部署
功能\工具
|
ansible
|
CurveAdm
|
TiUP
|
CephAdm
|
一键安装
|
Y(依赖容易出问题)
|
Y
|
Y
|
Y
|
一键部署
|
N(各个组件单独部署)
|
Y
|
Y
|
N(步骤稍多)
|
playground
|
N
|
Y
|
Y
|
N
|
多集群管理
|
N
|
Y
|
Y
|
N
|
一键扩容
|
N(步骤稍多)
|
Y
|
Y
|
N(步骤稍多)
|
一键升级
|
N(步骤稍多)
|
Y
|
Y
|
Y
|
一键停服
|
N
|
Y
|
Y
|
N
|
一键清理
|
N
|
Y
|
Y
|
N
|
部署环境预检
|
Y(少量预检项)
|
Y
|
Y
|
N
|
操作审计
|
N
|
Y
|
N
|
N
|
周边组件部署
|
N
|
Y
|
/
|
N
|
一键日志上报
|
N
|
Y
|
Y
|
N
|
集群状态统计上报
|
N
|
Y
|
Y
|
N
|
N
|
Y
|
N?
|
N
|
项目成果
- 推动Curve块存储业务规模发展,2年内集团内部存储数据容量从不到xxxTB增加到超xxPB,同时发展外部用户数家;近2年未发生集群级故障,性能和稳定性相比Ceph云盘有了极大提升了
- 带领团队完成了Curve文件存储的规划、设计及开发(代码量13w行,是所有curve小伙伴的结晶),数据和元数据相关性能均达到开源存储项目的领先水平,目前正在推广落地中,已有2个业务使用
- Curve开源社区建设方面,推动Curve加入CNCF基金会sandbox项目、信创认证、PG数据库社区共建等社区建设工作,目前已有数位外部贡献者,以及数家外部用户,测试中用户10+,项目star数1.5k,社区用户群人数1k
总结复盘
NOS项目
背景和必要性
- 员工长期保持激情:架构、盈利、成本综合考虑,单纯的考虑某一方面很难长久留存员工(注:这条建议很好,但也比较有挑战;比如架构升级一般都是由业务需求来推动的,盈利和成本这块可以内驱,但如果增量太少,比如nos,也不好做)
- NOS历史包袱比较重,建议要从长期考虑进行整体架构优化和调整,只关注短期目标很难把业务做稳做实(注:短期主要是指新的存储技术,新的业务拓展,成本优化等,这块已经很多模块处于停止维护状态,但其实还是会有新的模块加进来,后续是不是会变成历史包袱,很难说,只能尽量避免,代码和架构总有腐化的时候,不可能扛几年甚至十几年)
- 所做产品的价值体现不出来,考评吃亏(注:主要是指业务规模上不去,但又很难拓展,这条说的比较实际,我本身也有这种困扰;内部客户量上不来,虽然说可以拓展外部客户,但从底层平台来说,没有完善的产品,确实难走商业化的路子,基础设施这块应该都有类似的问题)
项目挑战
挑战1:EC存储引擎小文件空间利用率问题
挑战2:冷归档存储业务需求和小规模成本问题
挑战3:业务拓展问题
- 单位存储成本
- 服务稳定性
- 数据可靠性
项目成果
- 通过技术架构升级推动NOS内部降本,给业务的报价相比xx云OSS 9折甚至更低(大客户报价连续两年打折,非常好的满足了业务方降本诉求)
- 开发上线1.2副本低频存储(xxPB)及冷归档存储(xxPB),以及新上线的自研归档存储,完善了NOS存储产品线,非标准存储占比达60%,为业务方节省大量成本
- 持续进行业务拓展(xx、xx、xx等),年营收增长达30%以上;近2年存储容量实现翻番达到xxPB,并拓展了商业化客户
- 通过主动为业务降本及共建等手段,持续提升业务方满意度,上半年更创新高;近2年SLA均超过99.5%
- 解决了团队内部信心不足、人心涣散问题,团队凝聚力和士气显著提升
- 低频、归档存储演进过程中的数据可靠性保障问题,我们转存了超过60%的数据到低频或归档存储引擎,同时我们还在底层把大量数据从filestore集群转移到bluestore集群,以及从1.5副本转移到1.2副本甚至更低冗余度的集群,这一系列过程中,我们承担了极大的数据可靠性风险(也在转存到各个阶段做了大量的校验程序),但是我们做到了转存xxPB数据的100%可靠性,并且做到了对业务无感知,没有造成任何性能和故障问题
- 通过cdn进行直传优化,节省了大量的边缘节点成本(之前是aws海外虚拟机,或者国内idc租赁服务器来搭建直传边缘加速节点)
- 我们还在公有云和私有云环境完成了网宿CDN到融合CDN的数千个域名的平稳迁移工作,也是为了给业务节省成本,改造了CDN管控服务,并且修复了多个CDN厂商间的兼容性问题
- 我们调整了计费策略,让业务可以享受更多折扣,为此我们多次改造统计计费服务,承担了大量的改造工作量
- 还有我们正在进行的ddb改造tidb工作,由于ddb存储的对象数量已经超过千亿,要扩容已经非常困难并且会导致空间严重浪费
- 老旧腐化存储引擎的维护工作,也非常有挑战,比如sdfs,已经是10年前的软件,nefs也有5年历史,目前NOS日增数据近百TB,都是靠这两个引擎承担,并且我们为了节约成本又不适合进行扩容,因此这两个引擎的IO压力非常大,同时机器也比较老旧,各种异常都容易触发,而这两个引擎已经没有非常专业的人可以维护,为此我们也做了大量工作,来熟悉并掌控他们,也解决了多个严重问题
- 为了提升xx业务数据转存到NOS的速度,我们对转存服务也做了大量性能优化工作,从最初的媒体xTB,到xxTB,提升了10倍;为了提升xx业务转存NOS低频存储数据到冷归档存储的速度,我们也对转存服务再次进行了优化,从每天xxTB提升到xxxTB,速度提升了4倍,数据转存时间从半年左右降低到了1.5个月,为业务节约了大量成本
- 富媒体处理业务私有化部署改造,为云音乐海外云上私有化部署提供支持,节约业务开发成本,我们也有比较大的工作量
- 与视频云共建视频处理服务,简化业务方使用逻辑的同时还可以为业务节省成本(价格更低)
- 我们也做了很多安全增强工作,来提升业务使用nos的安全性
总结复盘
- 原有的两种3副本引擎的下线和替换成EC引擎的工作,比预期的进展慢,这两种腐化的存储引擎导致我们出现了几次线上故障;另外这也涉及到过保服务器的利旧和成本问题,如果一次性下线,成本太高,但又不能利旧给EC引擎用,所以目前我们的策略是开放大文件EC直接写入后对老的3副本集群逐步缩容
- 计费系统的演进跟不上我们业务形态的发展,导致很多计费需要运营同学手工出帐解决
- 以及对外商业化探索,可以适当早一点发起,至少可以和已有的商业化客户进行一些接触,多了解外面客户的需求
- 虽然我们这两年已经清理或重构了不少模块,但还有更多的腐化模块,需要厘清并尽快处理下线或者重构(如ddb、httpdns、cdn、跨分区同步、s3 sdk兼容性、事件通知等)
- NOS性能问题与公有云还有比较大的差距(主要是时延),但好在用户不太敏感,尤其是对接CDN的资源,回源比例非常低,时延问题基本没有影响,所以目前也没有排在很高的优先级来解决,但问题已经确认是腐化的3副本存储引擎性能不足导致的
专业贡献
- 2020年10.24创新奖:Curve项目获得最佳技术开源贡献奖【自研开源】,这不是我的功劳,是Curve团队的
- Curve:信创认证,信通院OSCAR尖峰开源项目及开源社区,可信开源项目认证
- Curve:捐献给CNCF基金会sandbox项目
- 专利:NOS 2篇、Curve一篇
- NOS:2022H1 云计算降本增效奖
学习分享
- Ceph:云音乐goblin平台共建项目infoq文章一篇
- Curve:杭研公众号、Curve自有公众号文章数篇,ITPUB专访一篇,
- kms高质量文章数篇(一篇上首页推荐/月度最佳),NEXT训练营高质量文章数篇(结营仪式上受到专项表彰)
- 实践者论坛分享一次《Ceph云盘IO抖动原因及优化措施》,课程一项《分布式存储介绍(curve&ceph)》
- 2022.08.25:参加阿里云金融创新峰会,演讲主题《网易数帆开源社区建设实践 — 以Curve社区为例》
- 团队同学还有很多文章、直播、外部会议等等分享,不是我去讲的就不算在内了,团队外部会议分享这块比较随意,谁有空或者谁合适就谁去参加,毕竟每个同学都要有各自的发展空间
未来发展计划
- 把Curve项目做好
- 对于文件存储,今年和明年上半年先把AI场景和云上场景的效果做出来,拿到一批用户案例;之后再拓展更多场景
- 对于块存储,今年先把高性能硬件(NVME/RDMA)适配起来,明年上半年把Curve软件层的性能优化好,争取性能可以对标到阿里云ESSD云盘,保底也要做到超过阿里云高效云盘(主要是时延),支撑好云原生数据库应用场景
- 要在40岁之前把Curve项目带进CNCF孵化项目,目前来看,这也是一件非常有挑战的事情,需要把Curve开源社区发展的非常好,并且要有相当多的用户案例
- NOS项目要保持盈利
- 内部业务,要继续拓展增量并保持存量,通过软硬件优化来降低成本并最终给业务降价,做到薄利多销来对抗公有云厂商的逐年降价,希望能在40岁之前让NOS存储的数据量再翻一番,这个事情不确定性比较大,毕竟目前可以拓展的业务已经非常少,单靠业务数据的自然增长是完全没希望的,另外就是软硬件优化的方向和思路还不太清晰,还需要进一步深入调研,可能可以考虑的方向是数据压缩。
- 外部商业化,今年开始尝试,明后两年能拿下2~3单合同
- Ceph项目还是维护好,别出问题就行
- 管理岗方向,这个目前在做一些团队管理工作,但是就像我上一篇文章说的,还没有完整的方法论,套路不清晰,时不时要修正,这个方向比较有挑战,主要是不知道怎么成长,是不是各位大boss有什么经验可以传授一下?还是说都是一步一步慢慢总结改进走出来的?这个方向可能确实没有速成途径吧
- 商业化架构师方向,我个人感觉这个方向挺不错的,就是得能忽悠、会忽悠客户,还得能写一手好材料(word、ppt要玩的很溜,各种高大上的专业名词要搞得很透,各种新鲜技术都要略懂能跟客户聊得很嗨,各种人情世故、客情关系要做的很到位),也非常有挑战,这个方向做好了个人综合素质会上一个台阶
文章预告
- 序 — ps. 希望了解NOS的大佬能帮忙做序
- NOS介绍
- NOS历史
- NOS现状
- NOS未来
70. 爬楼梯
题目链接:https://leetcode.cn/problems/climbing-stairs/
这道题不会做,看官方题解才明白。
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 30 31 32 33 34 35 36 37 38 |
class Solution { public: /* 记忆递归法 unordered_map<int, int> mymap; int climbStairs(int n) { if (n < 1) return 0; if (n == 1) return 1; if (n == 2) return 2; if (mymap.count(n) > 0) { return mymap[n]; } int total = climbStairs(n - 1) + climbStairs(n - 2); mymap[n] = total; return total; } */ // 动态规划法 int climbStairs(int n) { int a = 1, b = 2; int total = 0; if (n <= 0) { return 0; } else if (n == 1) { return a; } else if (n == 2) { return b; } for (int i = 3; i <= n; i++) { total = a + b; a = b; b = total; } return total; } }; |
160. 相交链表
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/
下面两种方法都想到了,官方题解的双指针法想不到。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /* 暴力解法 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode* hb = headB; while (headA) { headB = hb; while (headB) { if (headB == headA) { return headA; } headB = headB->next; } headA = headA->next; } return NULL; } */ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { unordered_set<ListNode*> s; while (headA) { s.insert(headA); headA = headA->next; } while (headB) { if (s.count(headB) > 0) { return headB; } headB = headB->next; } return NULL; } }; |
146. LRU 缓存
题目链接:https://leetcode.cn/problems/lru-cache/
这道题超出时间限制了,原因应该是时间复杂度是O(n)不是O(1),用list保存缓存的key列表,调换list里面元素的顺序比较慢。
等我看官方题解更新吧。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
// 正确版本 class DListNode { public: DListNode* prev; DListNode* next; int _key; int _value; DListNode(): _key(0), _value(0), prev(nullptr), next(nullptr) {} DListNode(int key, int value): _key(key), _value(value), prev(nullptr), next(nullptr) {} }; class LRUCache { public: int cap; int size; unordered_map<int, DListNode*> cache; DListNode* head; DListNode* tail; LRUCache(int capacity) { cap = capacity; head = new DListNode(); tail = new DListNode(); head->next = tail; tail->prev = head; size = 0; } int get(int key) { // hint if (cache.count(key) > 0) { moveToHead(cache[key]); return cache[key]->_value; } // miss return -1; } void put(int key, int value) { // update if (cache.count(key) > 0) { DListNode* node = cache[key]; node->_value = value; moveToHead(node); return; } // insert ++size; if (size > cap) { int key = tail->prev->_key; removeNode(cache[key]); cache.erase(key); --size; } DListNode* node = new DListNode(key, value); cache[key] = node; addToHead(node); } void removeNode(DListNode* node) { node->prev->next = node->next; node->next->prev = node->prev; } void addToHead(DListNode* node) { node->next = head->next; head->next->prev = node; node->prev = head; head->next = node; } void moveToHead(DListNode* node) { removeNode(node); addToHead(node); } }; /** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */ |
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 30 31 32 33 34 35 36 37 38 39 40 |
// 时间复杂度过高版本 class LRUCache { public: int cap; unordered_map<int, int> cache; list<int> l; LRUCache(int capacity) { cap = capacity; } int get(int key) { if (cache.count(key) > 0) { l.remove(key); l.push_front(key); return cache[key]; } return -1; } void put(int key, int value) { l.remove(key); l.push_front(key); while (l.size() > cap) { if (cache.count(key) == 0) { cache.erase(l.back()); } l.pop_back(); } cache[key] = value; } }; /** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */ |
我是如何带团队的
这篇文章荣获网易集团内部知识分享平台《2022年度十佳作者》及《2022年度十大人气文章》。
这篇文章怎么来的
近期收到HRBP通知,做了一次一线管理者述职,从接手存储团队以来不知不觉已经过去2年,这两年有不少感想,从去年初就在想(刚看了一眼popo待办,这项任务已逾期546天,现在总算可以标记为已完成了,尴尬~),能否整理出一篇文章,详细的讲讲自己是怎么带团队的,有哪些方式方法是需要纠偏的,有哪些是可以改进的,又有哪些是可以继续保持并加强的。这些东西如果我自己不整理分享出来,就很难被外人获知,也就无从给出辅导反馈,自己也就没有改进的机会。因此借这个机会,把述职PPT里面没有发散出来的东西,整理出来,算是一种总结沉淀,也算是一种同事或者上下级之间的互相交流。针对文章中的各种管理方式、问题或者案例,欢迎各位同事领导找我沟通指导。
我的工作经历
介绍我的工作经历,是为了让大家对我的管理理念或者思路有更清晰的了解,人们总是习惯按照自己的工作方式方法或者质量标准为尺度去要求其他人,并且过往的工作经验能很大程度上左右自己对某件事或者某项工作的看法。比如有些人认为一个功能开发工作量20天搞定,而另外一个人则认为至少1个月,那这两个人如果技术能力和工作效率差不多的话,工作量的偏差就在于代码开发之外的工作量的评估了。作为一个主管,你更认可哪个人的评估结果?这在很大程度上需要依靠主管自己的工作经验。主管之前做事考虑全面、细致、测试充分、代码质量自我要求高,工作性格偏严谨,那极有可能他会认为至少要1个月,而不是20天撸完代码就发布上线。
我是10年参加工作,前两年在华为工作,有比较严格的开发流程和质量规范,自己只要按部就班的遵守就ok了。但12年入职网易之后,流程和规范就没有公司级的标准了,通常都是项目或者部门自己的规范,这是互联网行业和传统软件行业的差异,这里不做评价。在网易做了2~3年开发之后,也开始做leader带小团队,那时候团队的小伙伴们,绝大部分都很给力,几乎不用怎么操心,定好目标之后各司其职,发现问题自己修掉就行了,开源社区时不时的push几个pr过去,还能收获不少成就感。
再后来就遇到了一些不那么给力的小伙伴,给人的感觉就是带不动,从不用带到带不动,给我的落差感很大,经常想不明白为啥会不知道工作怎么做(技术能力是一方面,工作方式是另一方面)。也有另外一些比较给力的小伙伴,一部分是本来就知道怎么做工作,一部分是看组里大佬怎么工作,也都不怎么费心。遇到不给力的小伙伴,感觉自己也比较受打击,经常怀疑自己带人到方法不对,说不定换个leader人家就能变得很给力,绩效可以好的飞起。
在后来在网易工作了5年,最开始身边的那批小伙伴们也都慢慢的分开了,项目也基本进入维护状态了,加上前同事一直邀请去他那边小公司做同样的事情,就出去做了一整年。这一年带了小公司10几个研发,最多的时候接近20人,从最开始的团队没有任何流程,到稍微规范,我也花了一些心思,主要是在小公司里流程依赖的工具、平台都要自己动手弄。这里的小伙伴们,虽说都不是什么名牌大学毕业的本硕生(甚至有一个前端同学是高中毕业,这里没有任何歧视前端同学的意思),但也都能在指导下做出来想要的东西,可能大家知道自己学校不行,能找到一份程序员的工作实属不易,也想趁刚毕业多学点技术,一个个的干劲很足,自己也有一些经验可以给他们一点指导,所以并没有感觉带人吃力,工作氛围也比较轻松愉快。虽说后来2年这家小公司的母公司收缩业务,杭州这边分公司基本裁撤了,但是之前一起工作的那群年轻小伙伴们,也都有了新的不错的工作,这也是我一年做到的自认为稍微有点成就感的事情之一。
再后来就又回到网易工作,先做了一年多的开发,之后接手团队。团队有3个小组或项目,状态各有不同,一个纯维护状态基本没有开发量(用开源)、一个10年的老项目还在持续更新有一定的开发量(半自研半用开源)、一个近几年的新项目还在发展阶段有很大的开发量(做开源项目)。
人才招聘
招什么样的小伙伴
通过这10多年工作中的观察体会,我认为一个高绩效或者说我愿意与他共事的小伙伴,应该具备以下几个特质:
- 有能力:光有想法是不行的,要自己有能力做出来或者设计出来,空口说白话谁都会,show me your code才是王道。
- 有动力:首先我声明自己就是一个俗人&穷人,所以看待身边的人也是按照我这个视角来看的。是什么让你出来做码农这种工作?是什么让你在职场拼命往上爬?是缺钱还是想赚更多钱?我共事过的小伙伴中也有不少富裕家庭出来的,但我经常想如果真正富裕到一定程度,应该不会出来做码农吧?我还是建议这类小伙伴最好不要出来跟我们卷了,回家接手家族产业才是王道。当然不排除有小伙伴是为了用代码改变世界才出来做这行,但是很可惜我没遇到过。
- 有意愿:这个是说,你有能力做一件事情,但是你得愿意动手才能落地,有些小伙伴偶尔会跟我说这块功能我不感兴趣,不想做。如果他真的不想做,那我总不能强迫他去做,强扭的瓜不甜,即使委屈做了也肯定不能追求卓越,好在这种情况不太多见。
- 有想法:有的小伙伴有技术能力做一个功能或者小的项目,也有很强烈的意愿和动力,但是在整体思路上和具体实现的方案上,没有清晰的想法,就是设计架构能力不太行,或者对产品体验方面没有想法,做出来的东西让用户用起来总是感觉很别扭不顺手。而有想法的小伙伴则能做到自己就是用户,深刻理解用户或者业务需求和使用场景,做出来的东西用户用着特别顺手,就跟自己开发的一样。说到这个,怎么才能产生好的想法,我理解一方面要有产品思维,一方面要和用户在一起。
后来网易发布了自己的人才观:
- 聪明
- 有活力
- 自驱
- 有Sense
我理解正好与上面那几条不谋而合。
作为主管,想招进团队的人肯定是自己愿意与他长期共事的人,上面已经解释过这方面的标准。但是,我不得不说但是,面试过程中真的很难把这几个方面的东西都考察到,培训过的SBO面试法,当然是一种很好的手段,但是我认为仍然不能让你避开所有的坑,以我的经验来说,身边优秀小伙伴推荐的他愿意共事的人才更靠谱。你 — 你欣赏的小伙伴A — A欣赏的小伙伴B,那么你如果把B招进来,十有八九是不会让你失望的。
招聘最大的困难是什么?
撒不开网,捞不到合适的候选人。
不要觉得大公司候选人多,小公司也有一堆简历,因为能进大厂的都是比较好的学校毕业的,但是你想想985毕业的比例就知道,更多的码农还是普通学校毕业的。
简历多有用吗?其实没多大用,反而增加了筛选和面试的负担。少而精准才是最关键的。怎么做到呢?我也没有好的思路,但是凭直觉最理想的就是点对点直接挖人,认识的小伙伴也都分散到各个公司,想找总是可以找到,但成本太高,开不起价。
最痛苦的是什么?
预算不足。
有一种是简历筛选的时候就知道候选人定级应该超出预算,这种还不是最痛苦的。另一种是面试都ok了,但是候选人薪资要求比预期高,这种就很难达成一致,原因可以参考我上面说的“有动力”的解释。遇到这种情况怎么办?我理解可以看两个情况:如果是薪资要求差距不大,还是可以通过尝试沟通项目的发展前景和从事的工作的前沿性、挑战性,说白了就是画画饼,让候选人觉得,即使我现在进去这个项目赚钱不如预期,但是一旦我做好了这个项目,以后就能赚更多的钱。第二种如果是差距很大,直接over得了,别浪费两方时间。
换位思考下,如果我出去找工作,那么我只考虑钱,也分两种情况:1是这份新工作让我立刻可以赚到钱(给到的薪资比较满意);2是这个新工作可以让我以后赚更多的钱(给到的薪资不太满意但还不至于感觉到被鄙视,但是我能通过这份工作变成大佬)。再次强调下:我是个俗人&穷人。
最惨的是什么?
候选人看不上你的团队或者项目或者公司。
这种情况在小公司特别常见,大厂也偶有发生。被候选人看不上怎么办?我也没啥好办法,每个人都有自己的发展规划和看项目的视角,候选人就像投资人一样,觉得你这个项目没前途,不会成,那你要么坚持自己的方向说不定哪天就能一飞冲天让他们后悔莫及,要么重新审视自己的项目对现在的方向进行修正。谁都有看走眼的时候,你只能找那些志同道合的小伙伴,否则不认可你项目的人才加入进来并不一定是好事。
boss在述职现场的提问:为什么你没有招到大佬级的人才?
我现场的回答:
- HC的级别不到大佬级
- 我个人的大佬资源也不够,搭不上线
回来后,我又想了一段时间这个问题,我认为boss的问题可能还可以尝试从另外一个角度理解:为什么你没有培养出来大佬级的人才?
这个问题我认为对我来说更有挑战,为什么我没有培养出来大佬级的人才?甚至可以更直接一点:为什么我自己没有成为大佬级的人才?
如果我自己都做不到,怎么能要求或者期望小伙伴们做到?培养人才、构建人才梯队,确实是一个管理者的本职工作之一。
要回答这个问题,理由或者说借口总是能找到,但现在不是boss在问我,是我自己在扪心自问,怎么回答自己?我认为要培养出来大佬级的人才,天时地利人和都要具备。
- 天时:风口的项目
- 地利:老板的支持,项目的需要,公司的背书
- 人和:你团队里有一个具备大佬潜质的小伙伴,或者你自己就是这个人
我见过或者听说过一些华为的大佬,也了解网易一些大佬的开挂经历,大部分都是有大佬潜质的人才,在公司或者项目需要立一个业界大佬flag的时候,这些人主动或者被动的站出来并且顶上去了,经过一段时间的痛苦期之后,大佬就练成了。你可曾见过或者听过,一个长期维护阶段的项目出过大佬?你又可曾听过一个生命周期快结束的项目出过大佬?以我略微熟悉的云计算/虚拟化相关开源项目来说,想要成为社区的core developer或者甚至maintainer,没有长期稳定的公司项目和需求做支撑,你连需求都找不到,只能做一些修修补补的工作,怎么能进入社区核心开发团队?
最后回答下我自己为什么没有成为大佬,我认为主要是我离大佬潜质还有一点距离,项目的需求也不太强烈。
案例
其实述职的时候列了几个案例,但是感觉案例也都是项目里的个别情况,时间长了总能招到几个还不错的小伙伴,所以这里就不列了。但是最难的是招到的每个小伙伴都是非常优秀的。更何况也不是每年都有招聘指标。
绩效管理
我自己做开发时的绩效
工作的前几年,除了第一年刚入职绩效不是A,前面几年都是A。为啥我能拿A?我自认为有如下几个原因:
- 对工作有敬畏心:学校一般,能进大厂不容易,不要因为不能胜任工作被开除了,有危机感
- 对公司有感激心:公司给发工资,相比其他小公司薪资还可以,不能白拿
- 对赚钱有上进心:用比较流行的话来说,小镇做题者(不能称为家,因为做题也不十分拿手),家穷人丑,只能拼命赚钱,在大厂里拿到高绩效才能比别人赚得多(卷起来)
- 对技术有钻研心:学好技术以后才能赚更多钱
有了这些基础,做工作的时候只要超出leader预期,就能拿到好绩效。超出预期有很多种情况:
- 提前完成任务
- 高质量完成任务
- 积极主动,不要让leader催,而是催leader
- 帮leader分担压力
- 帮团队解决难题
我相信如果你能做到以上几种情况的1到3个,绩效不会差(除非有人比你还卷)。
我带团队时的绩效
众所周知,带领高速发展的业务,容易拿到高绩效,而维护状态的业务则很难。能高速发展一般有两种情况:一是公司内部或者外部环境有强需求、大痛点,没你不行;二是你带领团队克服艰难险阻把本来发展一般的业务搞上去了,发展起来了。当然肯定是第二种管理者更厉害,第一种有一点运气成分,类似站在了风口,大部分人都能起飞。
具体到我自己,两种情况应该算是都经历过,但是很遗憾,第二种情况我还没能做到最好。所以绩效一直一般,我的压力有点大,并不是怕boss开掉,而是怕项目被我带到沟里,所以我经常在想,换一个人来带这个项目会不会比我做的更好?我有没有尽力而为?说实话第一个问题我自己没办法回答,我相信肯定有很多人会比我做的更好,我只能回答第二个问题,自己尽力了就ok,要不要换掉我交给boss就好。
怎么搞好团队绩效?
怎么让团队整体绩效保持较高水平?怎么提升团队里个人绩效?怎么沟通绩效?怎么做绩效辅导?这些都是同一类问题。
通常我都是以自己的经验来要求团队里的小伙伴做一下超出leader预期的工作,如果每个人都能超预期,那团队绩效肯定也会远超预期。但是据我观察,有一些小伙伴是很难做到像我刚毕业那几年做开发时一样卷,可能不像我一样家穷人丑吧,安安分分按部就班做一份工作有一份工资做零花钱就ok。
这里我有一个例子,虽然不是我们这行,但也非常有参考价值,我一个高中同学,师范大学毕业后去深圳一所普通公立高中当班主任,有一个学生经常翘课,打电话给家长忙着挣钱没时间管,找学生谈话,问他天天翘课怎么考大学?被说烦了,就说,我家在深圳有多少套房,几家工厂,不考大学也一样活得很好。后来我同学干了3年就改行不当老师了。
举这个例子只是想说,不是每个人都差钱,每个人都追求是不一样的,所以我一般跟小伙伴沟通的时候,也会根据他们家庭情况来区别交流,不差钱的小伙伴,尽量用技术成就感来聊,差钱的那直接聊高绩效就能升职加薪。但是高绩效的要求还是要一视同仁讲讲清楚的,就是上面我提到的5点超预期的方向。
另外,不差钱的小伙伴很多也做得很好,还是有很多有追求有理想的小伙伴的,公司价值观“热爱”可以解释这种人。在这方面每个人都应该向我们丁老板学习,绝对的不差钱,绝对的有追求,绝对的“热爱”。
激励不动怎么办?
也有实在激励不动的,躺平或者半躺平的小伙伴,怎么办?没办法,团队还要继续发展前进,也不是养老的地方,包括我自己也做好随时被淘汰的准备。361的1就是为这种情况准备的。我相信如果一个团队没有这种人,那团队绩效就不会差,我也一定会据理力争尽力保证没有这个1的存在。如果团队绩效都没做好,我怎么好意思厚着脸皮去争取?我自己都要引咎辞职了吧。
怎么绩效沟通?
绩效沟通有时候挺难,有时候也不难,只要你别给小伙伴惊吓就都还好,提前打好预防针,把沟通辅导工作做在平时。哪里不行要提前说,给人机会改进。
当然也不排除有些小伙伴就是觉得自己做的很到位了,或者有些绩效指标的标准确实也有一点模糊,按指标来说他自认为达到4分或者5分,你为啥给3分。这种情况一般我是团队内横向比较,把好的标杆挑出来,列清楚理由和建议。如果还是沟通不来,我通常会跟我的主管和HRBP交流学习,看看他们的建议,当然最关键的是你的考核结果要有依据而不是根据个人喜好打分。做不到每个人都心服口服,也要做到公平公正。
最后,同样的,案例也不放了。
团队氛围
什么叫团队氛围?
团队小伙伴们整天一起吃吃喝喝、吹水打屁、欢声笑语,算不算氛围好?每个人都愁眉苦脸、广投简历、随时跑路,肯定不是好的团队氛围。一个正常的团队,应该是开发时小心翼翼、测试时吹毛求疵、上线时严肃认真、业务稳定运行时举杯相庆。刚毕业入职华为,有一句类似公司价值观的话讲的很好:胜则举杯相庆,败则拼死相救。
好的团队氛围关键因素之一,要保持团队稳定性,但要做到这一点很难,所以可以退而求其次,保持团队人才梯队稳定性:老带新,新成老,老升职或跳槽去追求更大成长空间。一个再好的项目,经过多次不完整交接之后,也会面临腐化挑战,出问题都没人能解决或者花费很长时间熟悉项目代码,改动代码也会瞻前顾后,担心掉到暗坑里。什么叫完整交接?我的理解,完整是指经过梯队培养的新人,在项目里做过相对比较长时间的深入开发,对已知的问题或设计缺陷有比较清晰的理解,知道怎么避坑,敢改代码,敢加功能。我认为以校招同学来看,至少全职投入一年,两年最好,才算是完整的交接。离职前一个月的工作交接,不能算交接,只能算转交,其实接手的人可能完全没接住,尤其是之前都没接触过这个项目的核心代码。
好的团队氛围还有一个比较关键的点,业务发展要好,只有团队业务发展好了,团队才能保持稳定,才有机会构建人才梯队,否则HC都没有了怎么培养接班人?只有每个人都有发展,有一定的技术挑战,有成长,才能稳定。所以要用业务发展解决团队里的各种问题,把蛋糕做大,团队成员每个人才能吃饱,只在团队内互相卷、做表面功夫大家都没有出路。
怎么把团队氛围搞好?有什么挑战?
根据上述好的氛围的解释,要搞好氛围其实说起来比较容易,但是做起来很难。我这块做的不算好,原因是部分业务发展没有达到预期,这就是搞好的团队氛围的挑战。这里就只讲一下我在团队氛围这块做了什么事情。
- 给团队找方向
- 项目1:高性能为核心优势,持续强化;以性价比为特色,持续完善
- 项目2:降本、增加业务粘性、提升稳定性,练好内功
- 项目3:用心维护、保持稳定、不出问题
- 给团队找业务
- 项目1:以项目3当前服务的业务为切入点,新增业务优先考虑使用项目1,后续再逐步切换
- 项目2:以集团内部业务为主,挖掘增量,扩大营收,提高利润
- 给团队立愿景
- 项目1:将其打造成为存算分离架构下的最佳开源云原生分布式存储系统
- 项目2:通过技术架构演进为业务降本,通过扩大存储规模来提升营收和利润,成为基础设施团队的重要利润贡献者
- 给人才找发展
- 根据个人意愿和业务需求确定个人发展方向,最终还是靠业务发展来促进人才发展
- 给团队立标杆
- 团队优秀案例宣贯,红黑星制度
- 以身作则,践行公司3大价值观
此外,我接触过的程序员都比较单纯,没有遇到过勾心斗角、互相拆台的戏码,最多也就是在技术上争辩几句,无伤大雅。以后真遇到了这类人,肯定不会留在团队里。
任务分派
听过一个观点是说团队80%的工作是20%的人做的,如果团队内小伙伴都是差不多的级别,这个比例应该有点夸张,但是也有一定的道理。比如一个团队里有一个技术大佬,他一个人做的工作,可能是几个校招生都做不出来的,这样比较的话,比例就很高了。
任务怎么分?分给谁?
通常我会把任务分为几类,同时还要了解每个小伙伴的技术兴趣和发展规划,以及每个人的技术专长:
- 重要且紧急:提需求给组长,沟通确认需求细节和优先级,初步评估复杂度,和当前人力分工以及任务饱和度,匹配最合适的人选,是否与当前工作有冲突,是否需要调整工作优先级或者更换其他人选
- 其他任务:加入需求清单,根据需求重要程度和优先级,排入合适的迭代或版本进行开发,具体人选综合考虑任务所属模块和个人主动认领来确定
- 线上故障:立即组织全体核心成员进行会诊,分头行动,快速修复
- 架构师或技术大佬:沟通对齐项目面临最大技术/架构挑战即可,预研完成后的版本落地由其他中低职级的开发负责
小伙伴的技术专长这块怎么发现?怎么把任务分配到合适的小伙伴?
我通常是看简历、review其代码和文档、使用或测试其开发的功能、观察其做事风格、与其深入沟通技术兴趣点(通常兴趣点就是其专长)。
一个紧急不重要的任务,通常不太建议分给一个做事认真细致考虑全面(这不是说这种小伙伴不好,相反很好但不适合这类任务),否则极有可能超出预期完成时间。通常这类任务一般分给做事迅速果断,先撸一版上线不行再花几个小时改好那种同学。
一个大家都没有知识储备的调研任务,通常应该分给那些学习能力特别强、对新技术特别敢兴趣的小伙伴,他可以在短时间内了解这块技术的大致情况,并给出后续的研究方向。
而一个重要且紧急的任务,就要确保一次做到完美,并且要保证按期完成,那么技术能力和deadline意识很强、考虑问题全面、代码质量高的小伙伴就是首选。你不能指望一个过往任务都经常延期或者bug频发的人,突然接手一个重要紧急的事情,就能很好的如期高质量完成,工作习惯很难短时间改变。
有些小伙伴代码写的很好,但不擅长让代码跟人打交道,就是产品意识不足,做出来的东西没有bug质量很高,但是用起来就差强人意,用户感觉非常别扭,这类小伙伴通常适合做纯后端开发,不适合做接口、命令行工具、前端交互界面等类型的工作。
分配任务,当然也要看任务所属模块和模块的负责人,上面说的是模块有多个负责的小伙伴,或者新模块的情况,如果只有一个人负责一个模块,那就得考虑梯队人力了。
任务和技术职级的关系?任务的挑战/复杂度如何定义?
为了每个小伙伴都有各自的发展(直白点就是晋升),每个人要承担符合各自发展需要的任务,否则任务和职级不匹配,会导致人力浪费或者项目进度受影响。P5的人做P3的事,或者P3做P4的事情(33~41还好,跨多个级别就不合适了),都不合理。
所以要先把一项任务定义到所对应的级别,考虑好任务的复杂度和挑战,这需要比较多的开发经验才能作出合适的评估。我有时候也做不好,一般有两种方式来尽量准确,一是参考leader或者其他小伙伴的意见,二是先安排一个小伙伴去调研/PoC,而不是直接安排到版本去开发落地。
那么一些团队里必须要做的基础工作(比如日常值班解答用户问题,日常运维等等)怎么安排?通常新人会承担多一些这类任务,一来熟悉项目和业务,二来也符合级别发展需求。如果已经都比较熟练了,或者级别都稍高一点了,可以尝试值班排期,团队内部共同分担这类“杂活”,防止某些小伙伴一直“打杂”,影响他的发展。据我经验,很多小伙伴沟通的时候,一旦此类“打杂”工作过多(尤其是相对其他小伙伴),都会表达出来,如果再不解决,极有可能跑路。
绩效考核的时候,基础工作(或者“打杂”)其实对绩效的正面影响不是特别大,因为大家都做的差不多,除非某些小伙伴在运维的时候没遵守操作流程搞出锅了,这是减分项。重点还是看关键任务产出,所以一般在沟通的时候都会提前讲清楚这方面的事情。
怎么让每个小伙伴都有合适的发展路径?
一般来说,新入职的小伙伴,都是从周边非核心模块开始上手,搞出了问题,影响可控,不会给团队造成比较大的不良影响,等他把周边模块搞得风生水起后,也有新的小伙伴过来接手这块工作了,他就可以抽出来做更核心的业务模块了,这样也就有了自己的发展。否则一上来就做核心模块,学起来也吃力,大家也不放心,容易受打击。
高级别的小伙伴,关键要能给项目带来更高的价值,承担重任,关键问题能hold住,关键时刻能顶上去,关键业务能拿下来,组织绩效或者OKR就是靠这些小伙伴搞定的。业务拿不下来,OKR完成不了,项目都可能要被裁撤了,何谈个人发展?
最好的结果是了解团队中每个成员的能力和兴趣点,匹配项目目标,做到项目和个人成长的双赢。
领导业务
明确业务目标(制定OKR目标就是明确的一个过程),带领团队促进目标达成,上面的招聘、绩效、分工、氛围都是为了达成业务目标,都是具体的手段。
每个团队的业务和目标都不同,如何领导业务这块感觉也没啥好写的。
领导自己
领导自己也是为了更好的领导业务,为了领导自己做了哪些事情?
- 多沟通、多倾听团队意见,共同制定改进措施,持续跟进改进效果并进行修正
- 理论实践结合:读书、动手做事情(了解项目、了解团队成员,编译部署/找问题、写代码/review代码、写文章、写文档、宣传),了解项目和团队的优势和短板,扬长避短
- 拓展视野:了解竞品进展和优势、接触用户、拿需求
- 把项目放在心里:思考与竞品的差距和弥补措施、思考差异化发展路径、思考用户需求场景
- 破釜沉舟的心态:把当前项目作为个人职业生涯的最后一个项目,没有退路,必须成功
目前我感觉到的自己的不足之处主要有:
- 团队内部个别员工的积极性很难调动起来,苦口婆心没有效果,不知道怎么才能激励
- 项目发展方向制定时怕犯错,担心试错成本
- 个人的技术和产品视野不够开阔,对存储领域的理解不够深入,例如想做出差异化,但是又没有特别好的思路
- 没有形成体系化的管理方法论,还比较零散,需要多学习、思考、总结、沉淀
其他应该还有一些,尤其是在领导和小伙伴们眼里应该还有不少,希望能听到更多你们的声音。
141. 环形链表
题目链接:https://leetcode.cn/problems/linked-list-cycle/
一开始被题目里的pos误导了,后面直接看了官方题解,让我做感觉不一定做得出来,第一种方法估计会想不到增加一个set或者map或者vector保存链表节点的地址,第二种方法更想不到。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /* bool hasCycle(ListNode *head) { unordered_set<ListNode*> set; while (head) { if (set.count(head)) { return true; } set.insert(head); head = head->next; } return false; } */ bool hasCycle(ListNode *head) { if (!head || !head->next) { return false; } ListNode* slow = head; ListNode* fast = head->next; while (fast && fast->next) { if (slow == fast) { return true; } slow = slow->next; fast = fast->next->next; } return false; } }; |
94. 二叉树的中序遍历
题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/
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 30 31 32 33 34 |
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: void walk(TreeNode* node, vector<int> &res) { if (!node) { return; } if (node->left) { walk(node->left, res); } res.push_back(node->val); if (node->right) { walk(node->right, res); } } vector<int> inorderTraversal(TreeNode* root) { vector<int> res; walk(root, res); return res; } }; |
344. 反转字符串
题目链接:https://leetcode.cn/problems/reverse-string/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Solution { public: void reverseString(vector<char>& s) { char c; int left = 0, right = s.size() - 1; while (left < s.size()/2) { c = s[left]; s[left] = s[right]; s[right] = c; left++; right--; } } }; |
237. 删除链表中的节点
题目链接:https://leetcode.cn/problems/delete-node-in-a-linked-list/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: void deleteNode(ListNode* node) { ListNode* tail = node; while (node->next) { node->val = node->next->val; tail = node; node = node->next; } delete tail->next; // ? tail->next = NULL; } }; |