首页 文章 精选 留言 我的

精选列表

搜索[搭建],共10000篇文章
优秀的个人博客,低调大师

svnWebUI 1.1.0 发布,搭建 svn 服务器的神器

功能说明 svnWebUI是一款图形化管理服务端Subversion的配置得工具, 虽说现在已进入git的时代, 但svn依然有不少使用场景, 比如公司内的文档管理与共享, svn的概念比git的少很多, 非常适合非程序员使用. 但众所周知svn的Linux服务端软件即Subversion的用户和权限配置全部依靠手写配置文件完成, 非常繁琐且不便, 已有的几款图像界面软件已经非常古老, 安装麻烦而且依赖环境非常古老, 比如csvn还使用python2作为运行环境. Windows上倒是有不错的svn服务端软件即VisualSVN, 但一来Windows服务器少之又少, 第二VisualSVN没有web界面, 每次配置需要开启远程桌面, 安全性不高. 经历几次失败的图形界面配置后, 萌生了写一个现代svn服务端管理软件, 让svn的服务端管理有gitea的轻松体验的想法. 演示地址: http://svn.nginxwebui.cn:6060 用户名: admin 密码: admin 安装说明 1.安装java运行环境和Subversion Ubuntu: apt update apt install openjdk-11-jdk apt install subversion Windows: 下载JDK安装包 https://www.oracle.com/java/technologies/downloads/ 下载VisualSVN https://www.visualsvn.com/server/download 配置JAVA运行环境 JAVA_HOME : JDK安装目录 Path : JDK安装目录\bin 重启电脑 2.下载最新版发行包jar Linux: wget -O /home/svnWebUI/svnWebUI.jar http://file.nginxwebui.cn/svnWebUI-1.1.0.jar Windows: 直接使用浏览器下载 http://file.nginxwebui.cn/svnWebUI-1.1.0.jar 3.启动程序 Linux: nohup java -jar -Xmx64m /home/svnWebUI/svnWebUI.jar --server.port=6060 --project.home=/home/svnWebUI/ > /dev/null & Windows: java -jar -Xmx64m D:/home/svnWebUI/svnWebUI.jar --server.port=6060 --project.home=D:/home/svnWebUI/ 参数说明 -Xmx64m 最大分配内存数 --server.port 占用端口, 默认以6060端口启动 --project.home 项目配置文件目录,存放数据库文件,证书文件,日志等, 默认为/home/nginxWebUI/ 注意命令最后加一个&号, 表示项目后台运行 docker安装说明 本项目制作了docker镜像, 支持 x86_64/arm64/arm v7 平台,同时包含Subversion和svnWebUI在内, 一体化管理与运行Subversion. 拉取镜像: docker pull cym1102/svnwebui:latest 启动容器: docker run -itd -v /home/svnWebUI:/home/svnWebUI -e BOOT_OPTIONS="--server.port=6060" --privileged=true -p 6060:6060 -p 3690:3690 cym1102/svnwebui:latest 更新说明 1.添加普通用于登录功能, 普通用户可在我的主页修改密码和查看自己权限内的仓库 2. 仓库权限可配置到某个文件夹上, 实现svn的精细权限管理 3. 实现svn库的导入导出功能

优秀的个人博客,低调大师

svnWebUI 1.0.5 发布,搭建 svn 服务器的神器

功能说明 svnWebUI是一款图形化管理服务端Subversion的配置得工具, 虽说现在已进入git的时代, 但svn依然有不少使用场景, 比如公司内的文档管理与共享, svn的概念比git的少很多, 非常适合非程序员使用. 但众所周知svn的Linux服务端软件即Subversion的用户和权限配置全部依靠手写配置文件完成, 非常繁琐且不便, 已有的几款图像界面软件已经非常古老, 安装麻烦而且依赖环境非常古老, 比如csvn还使用python2作为运行环境. Windows上倒是有不错的svn服务端软件即VisualSVN, 但一来Windows服务器少之又少, 第二VisualSVN没有web界面, 每次配置需要开启远程桌面, 安全性不高. 经历几次失败的图形界面配置后, 萌生了写一个现代svn服务端管理软件, 让svn的服务端管理有gitea的轻松体验的想法. 演示地址: http://svn.nginxwebui.cn:6060 用户名: admin 密码: admin 安装说明 1.安装java运行环境和Subversion Ubuntu: apt update apt install openjdk-11-jdk apt install subversion Windows: 下载JDK安装包 https://www.oracle.com/java/technologies/downloads/ 下载VisualSVN https://www.visualsvn.com/server/download 配置JAVA运行环境 JAVA_HOME : JDK安装目录 Path : JDK安装目录\bin 重启电脑 2.下载最新版发行包jar Linux: wget -O /home/svnWebUI/svnWebUI.jar http://file.nginxwebui.cn/svnWebUI-1.0.5.jar Windows: 直接使用浏览器下载 http://file.nginxwebui.cn/svnWebUI-1.0.5.jar 3.启动程序 Linux: nohup java -jar -Xmx64m /home/svnWebUI/svnWebUI.jar --server.port=6060 --project.home=/home/svnWebUI/ > /dev/null & Windows: java -jar -Xmx64m D:/home/svnWebUI/svnWebUI.jar --server.port=6060 --project.home=D:/home/svnWebUI/ 参数说明(都是非必填) -Xmx64m 最大分配内存数 --server.port 占用端口, 默认以6060端口启动 --project.home 项目配置文件目录,存放数据库文件,证书文件,日志等, 默认为/home/nginxWebUI/ 注意命令最后加一个&号, 表示项目后台运行 docker安装说明 本项目制作了docker镜像, 支持 x86_64/arm64/arm v7 平台,同时包含Subversion和svnWebUI在内, 一体化管理与运行Subversion. 拉取镜像: docker pull cym1102/svnwebui:latest 启动容器: docker run -itd -v /home/svnWebUI:/home/svnWebUI -e BOOT_OPTIONS="--server.port=6060" --privileged=true -p 6060:6060 -p 3690:3690 cym1102/svnwebui:latest 更新说明 1.添加直接在网页查询svn文件列表的功能 2. 添加导入导出仓库和导入用户配置文件的功能, 方便老svn系统迁移 3. 增强系统登录安全性 下一步开发计划 1. 可以配置用户权限到某个目录上, 这个是svn比git强的地方, 更高级的权限管理, 必须要支持 2. 普通用户可以登录, 查看自己的项目和修改密码, 尽量贴近gitea的用户体验

优秀的个人博客,低调大师

关于技术团队搭建&管理的一些思考

​编者按 本文的作者,是今年来增长迅猛的美国智能家居品牌Wyze的首席架构师刘天强。他曾是AWS Rekognition的创始成员,有丰富的技术团队管理经验。 质量和交付速度谁更重要?对开发者应该高压管理吗?定制度还是自动化?该招聘什么样的工程师?还有极容易被忽略的中层管理者困境:技术专业性和赢得领导层的长期信任,二者怎么兼容? 这些问题,相信本文能提供一个解决思路。以下是来自他的自述…… 19年加入Wyze至今,从孤身一人到现在大约百来号人的团队,从搭班子到管理,中间遇到的大大小小的问题不少。一直也想找机会写下来,一来能把经验传播给团队,二来帮助自己将一些零散的想法系统化,三来造福更多想在技术创业领域大展拳脚的朋友。 速度vs质量 无论在创业公司还是大公司,这几乎是一个永恒的话题。对技术团队来说,永远面临着领导层和产品团队对于交付的压力,但同时也面临着草率发布以后未来被技术债反噬的问题。如何抉择或者平衡速度和质量,是所有技术团队管理者需要学习的重要一课,这里说一下我在做决策时的原则:在资源和时间允许的情况下,永远质量为王。 许多创业公司的朋友很可能不认同这一点,毕竟没有迭代和发布,就没有流量和收入,公司的现金会被迅速烧光。但这里有个前提条件,是“资源允许”的情况下。一般在B轮以前的创业公司,速度比质量更占优,因为大家关注点在于“生存”,但是B轮以后乃至上市公司,质量逐渐会比速度获得越来越多的关注,公司阶段越到后期,质量为王的效益就越发明显。 原因就在于四个字:边际效应。 一般来说,段数比较高的工程师在项目中思考更加周到、质量意识更高,当然反映在工资单上也更贵,但若公司收入增长曲率稳稳大于人员增长(例如收入指数增长,人员线性增长),越往后期,即便好工程师显著增加,收入和人员开销的距离也一定会逐渐拉大,如果此时在兼顾质量的同时速度跟不上,相比低质价廉手快但成长性偏弱的996团队,明智的管理层会选择横向扩张高质量的工程师来弥补战力不足,并且降低未来的安全和运维风险。反映在实际公司的经营中,早期工程团队的救火英雄往往是对内容了解,能够“Make it work”和“搞定问题”的执行者,不需要有强烈的质量意识和全局意识,但这部分人若在系统思考方面不成长,在后期质量为王的环境里就容易被业界经验更丰富、更擅长长线思考的同事们所取代,就造成了许多创业公司里早期员工跟不上后期发展的情况。 学会妥协,做双向方案: 现实情况下,资源无限的上下文几乎不存在,无论是创业公司有限的资金,还是大公司细到各个组的年度预算,都让技术团队的管理者无法永远在面对问题时无脑选择质量,这时候我们需要探讨的就是“妥协的艺术”,但敢于说“不”对于任何人都不容易。这里说一个我实际遇到的小例子: 在公司发布的一款智能硬件产品离预定的递交工厂生产的日期不到两周时,固件团队新来的负责人发现原来ODM设计的文件分区会让未来系统无法更新openssl等和安全相关的库。当时我们面临着来自产商、客户、以及公司回款的压力,如果在这最后两周重构底层固件,加上测试的时间,所有进度都会被打乱和推延,但如果不做这个更新,未来用户可能会因为无法升级固件相关的安全库,产生设备被攻击和数据泄露的风险。 两相权衡后,我选择说服业务团队顶住压力,将交付工期延后,最后公司也同意了我的决策。 这个决策现在看起来并不复杂,但包含着一个重要的原则:做双向方案。如果当日交付以后,我们能够较为容易地强制更新设备操作系统补上漏洞,我会选择先交付再修补,让业务和公司少扛压力。然而在当时的情况下这并不容易做到,因此我决定防范于未然。同样的决策原则,在有些时候我会偏向于“速度”,例如在上线前一些小比例的“边缘问题”没有妥善处理但很容易在后续迭代中修复。 风险管控 大原则只有一句话:承担可计算的风险。 可能不只是管理技术团队,生活其他方面这一条也同样适用。反映在技术团队遇到的问题中,常常和运维以及突发事故处理有关。 对于大公司来说,由于基础设施齐全,不太存在做决策前无法拿到足够数据的问题(虽然一些早期的组也可能有),但创业公司往往不是这样的,因此风险管控在实际操作中常常就落实到数据的可视化上。 我们公司曾经有一套早年外包出去的基础架构,下属几十个子服务和100多个API,文档不全,质量不高。但因为极其重要,内部成立了一个团队来消化和重构之,因为该系统信息繁琐,在开始的阶段十分难以下手。团队经常遇到的问题类似:是否应该要把这两个API合并?修改这段代码对系统整体的影响是什么?部署安全吗? 所有这些问题纠结的根本就在于:行动风险无法预估。但如果我们放任不做大刀阔斧的改变,只专注于做小修小补,一来团队会面临越来越多的公司内部压力和质疑,二来团队本身长期的运维压力也会逐步变大。 因此我们的决定是:与其乐观而莽撞地修改系统的功能,不如在对系统做任何实际性修改和重构以前,先给各部分加上服务级别的指标并按照统一标准给重要的服务加上工作台和警报,这样方便在测试环境中对所有修改预估风险并排出优先级,同时和过去的外包团队不尽其烦地请教不清晰的部分。 在这项工作的前几个月,该系统发生过几次因为历史遗留问题导致的事故,但因为并没有足够的指标和相关部分的了解,团队更多聚焦在减轻问题的方案而不纠结于根治,这在许多不了解情况的人看来是在“滑水”,但在团队辛勤劳作了4个月后,几次重要的部署彻底改变了过去该系统“一个月发生三次事故”的惨状,此后该系统运行极其稳定,最终也扭转了团队的口碑并且收获了信任。 宽vs严 没有人喜欢自己的老板做“显微镜管理”,但不得不说,事无巨细很多情况下确实能解决不少问题,尤其是技术岗的经理常常自己工程能力不输给下属。多管一些还是少管一些都各有各的道理,但仍然不乏原则。 总的原则是:管小团队适合从严,管大团队不能太严。小团队时期,领导自己需要下火线,对业务了解如果不驾驭在下属之上,很难服众,但是团队出现层级以后,如果层级高的领导事无巨细,反而是一种僭越,并且一定会让自己成为瓶颈。这里的问题在于,如果不事无巨细,如何保证团队的执行力? 19年的时候,公司还在极其早期时发生过数据泄露,大体是因为一个初级员工不慎将一些机器暴露在网络上引发黑客的攻击并且夸大。当时责任团队大致30人左右,事后反省时,我们几乎不关注员工的个人失误,而聚焦在管理的缺失上,核心问题在于:为什么团队经理无法在事故发生前就知道组员的操作失误并且及时制止?当时责任团队30多人,已经超过了经理能够事无巨细过问的范围,在帮助团队回顾具体事宜、强化必要安全措施的同时,我提出了两个比较显而易见的建议: 细分团队的层级:当时的团队,30多位工程师同时报告给1个经理,根本无法在小团队的层面从严管理,合理的做法是将团队划分成至多7人一组,由几位基层经理统驭,再汇报给高级经理。 这样一来可以保证基层的“严”,二来可以避免高层成为瓶颈。这个类似于Amazon的“Two Pizza Rule”。 强化自动化检测机制:中心思想是“在运维方面,人比机器更容易犯错误”,与其寄望于招到的永远都是明星工程师或者基层经理的事无巨细,不如尽可能把重复琐碎的工作交给自动化,降低管理成本,而且还能避免过多带着感情色彩的决策。 后来这两个建议都被团队采纳,执行了一年后再没有出现过重大安全事故,运维质量也有了质的提高。另外:从基层经理到高层经理的必经之路,是如何将“事无巨细”交给“制度和自动化”?这正是我们的下一个话题。 制度vs自动化 承接上篇的安全问题,如果需要在长期完全避免,则同时需要一套所有工程师都遵守的制度和一套完善的自动化检测机制。我们时常面临的问题是:哪些事情适合对团队订立制度,言传身教?哪些适合死磕自动化来替代人力? 原则是:能自动化的尽量自动化,资源所限无法短期内自动化的规则,主要靠制度和执行。原因是:对于确定性的任务,机器永远比人可靠。 近期的一个小例子:团队用到一个关系型数据库需要定期更换密码,但因为业务繁忙,工程师时常忘记。这种情况后续讨论的结果就是:通过自动运行的脚本来每月更换密码并且将其存入只有必要的工程师和服务能够访问的地方。这样一来经理不用每月都提醒下属更换密码,二来更方便管理密码的获得权限,两全其美。 上述这类自动化做多了以后,相关的团队发现需要手工干预的任务越来越少,制度的订立和执行成本大幅度下降,团队条条框框也少了,最终从经理到下属大家都开心。 自动化好处多多,但是因为工程资源有限,对于处理许多情况,很多时候团队不得不靠订立制度而非自动化。订立制度、撰写文档都不太困难,关键在于“执行力”。大部分情况下,制度的执行和管理者的强调力度成对数增长的关系,过分甚至偏激地强调制度的执行并不会显著地提高执行效率,有时反而事与愿违。因此,“执行力”的精髓在于“激励”而不非“强推”。 “激励”并不限于比较实际的和金钱挂钩的激励,很多时候可以是让员工意识到这么做利人利己、降低自己工作的好办法。就拿之前所说的自动化来说,如果要激励团队尽可能自动化,最有效的办法永远不是一味强调,而是让那些意识不强的员工强制执行一两次后,自己看到自动化对自己平衡生活与工作的好处。 信任的力量 这本著名的《团队的五个功能障碍》里面强调的最本质问题就是“信任”,具体到我们今天讨论的话题,就可以衍生出许多有意思的问题,其中想谈三个代表性问题:对于自己不熟悉的技术领域,是否完全放心放权?对于和非技术团队的合作,甚至是公司的领导和管理层,如果专业判断在某些情况下会影响到对方对自己的信任,是选择专业判断还是信任?如何获得信任? 对于自己不熟悉的技术领域,是否完全放心放权? 放权是扩张业务范围的必经之路,但新的领域往往面临着未知和风险,并且很可能不是你所擅长的,这时候学会如何寻找和管理代理人就异常重要。 领导自身对新领域的持续学习固然重要,但本文主要聚焦在管理上,因此关于“如何快速学习新领域的知识”这部分就略去不表。总的来说,我的原则简单概括为四字:严进宽出。具体展开来说:在选领域带头人时慎之又慎,但一旦选定,便无保留地信任对方的专业并给予充分的自由度。 原因也很简单:术业有专攻,尤其是技术领域,管理一个多元的技术团队不代表团队领导就一定了解每个细分领域的知识点和细节,但其通识、逻辑和思辨必须较大部分下属出色。这里举出我们之前创立固件团队的例子。 对于一家智能硬件公司来说,出色的端侧工程能力十分重要,但由于我们技术团队早期几乎所有核心人物都是云计算和AI背景,真正开始深度介入固件领域的时间非常晚。这当中有两个明显的难处: ODM投入较大,积累较多,作为人员资源严重不足的新团队,学习速度必然跟不上业务成长; 端侧技术栈偏底层,大量基于C/C++甚至是汇编和Linux kernel,市面上人才储备严重不足,主要原因是大部分互联网公司不需要和硬件固件打交道。 然而,作为一家长期技术栈必然大量依靠端云结合技术的特殊互联网公司,我们必须咬牙把固件这块硬骨头啃下来。于是,从2020年初开始,我们便踏上了寻人之路,先后花了一年时间,也只找到了个位数的初始成员,在经历了几番波折后,在年底方才找到了能够放心托付团队的负责人。虽然过程并非一帆风顺,但是对于“严进宽出”这条准则中的“严”有了更具体的看法: 对于技术团队的领导人来说,不在其领域的人常常无法精准地判断他的水平,但无论任何一个领域的带头人,其在计算机科学领域的基本素养必须扎实过关,逻辑思维能力必须强,这也成了“外行”评价“行家”的核心部分。 我上一家公司Orbeus在被Amazon收购以前,曾经经历过一轮严格的技术尽调,在持续3小时的展示和问答环节中,Amazon那边派出的PE虽然并非AI领域的专家,但我注意到对方在仔细倾听和消化我方的技术架构后,一边梳理知识点,一边以“假设我要学习这项技术”的态度做出提问,还问出了许多一开始我们自己都没想过的问题。在叹服之余,我也从中学习到了“通识”的重要性,这对我在Wyze组建多元化技术团队时如何鉴别人才提供了重要的启发。 业务扎实的好人才有其共性:通识强大、逻辑严谨、态度谦逊而且直面问题。 基于这些判断,我在面试阶段比较少问深度领域相关的问题,更多让面试者说自己的工作,然后抱着学习的态度做一些深入的了解,例如面试者常常会说自己做过的系统架构,那我就会问某两个模块间通信怎么加密的?证书怎么存放?如何在某个步骤发生问题的时候怎么容错?哪些指标可以用来评价特定模块的开发质量?另一种方式看起来更简单但你为什么这么做?这些问题非常宽泛,但是从回答中可以看出面试者思考问题的方式和面对挑战的态度。 业务层面过关自然很重要,但人才是否能够在团队中获得成功,尤其是高层人才,还需要至少考察两方面:动机和领导力。在固件团队最终找到合适的带头人以前,我们经历过一次波折。该团队第一任带头人业务十分扎实,在任一年业绩也可圈可点,却不到一年就提出离职,理由是希望出去“自己做点事情”。 这意味着我们选人时在对对方的动机和领导力的判断上出现重大问题,虽然每个人都有选择自己职业路线的自由和权力,但是选择团队重要合伙人的关键点在于“是否能够和公司一起成长”,无论是能力上还是财务回报上。如果无法以“共同成长”做为出发点,这个人必然会在某个时间节点下船,从而引出一系列突发事件。 再深入一些,虽然不是100%,但近两年我发现团队中的顶级成员和成长最快的新人普遍有一个共性:对自己所在领域和工作内容充满了热情并且舍得投入大量的精力,这种浓厚的求知欲在不自觉之间成为了他们和公司共同成长的基础,不仅为他们个人带来职业上的回报,也为公司带来巨大的价值。所以在判断一个人是否是个好的领域带头人时,这一点同样适用:强烈的求知欲和对自己所在领域的热情。 如果一个人谈到技术时没有办法容光焕发,而只是一味专注于自己将来职业发展或者待遇的话,那就趁早算了。 在经过千辛万苦找到可以拜托的人以后,下面就需要充分的信任,作为团队领导,也可以把注意力从业务转移到垂直领域的评价体系建立上,你需要和新来的带头人在最初的一两个月把第一年的范围和成功的标准制定讨论清楚,也可以让对方推荐一些领域相关的综述和文章,这有助于你能够提纲挈领地把握重点而不被带跑偏,尤其是一些学术性较强的领域,例如AI,很多时候一个细分领域的研究就可以帮助你从高层次了解大家努力的方向,进而获得决策能力,这类阅读不仅仅只限于开始的阶段,随着范围和优先级不断变化,你也需要读越来越多的综述来理解团队的整体认知。 Professionalism vs Trust? 大多数情况下,专业化会促进信任加深,但在少数且重要的环境下,却未必如此,典型的情况例如多个不同的团队合作时,一个团队的专业化准则和另一个团队发生冲突。智能硬件领域多的是这样的例子:技术想要高配高质,运营方面的成本考量不允许,产品方面上市时间考量不允许。还有一些公司过度注重财务模型,却忽略了长期技术和产品的潜在影响。 这里我的答案也很简单:Always Prioritize Trust over Professionalism。理由也不复杂:专业化的作用是把一件事做好,如果合作双方(N方)都没有了信任,事情都不用做了,又谈何“做好”?作为技术人员,我们的天性不像其他职业一样容易变通,尤其是资深工程师,对于技术方案吹毛求疵的程度有时就像从草堆里挑绣花针。如果一不合意就耽误业务,长久下来业务不是去找别的技术团队,就是把工程外包,最终结果是双输。 所以这里关键要把握一个度,有所为,有所不为,核心原则就是前文提到的做双向方案,只要不触及“不可逆”的底线,其他点都是可以拿到桌面上谈的,在大家把自己诉求开诚布公地沟通,做适当妥协的过程中,信任也建立起来了。 对于开发团队来说,需要特别提醒一点:产品团队对技术团队的方案建议,可以参考,但一定要思辨。这里所说的信任,具体来说是长期的,只要在不损害长期信任的前提下,一定要充分考虑专业性。归根到底,产品团队关注重点在于项目的交付,但技术团队的重点是怎么交付可以做得更好并且最小化将来的维护成本。一个极端但简单的例子:技术团队是否写UnitTest对于产品发布看起来影响不大,但是缺少了这一环,代码在许多边缘问题上的逻辑恐怕并不是工程师原来预想的那样,会大大降低代码质量,提高维护成本。在一些关键原则上,如果扮演“好好先生”,长远来讲,不仅不利于建立信任,反而可能会危害到早期因为“手快”建立起的短期信任。 如何赢得信任? 这个话题极其宽泛,但在本文的讨论范围内,行为准则大致离不开这几个关键词:坚持长期主义、行为和决策多数可被预测(看得透)、一诺千金、不轻易承诺、持续做事实证明正确的决定。 坚持长期主义:在“Professionalism vs Trust”这一节中提到了“长期信任”的概念,这是在任何情况下我们都需要争取的信任类型。如果一个行为能够在短期内赢得合作伙伴信任甚至增进关系,但长期来说却有害,那么一定需要抵制住诱惑。 表现在开发团队,最经常遇到的情况就是从产品经理处拿到一堆需求,对方问研发经理某月某日前能够完工么,研发经理一看时间觉得很紧,但为了迎合业务,在省掉UnitTest、加入一些quick & dirty的做法后,发现纯功能开发刚好能赶上进度就直接说ok。 工程团队少干活少动脑子,产品那边又能按期交付,大家都很开心,然后产品就这样发布了。可想而知,在用户不多的情况下产品问题也不大,毕竟没几个人会提反馈或者到SNS上写测评,但一旦量大到一个程度,每天公司的客服接到的都是质量问题的抱怨,工程师每天都忙着修琐碎的bug做不了新项目,士气低落,产品新功能无法推进,时不时还来一个整体宕机搞得全公司抓狂,最终越来越多工程师离职,在职工程师压力越来越大,新产品无法发布,发布了也无法取得用户信任,工程师和产品团队信任破产,全剧终。 本文作者:刘天强 原文链接:https://tianqiangliu.medium.com/ 后续我们还会分享更多团队管理相关的文章,感兴趣的小伙伴可以关[LigaAI@oschina](https://my.oschina.net/u/5057806) ,也可浏览 LigaAI-新一代智能研发管理平台~

优秀的个人博客,低调大师

实时计算框架:Spark集群搭建与入门案例

一、Spark概述 1、Spark简介 Spark是专为大规模数据处理而设计的,基于内存快速通用,可扩展的集群计算引擎,实现了高效的DAG执行引擎,可以通过基于内存来高效处理数据流,运算速度相比于MapReduce得到了显著的提高。 2、运行结构 Driver 运行Spark的Applicaion中main()函数,会创建SparkContext,SparkContext负责和Cluster-Manager进行通信,并负责申请资源、任务分配和监控等。 ClusterManager 负责申请和管理在WorkerNode上运行应用所需的资源,可以高效地在一个计算节点到数千个计算节点之间伸缩计算,目前包括Spark原生的ClusterManager、ApacheMesos和HadoopYARN。 Executor Application运行在WorkerNode上的一个进程,作为工作节点负责运行Task任务,并且负责将数据存在内存或者磁盘上,每个 Application都有各自独立的一批Executor,任务间相互独立。 二、环境部署 1、Scala环境 安装包管理 [root@hop01 opt]# tar -zxvf scala-2.12.2.tgz [root@hop01 opt]# mv scala-2.12.2 scala2.12 配置变量 [root@hop01 opt]# vim /etc/profile export SCALA_HOME=/opt/scala2.12 export PATH=$PATH:$SCALA_HOME/bin [root@hop01 opt]# source /etc/profile 版本查看 [root@hop01 opt]# scala -version Scala环境需要部署在Spark运行的相关服务节点上。 2、Spark基础环境 安装包管理 [root@hop01 opt]# tar -zxvf spark-2.1.1-bin-hadoop2.7.tgz [root@hop01 opt]# mv spark-2.1.1-bin-hadoop2.7 spark2.1 配置变量 [root@hop01 opt]# vim /etc/profile export SPARK_HOME=/opt/spark2.1 export PATH=$PATH:$SPARK_HOME/bin [root@hop01 opt]# source /etc/profile 版本查看 [root@hop01 opt]# spark-shell 3、Spark集群配置 服务节点 [root@hop01 opt]# cd /opt/spark2.1/conf/ [root@hop01 conf]# cp slaves.template slaves [root@hop01 conf]# vim slaves hop01 hop02 hop03 环境配置 [root@hop01 conf]# cp spark-env.sh.template spark-env.sh [root@hop01 conf]# vim spark-env.sh export JAVA_HOME=/opt/jdk1.8 export SCALA_HOME=/opt/scala2.12 export SPARK_MASTER_IP=hop01 export SPARK_LOCAL_IP=安装节点IP export SPARK_WORKER_MEMORY=1g export HADOOP_CONF_DIR=/opt/hadoop2.7/etc/hadoop 注意SPARK_LOCAL_IP的配置。 4、Spark启动 依赖Hadoop相关环境,所以要先启动。 启动:/opt/spark2.1/sbin/start-all.sh 停止:/opt/spark2.1/sbin/stop-all.sh 这里在主节点会启动两个进程:Master和Worker,其他节点只启动一个Worker进程。 5、访问Spark集群 默认端口是:8080。 http://hop01:8080/ 运行基础案例: [root@hop01 spark2.1]# cd /opt/spark2.1/ [root@hop01 spark2.1]# bin/spark-submit --class org.apache.spark.examples.SparkPi --master local examples/jars/spark-examples_2.11-2.1.1.jar 运行结果:Pi is roughly 3.1455357276786384 三、开发案例 1、核心依赖 依赖Spark2.1.1版本: <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>2.1.1</version> </dependency> 引入Scala编译插件: <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>3.2.2</version> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> 2、案例代码开发 读取指定位置的文件,并输出文件内容单词统计结果。 @RestController public class WordWeb implements Serializable { @GetMapping("/word/web") public String getWeb (){ // 1、创建Spark的配置对象 SparkConf sparkConf = new SparkConf().setAppName("LocalCount") .setMaster("local[*]"); // 2、创建SparkContext对象 JavaSparkContext sc = new JavaSparkContext(sparkConf); sc.setLogLevel("WARN"); // 3、读取测试文件 JavaRDD lineRdd = sc.textFile("/var/spark/test/word.txt"); // 4、行内容进行切分 JavaRDD wordsRdd = lineRdd.flatMap(new FlatMapFunction() { @Override public Iterator call(Object obj) throws Exception { String value = String.valueOf(obj); String[] words = value.split(","); return Arrays.asList(words).iterator(); } }); // 5、切分的单词进行标注 JavaPairRDD wordAndOneRdd = wordsRdd.mapToPair(new PairFunction() { @Override public Tuple2 call(Object obj) throws Exception { //将单词进行标记: return new Tuple2(String.valueOf(obj), 1); } }); // 6、统计单词出现次数 JavaPairRDD wordAndCountRdd = wordAndOneRdd.reduceByKey(new Function2() { @Override public Object call(Object obj1, Object obj2) throws Exception { return Integer.parseInt(obj1.toString()) + Integer.parseInt(obj2.toString()); } }); // 7、排序 JavaPairRDD sortedRdd = wordAndCountRdd.sortByKey(); List<Tuple2> finalResult = sortedRdd.collect(); // 8、结果打印 for (Tuple2 tuple2 : finalResult) { System.out.println(tuple2._1 + " ===> " + tuple2._2); } // 9、保存统计结果 sortedRdd.saveAsTextFile("/var/spark/output"); sc.stop(); return "success" ; } } 打包执行结果: 查看文件输出: [root@hop01 output]# vim /var/spark/output/part-00000 四、源代码地址 GitHub·地址 https://github.com/cicadasmile/big-data-parent GitEE·地址 https://gitee.com/cicadasmile/big-data-parent

优秀的个人博客,低调大师

Redis高可用集群搭建,配置,运维与应用!

前言 现如今 Redis 变得越来越流行,几乎在很多项目中都要被用到,不知道你在使用 Redis 时,有没有思考过,Redis 到底是如何稳定、高性能地提供服务的? 你也可以尝试回答一下以下这些问题: 我使用 Redis 的场景很简单,只使用单机版 Redis 会有什么问题吗? 我的 Redis 故障宕机了,数据丢失了怎么办?如何才能保证我们的业务应用不受影响? 为什么需要主从集群?它有什么优势? 什么是分片集群?我真的需要分片集群吗? 如果你对 Redis 已经有些了解,肯定也听说过数据持久化、主从复制、哨兵这些概念,它们之间又有什么区别和联系呢? 如果你存在这样的疑惑,这篇文章,我会从 0 到 1,再从 1 到 N,带你一步步构建出一个稳定、高性能的 Redis 集群。 在这个过程中,你可以了解到 Redis 为了做到稳定、高性能,都采取了哪些优化方案,以及为什么要这么做? 掌握了这些原理,这样平时你在使用 Redis 时,就能够做到「游刃有余」。 Redis实战学习笔记+面试视频+面试真题,这篇文章干货很多,希望你可以耐心读完。 从最简单的开始:单机版 Redis 首先,我们从最简单的场景开始。 假设现在你有一个业务应用,需要引入 Redis 来提高应用的性能,此时你可以选择部署一个单机版的 Redis 来使用,就像这样: 这个架构非常简单,你的业务应用可以把 Redis 当做缓存来使用,从 MySQL 中查询数据,然后写入到 Redis 中,之后业务应用再从 Redis 中读取这些数据,由于 Redis 的数据都存储在内存中,所以这个速度飞快。 如果你的业务体量并不大,那这样的架构模型基本可以满足你的需求。是不是很简单? 随着时间的推移,你的业务体量逐渐发展起来了,Redis 中存储的数据也越来越多,此时你的业务应用对 Redis 的依赖也越来越重。 Redis 因为某些原因宕机 但是,突然有一天,你的 Redis 因为某些原因宕机了,这时你的所有业务流量,都会打到后端 MySQL 上,这会导致你的 MySQL 压力剧增,严重的话甚至会压垮 MySQL。 这时你应该怎么办? 我猜你的方案肯定是,赶紧重启 Redis,让它可以继续提供服务。 Redis数据丢失如何选择 但是,因为之前 Redis 中的数据都在内存中,尽管你现在把 Redis 重启了,之前的数据也都丢失了。重启后的 Redis 虽然可以正常工作,但是由于 Redis 中没有任何数据,业务流量还是都会打到后端 MySQL 上,MySQL 的压力还是很大。 这可怎么办?你陷入了沉思。 有没有什么好的办法解决这个问题? 既然 Redis 只把数据存储在内存中,那是否可以把这些数据也写一份到磁盘上呢? 如果采用这种方式,当 Redis 重启时,我们把磁盘中的数据快速恢复到内存中,这样它就可以继续正常提供服务了。 是的,这是一个很好的解决方案,这个把内存数据写到磁盘上的过程,就是「数据持久化」。 数据持久化:有备无患 现在,你设想的 Redis 数据持久化是这样的: 但是,数据持久化具体应该怎么做呢? 我猜你最容易想到的一个方案是,Redis 每一次执行写操作,除了写内存之外,同时也写一份到磁盘上,就像这样: 没错,这是最简单直接的方案。 但仔细想一下,这个方案有个问题:客户端的每次写操作,既需要写内存,又需要写磁盘,而写磁盘的耗时相比于写内存来说,肯定要慢很多!这势必会影响到 Redis 的性能。 Redis性能受到影响?如何规避这个问题? 我们可以这样优化:Redis 写内存由主线程来做,写内存完成后就给客户端返回结果,然后 Redis 用另一个线程去写磁盘,这样就可以避免主线程写磁盘对性能的影响。 这确实是一个好方案。除此之外,我们可以换个角度,思考一下还有什么方式可以持久化数据? 这时你就要结合 Redis 的使用场景来考虑了。 Redis使用场景 回忆一下,我们在使用 Redis 时,通常把它用作什么场景? 是的,缓存。 把 Redis 当做缓存来用,意味着尽管 Redis 中没有保存全量数据,对于不在缓存中的数据,我们的业务应用依旧可以通过查询后端数据库得到结果,只不过查询后端数据的速度会慢一点而已,但对业务结果其实是没有影响的。 基于这个特点,我们的 Redis 数据持久化还可以用「数据快照」的方式来做。 那什么是数据快照呢? 简单来讲,你可以这么理解: 你把 Redis 想象成一个水杯,向 Redis 写入数据,就相当于往这个杯子里倒水 此时你拿一个相机给这个水杯拍一张照片,拍照的这一瞬间,照片中记录到这个水杯中水的容量,就是水杯的数据快照 也就是说,Redis 的数据快照,是记录某一时刻下 Redis 中的数据,然后只需要把这个数据快照写到磁盘上就可以了。 它的优势在于,只在需要持久化时,把数据「一次性」写入磁盘,其它时间都不需要操作磁盘。 基于这个方案,我们可以定时给 Redis 做数据快照,把数据持久化到磁盘上。 持久化方案,就是 Redis 的「RDB」和「AOF」: 其实,上面说的这些持久化方案,就是 Redis 的「RDB」和「AOF」: RDB:只持久化某一时刻的数据快照到磁盘上(创建一个子进程来做) AOF:每一次写操作都持久到磁盘(主线程写内存,根据策略可以配置由主线程还是子线程进行数据持久化) 它们的区别除了上面讲到的,还有以下特点: RDB 采用二进制 + 数据压缩的方式写磁盘,这样文件体积小,数据恢复速度也快 AOF 记录的是每一次写命令,数据最全,但文件体积大,数据恢复速度慢 如果让你来选择持久化方案,你可以这样选择: 如果你的业务对于数据丢失不敏感,采用 RDB 方案持久化数据 如果你的业务对数据完整性要求比较高,采用 AOF 方案持久化数据 假设你的业务对 Redis 数据完整性要求比较高,选择了 AOF 方案,那此时你又会遇到这些问题: AOF 记录每一次写操作,随着时间增长,AOF 文件体积会越来越大 这么大的 AOF 文件,在数据恢复时变得非常慢 这怎么办?数据完整性要求变高了,恢复数据也变困难了?有没有什么方法,可以缩小文件体积?提升恢复速度呢? 我们继续来分析 AOF 的特点。 AOF 的特点 由于 AOF 文件中记录的都是每一次写操作,但对于同一个 key 可能会发生多次修改,我们只保留最后一次被修改的值,是不是也可以? 是的,这就是我们经常听到的「AOF rewrite」,你也可以把它理解为 AOF 「瘦身」。 我们可以对 AOF 文件定时 rewrite,避免这个文件体积持续膨胀,这样在恢复时就可以缩短恢复时间了。 再进一步思考一下,还有没有办法继续缩小 AOF 文件? RDB 和 AOF 各自的特点: 回顾一下我们前面讲到的,RDB 和 AOF 各自的特点: RDB 以二进制 + 数据压缩方式存储,文件体积小 AOF 记录每一次写命令,数据最全 我们可否利用它们各自的优势呢? 当然可以,这就是 Redis 的「混合持久化」。 具体来说,当 AOF rewrite 时,Redis 先以 RDB 格式在 AOF 文件中写入一个数据快照,再把在这期间产生的每一个写命令,追加到 AOF 文件中。因为 RDB 是二进制压缩写入的,这样 AOF 文件体积就变得更小了。 此时,你在使用 AOF 文件恢复数据时,这个恢复时间就会更短了! Redis 4.0 以上版本才支持混合持久化。 这么一番优化,你的 Redis 再也不用担心实例宕机了,当发生宕机时,你就可以用持久化文件快速恢复 Redis 中的数据。 但这样就没问题了吗? 仔细想一下,虽然我们已经把持久化的文件优化到最小了,但在恢复数据时依旧是需要时间的,在这期间你的业务应用还是会受到影响,这怎么办? 我们来分析有没有更好的方案。 一个实例宕机,只能用恢复数据来解决,那我们是否可以部署多个 Redis 实例,然后让这些实例数据保持实时同步,这样当一个实例宕机时,我们在剩下的实例中选择一个继续提供服务就好了。 没错,这个方案就是接下来要讲的「主从复制:多副本」。 主从复制:多副本 此时,你可以部署多个 Redis 实例,架构模型就变成了这样: 我们这里把实时读写的节点叫做 master,另一个实时同步数据的节点叫做 slave。 采用多副本的方案,它的优势是: 缩短不可用时间:master 发生宕机,我们可以手动把 slave 提升为 master 继续提供服务 提升读性能:让 slave 分担一部分读请求,提升应用的整体性能 这个方案不错,不仅节省了数据恢复的时间,还能提升性能,那它有什么问题吗? 你可以思考一下。 其实,它的问题在于:当 master 宕机时,我们需要「手动」把 slave 提升为 master,这个过程也是需要花费时间的。 虽然比恢复数据要快得多,但还是需要人工介入处理。一旦需要人工介入,就必须要算上人的反应时间、操作时间,所以,在这期间你的业务应用依旧会受到影响。 怎么解决这个问题?我们是否可以把这个切换的过程,变成自动化呢? 对于这种情况,我们需要一个「故障自动切换」机制,这就是我们经常听到的「哨兵」所具备的能力。 哨兵:故障自动切换 现在,我们可以引入一个「观察者」,让这个观察者去实时监测 master 的健康状态,这个观察者就是「哨兵」。 具体如何做? 哨兵每间隔一段时间,询问 master 是否正常 master 正常回复,表示状态正常,回复超时表示异常 哨兵发现异常,发起主从切换 有了这个方案,就不需要人去介入处理了,一切就变得自动化了,是不是很爽? 但这里还有一个问题,如果 master 状态正常,但这个哨兵在询问 master 时,它们之间的网络发生了问题,那这个哨兵可能会误判。 这个问题怎么解决? 答案是,我们可以部署多个哨兵,让它们分布在不同的机器上,它们一起监测 master 的状态,流程就变成了这样: 多个哨兵每间隔一段时间,询问 master 是否正常 master 正常回复,表示状态正常,回复超时表示异常 一旦有一个哨兵判定 master 异常(不管是否是网络问题),就询问其它哨兵,如果多个哨兵(设置一个阈值)都认为 master 异常了,这才判定 master 确实发生了故障 多个哨兵经过协商后,判定 master 故障,则发起主从切换 所以,我们用多个哨兵互相协商来判定 master 的状态,这样一来,就可以大大降低误判的概率。 哨兵协商判定 master 异常后,这里还有一个问题:由哪个哨兵来发起主从切换呢? 答案是,选出一个哨兵「领导者」,由这个领导者进行主从切换。 问题又来了,这个领导者怎么选? 想象一下,在现实生活中,选举是怎么做的? 是的,投票。 在选举哨兵领导者时,我们可以制定这样一个选举规则: 每个哨兵都询问其它哨兵,请求对方为自己投票 每个哨兵只投票给第一个请求投票的哨兵,且只能投票一次 首先拿到超过半数投票的哨兵,当选为领导者,发起主从切换 其实,这个选举的过程就是我们经常听到的:分布式系统领域中的「共识算法」。 什么是共识算法? 我们在多个机器部署哨兵,它们需要共同协作完成一项任务,所以它们就组成了一个「分布式系统」。 在分布式系统领域,多个节点如何就一个问题达成共识的算法,就叫共识算法。 在这个场景下,多个哨兵共同协商,选举出一个都认可的领导者,就是使用共识算法完成的。 这个算法还规定节点的数量必须是奇数个,这样可以保证系统中即使有节点发生了故障,剩余超过「半数」的节点状态正常,依旧可以提供正确的结果,也就是说,这个算法还兼容了存在故障节点的情况。 共识算法在分布式系统领域有很多,例如 Paxos、Raft,哨兵选举领导者这个场景,使用的是 Raft 共识算法,因为它足够简单,且易于实现。 现在,我们用多个哨兵共同监测 Redis 的状态,这样一来,就可以避免误判的问题了,架构模型就变成了这样: 好了,到这里我们先小结一下。 你的 Redis 从最简单的单机版,经过数据持久化、主从多副本、哨兵集群,这一路优化下来,你的 Redis 不管是性能还是稳定性,都越来越高,就算节点发生故障,也不用担心了。 你的 Redis 以这样的架构模式部署,基本上就可以稳定运行很长时间了。 随着时间的发展,你的业务体量开始迎来了爆炸性增长,此时你的架构模型,还能够承担这么大的流量吗? 我们一起来分析一下: 稳定性:Redis 故障宕机,我们有哨兵 + 副本,可以自动完成主从切换 性能:读请求量增长,我们可以再部署多个 slave,读写分离,分担读压力 性能:写请求量增长,但我们只有一个 master 实例,这个实例达到瓶颈怎么办? 看到了么,当你的写请求量越来越大时,一个 master 实例可能就无法承担这么大的写流量了。 要想完美解决这个问题,此时你就需要考虑使用「分片集群」了。 分片集群:横向扩展 什么是「分片集群」? 简单来讲,一个实例扛不住写压力,那我们是否可以部署多个实例,然后把这些实例按照一定规则组织起来,把它们当成一个整体,对外提供服务,这样不就可以解决集中写一个实例的瓶颈问题吗? 所以,现在的架构模型就变成了这样: 现在问题又来了,这么多实例如何组织呢? 我们制定规则如下: 每个节点各自存储一部分数据,所有节点数据之和才是全量数据 制定一个路由规则,对于不同的 key,把它路由到固定一个实例上进行读写 而分片集群根据路由规则所在位置的不同,还可以分为两大类: 客户端分片 服务端分片 客户端分片指的是,key 的路由规则放在客户端来做,就是下面这样: 这个方案的缺点是,客户端需要维护这个路由规则,也就是说,你需要把路由规则写到你的业务代码中。 如何做到不把路由规则耦合在业务代码中呢? 你可以这样优化,把这个路由规则封装成一个模块,当需要使用时,集成这个模块就可以了。 这就是 Redis Cluster 的采用的方案。 Redis Cluster 内置了哨兵逻辑,无需再部署哨兵。 当你使用 Redis Cluster 时,你的业务应用需要使用配套的 Redis SDK,这个 SDK 内就集成好了路由规则,不需要你自己编写了。 再来看服务端分片。 这种方案指的是,路由规则不放在客户端来做,而是在客户端和服务端之间增加一个「中间代理层」,这个代理层就是我们经常听到的 Proxy。 而数据的路由规则,就放在这个 Proxy 层来维护。 这样一来,你就无需关心服务端有多少个 Redis 节点了,只需要和这个 Proxy 交互即可。 Proxy 会把你的请求根据路由规则,转发到对应的 Redis 节点上,而且,当集群实例不足以支撑更大的流量请求时,还可以横向扩容,添加新的 Redis 实例提升性能,这一切对于你的客户端来说,都是透明无感知的。 业界开源的 Redis 分片集群方案,例如 Twemproxy、Codis 就是采用的这种方案。 分片集群在数据扩容时,还涉及到了很多细节,这块内容不是本文章重点,所以暂不详述。 至此,当你使用分片集群后,对于未来更大的流量压力,都可以从容面对了! 总结 好了,我们来总结一下,我们是如何一步步构建一个稳定、高性能的 Redis 集群的。 首先,在使用最简单的单机版 Redis 时,我们发现当 Redis 故障宕机后,数据无法恢复的问题,因此我们想到了「数据持久化」,把内存中的数据也持久化到磁盘上一份,这样 Redis 重启后就可以从磁盘上快速恢复数据。 在进行数据持久化时,我们又面临如何更高效地将数据持久化到磁盘的问题。之后我们发现 Redis 提供了 RDB 和 AOF 两种方案,分别对应了数据快照和实时的命令记录。当我们对数据完整性要求不高时,可以选择 RDB 持久化方案。如果对于数据完整性要求较高,那么可以选择 AOF 持久化方案。 但是我们又发现,AOF 文件体积会随着时间增长变得越来越大,此时我们想到的优化方案是,使用 AOF rewrite 的方式对其进行瘦身,减小文件体积,再后来,我们发现可以结合 RDB 和 AOF 各自的优势,在 AOF rewrite 时使用两者结合的「混合持久化」方式,又进一步减小了 AOF 文件体积。 之后,我们发现尽管可以通过数据恢复的方式还原数据,但恢复数据也是需要花费时间的,这意味着业务应用还是会受到影响。我们进一步优化,采用「多副本」的方案,让多个实例保持实时同步,当一个实例故障时,可以手动把其它实例提升上来继续提供服务。 但是这样也有问题,手动提升实例上来,需要人工介入,人工介入操作也需要时间,我们开始想办法把这个流程变得自动化,所以我们又引入了「哨兵」集群,哨兵集群通过互相协商的方式,发现故障节点,并可以自动完成切换,这样就大幅降低了对业务应用的影响。 最后,我们把关注点聚焦在如何支撑更大的写流量上,所以,我们又引入了「分片集群」来解决这个问题,让多个 Redis 实例分摊写压力,未来面对更大的流量,我们还可以添加新的实例,横向扩展,进一步提升集群的性能。 至此,我们的 Redis 集群才得以长期稳定、高性能的为我们的业务提供服务。 这里我画了一个思维导图,方便你更好地去理解它们之间的关系,以及演化的过程。 后记 看到这里,我想你对如何构建一个稳定、高性能的 Redis 集群问题时,应该会有自己的见解了,Redis实战学习笔记+面试视频+面试真题,其实,这篇文章所讲的优化思路,围绕的主题就是「架构设计」的核心思想: 高性能:读写分离、分片集群 高可用:数据持久化、多副本、故障自动切换 易扩展:分片集群、横向扩展 当我们讲到哨兵集群、分片集群时,这还涉及到了「分布式系统」相关的知识: 分布式共识:哨兵领导者选举 负载均衡:分片集群数据分片、数据路由 当然,除了 Redis 之外,对于构建任何一个数据集群,你都可以沿用这个思路去思考、去优化,看看它们到底是如何做的。 例如当你在使用 MySQL 时,你可以思考一下 MySQL 与 Redis 有哪些不同?MySQL 为了做到高性能、高可用,又是如何做的?其实思路都是类似的。 我们现在到处可见分布式系统、数据集群,我希望通过这篇文章,你可以理解这些软件是如何一步步演化过来的,在演化过程中,它们遇到了哪些问题,为了解决这些问题,这些软件的设计者设计了怎样的方案,做了哪些取舍? 你只要了解了其中的原理,掌握了分析问题、解决问题的能力,这样在以后的开发过程中,或是学习其它优秀软件时,就能快速地找到「重点」,在最短的时间掌握它,并能在实际应用中发挥它们的优势。 其实这个思考过程,也是做「架构设计」的思路。在做软件架构设计时,你面临的场景就是发现问题、分析问题、解决问题,一步步去演化、升级你的架构,最后在性能、可靠性方面达到一个平衡。虽然各种软件层出不穷,但架构设计的思想不会变,我希望你真正吸收的是这些思想,这样才可以做到以不变应万变。

优秀的个人博客,低调大师

数据分析干货 | 留存率模型应该怎么搭建

几乎所有的业务数据分析和运营工作都是围绕着“拉新”、“留存”、“促活”、“转化”4个环节来开展的。 我们常常面临这样的问题,好不容易拉进来一批用户,玩着玩着就都流失了,更别谈转化和变现了。 所以,弄明白“留存率”非常重要,它是衡量产品质量、运营效果的重要指标,也是预估产品盈利能力的重要参考! 一、“留存率”是什么? 留存率,留的都是活跃用户(Active User),具体的讲,就是指某一时间段内完成了某种特定行为的用户。例如某内容平台,可以参考打开次数、使用时长、互动情况、内容产出量来制定自己的标准。需要注意的是,单个用户可能多次完成特定行为,统计时需要按照用户维度去重,即只算为1个用户。 举个例子,某天进来一批新用户,有的用了一下就再也没回来过,有的继续用过几次后也离开了,还有些在一定时间段里,能够一直持续活跃使用,这些一直保持活跃的我们称之为留存用户。留存用户占这批次新增用户的比例,就是留存率。 考量留存的时间, 一般会有次日、第7日、第30日型等 ,分别对应着次日留存率、第7日留存率、第30日留存率。还有按整周、整月的留存率计算形式,比如次月留存率等。 (7日留存和周留存容易混淆,举个例子说清楚:假如1月1日新增100人,其中20人在1月8日依然活跃,则7日留存是20%,即7日留存是指第一天新增用户在七天后活跃的人数;假如1月1日到第1月7日共新增1000人,其中300人在1月8日到1月14日之间依然活跃,那么周留存就是30%,即周留存是第一周新增总用户在第二周活跃的人数。) 根据现有的用户留存数量,就可以算出留存率,而根据留存率,又可以预测产品未来的活跃用户量。 作为一名运营,不要简单地以为用户拉进来就算是你的用户了,也不要总把「用户总数」作为洋洋自得的指标, 而应该更关注活跃用户数和留存率。 因为,只有真正活跃的用户,才能产生商业价值。 二、留存率模型 搞清留存率,本文将祭出一大法宝——「以留存率为基础的产品盈利模型」。 1.模型1.0 在1.0版本里,留存率只是个初步模型:(其实就是一个加法公式) 此模型说明了活跃用户数来源于「阶段内新增用户」加上「以往每个阶段的留存用户」。举个例子,假如要算7天的留存用户,那么第7天的活跃总用户数 = 第7天的新增用户数 + 第6天的新增用户数 x 第1天的留存率 + 第5天的新增用户数 x 第2天的留存率 + …… + 第1天的新增用户数 x 第6天的留存率。假如按周、月算,也是一样的道理,所以简单说来, 这个模型就是把每个阶段的留存人数相加的结果。 我们用案例再来解释一下: 比如,某产品7月1日的活跃用户量为500,然后拉取这500人接下来7天的每日活跃数,就可以计算出该产品7天的留存率: (当天留存率 = 该批次剩余活跃用户数 / 7月1日活跃用户量) 这样,我们就得出了产品的阶段留存率。然后我们可以依据这个留存率来计算每日自然新增的每日留存了,如果7月1日当天的新增用户为1400人,可以继续计算: (当天剩余活跃用户量 = 当天留存率 * 7月1日新增用户量) 因此,我们就初步得到了7月1日这批用户在接下来几天里的活跃数变化情况。当然现实情况是每天都有新增用户,因此我们可以计算每天新增用户的留存率,再把历史留存都加起来,就得到了每天的总留存。 假如7月1日新增用户为500人,并且每日稳定增长500人,那么根据留存率,可以算出7月7日的活跃用户总数: 2.模型2.0 一旦可以算出未来的活跃用户数量,我们就可以粗略的计算未来的收益、销售额等数据。 而这个模型可以继续优化,增加更多参数,使得计算结果更加接近真实情况。 需要注意的是,影响模型结果的因素很多,考虑的越多,模型就越接近于真实情况,精确度就越高。但同时,因素与因素之间也会互相影响,增加了模型的复杂程度,计算的需要的时间会增加,计算的结果也会更加难以得出。使用模型时,请仔细思考这两点的平衡性。 那么问题来了,现实中有哪些因素需要考虑?哪些可以增加到这个模型中? 1.用户来自不同渠道,因此不同渠道需使用不同的留存率; 2.随着运营活动的开展,每月自然新增也会产生变化; 3.很多产品每月会做付费推广,这其中需要考虑到推广的转化率; 4.推广及活动吸引来的用户的留存率,可能和自然新增的用户留存率不同;5.考虑到用户生命周期,历史存量用户会有固定的流失率; 6.总活跃用户中,有一定比例的付费率; 7.随着产品价值的提升,新增用户的付费转化率每月会增长; 8.随着产品的精细运营,单个用户在生命周期内的消费能力会逐渐递增; 9.还可以根据人均贡献率预估出总收益; …… 好了,如果把这些参数都添加进去,这个模型已经相当复杂了。但是只要公式正确,结果总归会趋近于真实情况的。 尽管你可能一时看不懂,但是我们还是YY了一个产品,YY了一些数据,把它的成本测算和收益预估做出来了。 可以看出,iOS渠道和安卓渠道分开计算了,并且添加了历史存量用户流失(10%)、每月自然新增逐月递增2%几个参数,重要的是,添加了付费推广的转化率和成本。 有了两个渠道的用户、成本后,就可以算更多数据了!先把总成本算出来(蓝底部分),再算用户数据(绿底部分),再然后,可以添加自己的转化数据(黄底部分)进行测算了!GMV都能算出来! 注意最后一行的红底部分,如果添加了KPI,就可以直接知道是否需要调整策略了! 当然,这里面的所有数据都是我胡诌的,你要是真以为我们11月可以做到近2000万GMV,那你真是可爱极了。 三、这个模型究竟有什么用呢? 主要有2大方面: 1.对于初创产品,可以预估产品的盈利时间,及时调整策略 对于初创产品,无论是老板、产品经理还是运营,最怕的除了产品功能不稳定,就是用户不稳和收益不清晰了,有了这个表,就可以轻松测算了。 2.拆分各个参数的KPI 对于已经过了启动阶段的产品,可以根据目标KPI,直观的看到当前运营状态下未来的结果,如果达不到目标,就要及时调整了。更重要的是,可以制定各渠道、付费率、客单价、总成本的KPI,拆分后就轻松多了。 在提升留存的方式上,不存在一个万能的方法,一用就马上能把产品的留存提高,我们更应该关注的是,产品本身是不是很好地满足了用户的需求。而留存率不高,95%的原因是产品本身的需求没有解决好。 更多精彩文章 1、汇总版|最全数据分析资料汇总(趣味Python、商业数据分析、爬虫等等) 2、PanDownload复活了!60MB/s! 3、商业数据可视化工具,能做到极致方便的也只有 Tableau 了! 4、付费?是不可能的!处理 PDF 只需几行代码,彻底解放双手! 目前群已满2000+人,旨在促进技术交流,可申请加入细分方向技术群,细分方向已涵盖:Python、数据分析、爬虫、算法、视频号(新增),已在群内成员请勿重复申请。一定要备注:研究方向+学校/公司(如数据分析+上交),根据格式备注,可更快被通过且邀请进群 ▲长按加微信群 ▲长按关注公众号 本文分享自微信公众号 - Python学习与数据挖掘(Python_CaiNiao)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

阿里云服务器基于 CentOS 搭建 Discuz 论坛

首先你需要一台阿里云服务器 地址:https://www.aliyun.com/minisite/goods一、准备 LAMP 环境LAMP 是 Linux、Apache、MySQL 和 PHP 的缩写,是 Discuz 论坛系统依赖的基础运行环境。我们先来准备 LAMP 环境安装 MySQL使用 yum 安装 MySQL: yum install mysql-server -y 安装完成后,启动 MySQL 服务: service mysqld restart 此实验使用 mysql 默认账户名和密码,您也可以设置自己的 MySQL 账户名和密码:[?],参考下面的内容: /usr/bin/mysqladmin -u root password 'Password' 将 MySQL 设置为开机自动启动: chkconfig mysqld on 下面命令中的密码是教程为您自动生成的,为了方便实验的进行,不建议使用其它密码。如果设置其它密码,请把密码记住,在后续的步骤会使用到。 安装 Apache 组件使用 yum 安装 Apache 组件: yum install httpd -y 安装之后,启动 httpd 进程 service httpd start 把 httpd 也设置成开机自动启动: chkconfig httpd on 安装 PHP使用 yum 安装 PHP:[?] yum install php php-fpm php-mysql -y 安装之后,启动 PHP-FPM 进程: service php-fpm start 启动之后,可以使用下面的命令查看 PHP-FPM 进程监听哪个端口 [?] netstat -nlpt | grep php-fpm 把 PHP-FPM 也设置成开机自动启动: chkconfig php-fpm on CentOS 6 默认已经安装了 PHP-FPM 及 PHP-MYSQL,下面命令执行的可能会提示已经安装。 PHP-FPM 默认监听 9000 端口 二、安装并配置 Discuz安装 DiscuzCentOS 6 没有Discuz 的 yum 源,所以我们需要下载一个Discuz 压缩包:[?] wget http://download.comsenz.com/DiscuzX/3.2/Discuz_X3.2_SC_UTF8.zip 下载完成后,解压这个压缩包 unzip Discuz_X3.2_SC_UTF8.zip 解压完后,就能在 upload 文件夹里看到discuz的源码了 到Discuz官网找一个安装包并复制安装包下载路径,这里我们用 Discuz_X3.2_SC_UTF8.zip配置 Discuz由于PHP默认访问 /var/www/html/ 文件夹,所以我们需要把upload文件夹里的文件都复制到 /var/www/html/ 文件夹 cp -r upload/* /var/www/html/ 给 /var/www/html 目录及其子目录赋予权限 chmod -R 777 /var/www/html 重启 Apache service httpd restart 三、准备域名和证书域名注册如果您还没有域名,可以在阿里云上选购 地址:。域名解析域名购买完成后, 需要将域名解析到ip领个阿里云代金券:https://www.aliyun.com/minisite/goods

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册