块存储、文件存储和对象存储

块存储 典型设备:磁盘阵列、硬盘 块存储主要是将裸磁盘空间整个映射给主机使用的,就是说例如磁盘阵列里面有5块硬盘(为方便说明,假设每个硬盘1G),然后可以通过划逻辑盘、做Raid、或者LVM(逻辑卷)等种种方式逻辑划分出N个逻辑的硬盘。(假设划分完的逻辑盘也是5个,每个也是1G,但是这5个1G的逻辑盘已经于原来的5个物理硬盘意义完全不同了。例如第一个逻辑硬盘A里面,可能第一个200M是来自物理硬盘1,第二个200M是来自物理硬盘2,所以逻辑硬盘A是由多个物理硬盘逻辑虚构出来的硬盘。) 接着块存储会采用映射的方式将这几个逻辑盘映射给主机,主机上面的操作系统会识别到有5块硬盘,但是操作系统是区分不出到底是逻辑还是物理的,它一概就认为只是5块裸的物理硬盘而已,跟直接拿一块物理硬盘挂载到操作系统没有区别的,至少操作系统感知上没有区别。 此种方式下,操作系统还需要对挂载的裸硬盘进行分区、格式化后,才能使用,与平常主机内置硬盘的方式完全无异。 优点: 这种方式的好处当然是因为通过了Raid与LVM等手段,对数据提供了保护。 另外也可以将多块廉价的硬盘组合起来,成为一个大容量的逻辑盘对外提供服务,提高了容量。 写入数据的时候,由于是多块磁盘组合出来的逻辑盘,所以几块磁盘可以并行写入的,提升了读写效率。 很多时候块存储采用SAN架构组网,传输速率以及封装协议的原因,使得传输速度与读写速率得到提升。 缺点: 采用SAN架构组网时,需要额外为主机购买光纤通道卡,还要买光纤交换机,造价成本高。 主机之间的数据无法共享,在服务器不做集群的情况下,块存储裸盘映射给主机,再格式化使用后,对于主机来说相当于本地盘,那么主机A的本地盘根本不能给主机B去使用,无法共享数据。 不利于不同操作系统主机间的数据共享:另外一个原因是因为操作系统使用不同的文件系统,格式化完之后,不同文件系统间的数据是共享不了的。例如一台装了WIN7/XP,文件系统是FAT32/NTFS,而Linux是EXT4,EXT4是无法识别NTFS的文件系统的。就像一只NTFS格式的U盘,插进Linux的笔记本,根本无法识别出来。所以不利于文件共享。 文件存储 典型设备:FTP、NFS服务器 为了克服上述文件无法共享的问题,所以有了文件存储。 文件存储也有软硬一体化的设备,但是其实普通拿一台服务器/笔记本,只要装上合适的操作系统与软件,就可以架设FTP与NFS服务了,架上该类服务之后的服务器,就是文件存储的一种了。 主机A可以直接对文件存储进行文件的上传下载,与块存储不同,主机A是不需要再对文件存储进行格式化的,因为文件管理功能已经由文件存储自己搞定了。 优点: 造价交低:随便一台机器就可以了,另外普通以太网就可以,根本不需要专用的SAN网络,所以造价低。 方便文件共享:例如主机A(WIN7,NTFS文件系统),主机B(Linux,EXT4文件系统),想互拷一部电影,本来不行。加了个主机C(NFS服务器),然后可以先A拷到C,再C拷到B就OK了。(例子比较肤浅,请见谅……) 缺点: 读写速率低,传输速率慢:以太网,上传下载速度较慢,另外所有读写都要1台服务器里面的硬盘来承担,相比起磁盘阵列动不动就几十上百块硬盘同时读写,速率慢了许多。 对象存储 典型设备:内置大容量硬盘的分布式服务器 对象存储最常用的方案,就是多台服务器内置大容量硬盘,再装上对象存储软件,然后再额外搞几台服务作为管理节点,安装上对象存储管理软件。管理节点可以管理其他服务器对外提供读写访问功能。 之所以出现了对象存储这种东西,是为了克服块存储与文件存储各自的缺点,发扬它俩各自的优点。简单来说块存储读写快,不利于共享,文件存储读写慢,利于共享。能否弄一个读写快,利于共享的出来呢。于是就有了对象存储。 首先,一个文件包含了了属性(术语叫metadata,元数据,例如该文件的大小、修改时间、存储路径等)以及内容(以下简称数据)。 以往像FAT32这种文件系统,是直接将一份文件的数据与metadata一起存储的,存储过程先将文件按照文件系统的最小块大小来打散(如4M的文件,假设文件系统要求一个块4K,那么就将文件打散成为1000个小块),再写进硬盘里面,过程中没有区分数据/metadata的。而每个块最后会告知你下一个要读取的块的地址,然后一直这样顺序地按图索骥,最后完成整份文件的所有块的读取。 这种情况下读写速率很慢,因为就算你有100个机械手臂在读写,但是由于你只有读取到第一个块,才能知道下一个块在哪里,其实相当于只能有1个机械手臂在实际工作。 而对象存储则将元数据独立了出来,控制节点叫元数据服务器(服务器+对象存储管理软件),里面主要负责存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息),而其他负责存储数据的分布式服务器叫做OSD,主要负责存储文件的数据部分。当用户访问对象,会先访问元数据服务器,元数据服务器只负责反馈对象存储在哪些OSD,假设反馈文件A存储在B、C、D三台OSD,那么用户就会再次直接访问3台OSD服务器去读取数据。 这时候由于是3台OSD同时对外传输数据,所以传输的速度就加快了。当OSD服务器数量越多,这种读写速度的提升就越大,通过此种方式,实现了读写快的目的。 另一方面,对象存储软件是有专门的文件系统的,所以OSD对外又相当于文件服务器,那么就不存在文件共享方面的困难了,也解决了文件共享方面的问题。 所以对象存储的出现,很好地结合了块存储与文件存储的优点。 最后为什么对象存储兼具块存储与文件存储的好处,还要使用块存储或文件存储呢? 有一类应用是需要存储直接裸盘映射的,例如数据库。因为数据库需要存储裸盘映射给自己后,再根据自己的数据库文件系统来对裸盘进行格式化的,所以是不能够采用其他已经被格式化为某种文件系统的存储的。此类应用更适合使用块存储。 对象存储的成本比起普通的文件存储还是较高,需要购买专门的对象存储软件以及大容量硬盘。如果对数据量要求不是海量,只是为了做文件共享的时候,直接用文件存储的形式好了,性价比高。

May 18, 2021 · 1 min · Egbert Ke

文件怎么在不同的文件系统间转存

文件 文件是一堆有特定格式的数据,在硬盘中由一堆特定顺序的磁盘块组成。 文件系统 文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。 同一个文件,文件内容肯定相同,放在不同的文件系统中,不同的是文件内容的存放方式。 when a file is copied between different filesystem types, the content isn’t changed, only the way the file is written to disk. 举个具体的例子,本机磁盘有两个分区,格式化成不同的文件系统,当把一个文件从其中一个分区拷贝到另一个分区时,完全可以,文件内容一样,不同的是文件在磁盘中的组织方式,而且这种组织方式的不同对用户是透明的,我们只需要关注文件内容和格式本身,不需要关注文件所处的文件系统。

May 18, 2021 · 1 min · Egbert Ke

软件制图方法

前言 “架构制图”这词乍一听似乎有些晦涩,但如果提起“工程制图”,相信绝大部分工科背景的程序员们都不会陌生,甚至还能共同感慨下那些年一起伏在宿舍左手圆规,右手直尺,徒手作图到深夜的日子。 软件工程也是工程,因此传统工程制图的一些基本理论,在软件行业同样适用。但另一方面,软件与实体制造业之间还是有着本质区别,所以在制图方面的需求和方式也大相径庭,无法直接套用。作为软件行业的从业者,你可以完全不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。 本文在后半段将介绍如何用图去描述(describe)和传达(communicate)你的架构设计。值得强调的是,本文并不会侧重于单一的方法和工具,而是更希望关注那些优秀方法背后的通用方法论,即架构制图的本质、共性和最佳实践。希望本文能起到引子作用,激发大家对自己日常工作中关于架构和制图部分的关注、审视与思考;如果还真能帮助大家提升一点点制图效率和效果,那就更好不过了。 什么是软件架构? 1. 软件架构定义 IEEE 给出的定义:架构是环境中该系统的一组基础概念(concepts)和属性(properties),具体表现就是它的元素(elements)、关系(relationships),以及设计与演进的基本原则(principles)。 CMU 软件工程研究院的定义:架构是用于推演出该系统的一组结构(structures),具体是由软件元素(elements)、元素之间的关系(relationships),以及各自的**属性(properties)**共同组成。 Uncle Bob 在 Clean Architecture 一书中给出的定义:架构是创建者给予该系统的形态(shape)。这个形态的具体形式来源于对系统组件(components)的划分和排列,以及这些组件之间互相通讯的方式。 2. 架构核心要素 综合上述各种权威定义,软件系统的架构通常需要包含如下四类核心要素: 元素(elements):将系统拆分为一组元素 - 模块、组件、结构体、子系统; 关系(relationships):不同元素之间的关系 - 交互、依赖 、继承、组合、聚合; 属性(properties):每个元素具备的属性 - 名称、职责、接口、实现限制等; 原理(principles):为什么这么设计 - 拆分依据、设计原则、决策原因等。 为什么架构很重要? 1. 架构是系统实现的蓝图 最近有部很火的网剧叫《摩天大楼》,讲述了一段匪夷所思的悬疑故事。为什么扯这个呢?因为我想借用这个剧的标题来问个问题:摩天大楼是由谁建起来的?也许你心里会默念:废话,不就是建筑工人们一砖一瓦堆起来的嘛。仔细再想想?背后是不是还有一堆操碎了心的建筑设计师(比如剧中帅气的林大森)和土木工程师们?他们虽然不搬砖也不扛水泥,但如果没有他们产出的那些繁琐严谨的设计图纸,摩天大楼是是不可能像农村自建房一样仅凭工人们各自的经验与想象力就能快速平稳地竖立起来的。 正是靠着这些图纸所描绘出来的工程蓝图(blueprints),才让成百上千工人们的分工合作和验收标准有了依据:大家只需要照着蓝图,按部就班地把自己所负责的那些砖瓦添上去就行了;只要蓝图正确,且施工过程也没有偏差,最终顺利完工只是个时间问题。 与建筑、汽车或者任何其他工程行业一样,软件在落地实现(编码)之前也需要先有蓝图;而其中最重要的一份蓝图,就是架构设计。没有架构,仅凭程序员自己脑子里的模糊设想,也许你可以像传统手艺人一样独自创造出一些美好有用的小东西(比如 Linux 0.01 版本),但不太可能以工程的方式协同一个团队共同建造起一个与摩天大楼规模类似的复杂软件系统(比如现代的 Linux 系统)。一方面,人类的思维能力终归有限,必须依靠架构这种高度抽象和简化的蓝图,才能让复杂系统的创造、理解、分析和治理变得可行;另一方面,量级达到一定程度的大型系统,也只能依靠多人分工合作才能完成,而架构也正是多人沟通协作的重要基础。 2. 架构是沟通协作的基础 软件项目的最终价值产出就是软件系统,而架构作为软件系统的灵魂和骨架,可以起到如下作用: 理解对齐:所有软件系统的目的都是为了实现用户需求,但实现的途径有无限种可能性(相比传统工程行业,软件的灵活性更大、知识迭代更快)。架构设计就是去选择其中一条最合适的实现途径,因此其中会涉及非常多关键的选路决策(为什么要这么拆分?为什么选择 A 技术而不是 B?)。这些重要的技术决策需要通过架构描述这种形式被记录和同步,才能让项目组所有成员对整个系统的理解对齐,形成共识。 工作量化:项目管理最重要的步骤之一就是工时评估,它是确定项目排期和里程碑的直接依据。显然,只通过 PRD / 交互图是无法科学量化出项目工作量的,因为很难直观判断出一句简短需求或一个简单页面背后,究竟要写多少代码、实现起来难度有多大。有了清晰明确的架构之后,理论上绝大部分开发工作都能做到可见、可预测和可拆解,自然而然也就能够被更准确地量化。当然,精准的工作量评估在 IT 行业内也一直是个未解之谜,实际的工期会受太多未知因素影响,包括程序员的技能熟练度、心情好不好、有没有吃饱等。 标准术语:编程作为一种具有创造力的工作,从某种角度看跟写科幻小说是类似的。好的科幻小说都喜欢造概念,比如三体中的智子,如果没看过小说肯定不知道这是个啥玩意儿。软件系统在造概念这一点上,相比科幻小说只有过之而无不及,毕竟小说里的世界通常还是以现实为背景,而软件中的世界就全凭造物者(程序员)的想象(建模)了。稍微复杂一点的软件系统,都会引入一些领域特定甚至全新创作的概念。为了避免在项目过程中出现鸡同鸭讲的沟通障碍和理解歧义,就必须对描述这些概念的术语进行统一。而架构的一个重要目的,就是定义和解释清楚系统中涉及的所有关键概念,并在整个架构设计和描述过程中使用标准和一致的术语,真正做到让大家的沟通都在一个频道上。 言之有物:就跟讨论产品交互时需要对着原型图、讨论代码细节时需要直接看代码一样,架构是在讨论一些较高维技术问题时的必要实物(具体的实物化形式就是所谓架构描述)。否则,要么一堆人对着空气谈(纸上谈兵都说不上),要么每次沟通时都重新找块白板画一画(费时费力且容易遗落信息,显然不是长久之计)。 知识沉淀 & 新人培训:架构应该被作为与代码同等重要的文档资产持续沉淀和维护,同时也是项目新人快速理解和上手系统的重要依据。不要让你的系统跟公司内某些祖传遗留系统一样 —— 只有代码遗留了下来,架构文档却没有;只能靠一些口口相传的残留设计记忆,苦苦维系着项目的生命延续。 3. 架构决定了产品质量 如何衡量一个软件产品的质量?上图是 ISO/IEC 25010 标准定义的软件产品质量模型,包括以下 8 个大类:...

May 17, 2021 · 3 min · Egbert Ke

goroutine 记录

作者回复: 所以说不要用“协程”这个概念,因为“协程(coroutine)”指的是程序在同一个线程内的自行调度,是应用程序本身完全可控的。而 goroutine 的调度是 Go 语言的运行时系统发起的。 你不要揣测 Go 语言的调度器会怎样调度。你首先要知道哪些代码点是调度的时机(注意,到了调度时机也不一定发生调度,只是时机而已)。你还要知道如果想让多个 goroutine 按照你拟定的流程执行就需要用到 Channel 以及各种同步工具。 你说的“跳转到”只能在 coroutine 场景下才能这么说。在 goroutine 的场景下,没有“跳转”这么一说。 其一,你在上面的 for 语句中启用了一个 goroutine,你怎么就能断定后面的代码一定会先于这个 go 函数执行?不要做这种假设。因为连 goroutine 的调度都是并发的。 其二,两个 goroutine 一个 channel,一个 goroutine 发,一个 goroutine 取。这个 ch1 什么时候满、什么时候空,你基本上是确定不了的。因为两个 for 循环 在迭代的过程中都可能因被调用而换下 CPU。 其三,你要知道,几乎任何函数调用都存在调度时机,更何况是像 fmt.Println 这种需要 I/O 的重型操作。所以,为什么你那前一个 for 循环结束之后就不能被调度了呢? 以上是我通过你的文字表达猜测并回答的,并不一定完全匹配你要问的问题。还有问题的话再问我。 我觉得你对“并发”和“调度”这两个概念不清楚。我建议你好好看看专栏里讲 goroutine 的那几篇文章。有必要的话,买我的《Go 并发编程实战》第二版从头学一下。 研究下各种协程的实现,以及goroutine的实现

May 6, 2021 · 1 min · Egbert Ke

大厂晋升指南-职级详解

所有职级,能力可以分为3个维度,4个复杂度(COMD模型) P5 在别人的知道下做事,主要在技术和业务上,技术80% 业务20% P5 的核心能力要求是在别人的指导下完成任务,主要提升目标是从学生转变为“打工人”。 技术方面,P5 需要打好基础,学习岗位要求的基础技术。采用“碎片化时间,系统化学习”的方法提高你的技术学习效率。 业务方面,P5 需要熟悉各项业务功能的实现逻辑。对于 2C 业务,你要成为产品的深度用户;对于 2B 业务,你就要多跟客户交流。 管理方面,P5 的重点是熟悉项目流程,避免踩坑。你需要注意学习公司的管理制度。 P6 独挡一面 P6 的核心能力要求是独立负责端到端的项目任务,主要提升目标是成为独立自主的“项目能手”。 技术方面,P6 需要掌握团队用到的各种技术的“套路”,重点提升技术深度,学习时要避免贪多求全的心态,优先深入学习跟工作内容强相关的技术。 业务方面,P6 需要掌握某类业务相关的所有功能,并深度理解处理逻辑,主要的提升方法是“5W1H8C1D”分析法和竞品分析。 管理方面,P6 需要负责项目子任务推进,包括工作量评估、计划制定和沟通协调等。评估工作量的时候,建议使用 WBS 分解法,先拆解成容易评估的小任务,然后独立评估每项任务,最后汇总。 P7 P7 的核心能力要求是指挥单个团队达成目标,主要提升目标是成为让人信服的团队专家。 技术维度上,P7 需要精通团队相关的技术,重点提升技术宽度,主要提升方法是“比较学习法”。在这个阶段,你既要避免因为管理而丢掉技术,也要避免“生搬硬套”新技术。 业务维度上,P7 需要掌握业务整体情况,从用户特征、用户价值、获客方式和获利方式 4 个方面理解业务 6~12 个月的规划。对于 2C 业务,AARRR 漏斗模型是必须掌握的;对于 2B 业务,还应该了解行业强相关的手段和措施。 管理维度上,P7 需要负责指挥单个团队。对于担任 Team Leader 的 P7 来说,需要系统化地掌握管理的基本技能,避免事必躬亲或者做甩手掌柜;对于不是 Team Leader 的 P7 来说,要学会做一个靠谱的项目负责人。 P8 P8 的核心能力要求是指挥多个团队达成目标,主要提升目标是成为有影响力的领域专家。 技术维度上,P8 需要精通领域相关的技术,重点提升领域技术宽度,可以通过研究开源项目和参加技术大会来拓宽自己的技术宽度,也可以在技术大会上做主题演讲来提升自己的影响力。 业务维度上,P8 需要熟悉多个业务,并且开始需要掌握战略规划相关的技能,以帮助自己理解业务整体规划,可以采取“宝洁战略模型”的方法快速提升自己的业务理解力。 管理维度上,P8 需要负责指挥多个团队,提升自己管理技能的核心是学会抓住三个管理重点:搭建团队梯队,参与目标制定,关注技术演进。 P9 P9 的核心能力要求是导演成熟作品,主要提升目标是成为跨领域整合的业务导演。 技术维度上,P9 需要具备跨领域整合的能力,重点提升领域技术广度,可以通过环式学习法来提升自己的技术广度,通过关注和跟进新技术来提升自己的创新能力。...

May 4, 2021 · 1 min · Egbert Ke

来自极客时间的评论:认知天性:让学习变得轻而易举的心理学规律

这本书介绍了各种高效学习的方法,其中有几种方法,比较颠覆认知,书中认为学习时,应该有间隔的进行,而非集中式的重复进行,这样带来的好处是:能带来更长久的记忆,也就是长期记忆,而集中式练习则是短期记忆。花十分钟记忆十个单词所留存的记忆,不如分两次五分钟记忆十个单词所留存的记忆来得深刻。理由是:长期记忆的形成,需要有个巩固的过程,可能是数小时,可能是数天,在这期间,记忆痕迹得到加深,所学的新知识与旧知识建立连接,带来稳固的长期记忆,因此不要频繁的进行集中式学习,而是有间隔的进行,频繁的集中练习只会带来短期记忆,有间隔的学习所耗费的精力远大于频繁的重复式学习,使用这种方式,学习起来也更加困难,但也不容易遗忘。理论上来说,遗忘的越多,重新回忆起来的难度越大,但所保持的效果越持久,不过,还是不要等到所学知识遗忘的差不多了后再去重新学习,那样的话,你基本回忆不起来,只能重新从头开始,得不偿失,等到所学知识有点儿遗忘再去学会比较好。 拿学习专栏来说,不要反复地去学习同一章节,而是有间隔地进行,这会带来长期记忆,在学完一章内容后,不要立刻练习所学内容,而是应该等遗忘一些后进行,效果要好于学完一章节后立刻进行练习的方式,学完后不容易忘,在学完后立刻进行练习,学完后容易忘。书中建议:学习知识或技能时,通过自我检测的方式,代替重复学习,并且有间隔地进行自测,就拿学习算法来说,不要一遍接一遍地重复去学,而应该在学习完某一算法后,通过自测的方式来逼迫自己的大脑去检索所学,拒绝机械式的重复重复再重复,这样所学的知识会更加稳固,留存的记忆更持久,书中还提到:自我检测后的延迟反馈会进一步加强学习效果,也就是在进行自测后,不要立马查看答案,而是应该间隔一段时间再查看。 在练习所学时,有顺序的练习比无顺序的练习效果差,且这期间,穿插不同类容类型的学习方式,所产生的效果,要比在熟练某一知识后,再进入下一学习内容的练习效果要好,不仅能保持长久的记忆,使所学知识不易遗忘,还能提高学习者的辨识能力,也就是在面对各种复杂问题时,能正确识别问题类型,根据所学知识,从脑海中搜寻出对应问题的解决方案。回想一下我们上学时的课本内容安排,都是有顺序地,由浅入深地进行,而我们在学习时,就是通过不断练习同一知识点直至完全掌握后,依次有顺序地进入下一知识点的学习,直到课程学完。这种通过大量练习同一类型的题目的方式,使我们在考试遇到时,能得心应手地解决,但面对综合题时,这些问题都被混合在了一起,且没有顺序,我们难以辨别题目真正要考察什么问题,无法辨别问题的类型,从而无法正确地运用所学知识解决问题。拿到生活上来说,你遇到的问题也是没有顺序,且都是混合在一起的,你难以辨别各个问题之间的差异,不清楚要解决的问题到底是什么,从而无法选取合适的解决方案解决问题。 面对这种现状,前面提到的穿插不同内容类型的学习方式能帮到你。简单来说,就是在当前学习内容掌握的还不熟练的情况下,跳入下一阶段的学习,这种方式比在当前学习内容练习熟练后,再顺序进入下一阶段的学习方式,效果要好。例如,你在学完数组,哈希表,树,堆等数据结构后,在练习时,要在数组还未掌握熟练时,就进入树的练习,而不是等到完全掌握熟练一项内容才进入下一阶段的练习,你不能每学一样知识,待熟练后才进入下一阶段,应该以随机非顺序的方式进行,这种非顺序的穿插不同类型的学习方式能促进知识的活学活用。 这种学习方式如果转换到专栏学习的话,相当于在一个章节内容还未熟练的情况下就要进入下一章节的学习,比如,在学习完专栏章节1,2,3后,从章节2开始练习,待初步掌握,还未熟练时,进入章节1的练习,然后在未熟练时又进入章节2的学习,这种在练习期间,穿插各种不同学习内容的方式,比大量练习同一主题内容完全熟练后,再进入别的主题学习,效果要好得多,书中说的是远好于。 这样看来,这种学习方式还是很适合学习难度高的专业知识的,它能使所学知识停留在长期记忆,并能促进知识的活学活用,你一定不想体会辛辛苦苦好不容易学完算法后,在下一次要用到时想不起来的尴尬境地,或者在遇到综合各种算法问题时,束手无措的苦苦挣扎,而以上的学习方式或许能帮到你。 总结: 间隔进行,更容易形成长期记忆 不能每学一样知识,待熟练后才进入下一阶段,应该以随机费顺序的方式进行。 有点道理阿。

May 4, 2021 · 1 min · Egbert Ke

了解微型创业

最近听了一场知乎live,讲的是微型创业,在此记录一下。 理解小众市场 微型创业首先是小,面向的是小众市场,一两个人就可以搞定。小的特点,就是成本低,灵活,针对性强,能解决特定问题。 如何发现/选择小众市场 发现需求而不是创造需求,发现需求就成功了一半 1.画个圈圈型 从自身爱好出发,有一双善于发现的眼睛,加上别有用心一点。 2.望远镜型 善于利用工具,利用微信指数了解热点,市场的变化。谷歌趋势,百度指数。 利用谷歌关键词发现市场,用谷歌搜索Instagram 发现关键词 Instagram download pictures, 继续谷歌,点开排名第一的网站,输入图片链接地址就可以下载下来。盈利方式就是谷歌的ad scene广告系统,每年人民币20w. 网上的资源和开源的工具都很多,如果你足够机智,肯定能用好网上的工具。 3.犀牛鸟型 共生关系,国际国内大象级app很多,微信、Facebook,YouTube,有人做微信机器人的额产品收入非常可观,通过机器人管理微信群消息。github搜索wxbot,找到相关代码资源。比如YouTube的视频转gif动图链接,每个月700万流量,7000美元一个月,YouTube mp3.org 输入视频提取音频,技术难度没有,月流量2.7亿,270万美元。这种做大象周边小众市场的例子还有很多,只要你多琢磨琢磨,一刀切进去肯定是有肉吃的。 4.总在河边走型 想做某个市场但是不懂,先勇敢地跳进去,然后再深入。比如跨境电商,赚差价。比如区块链,很多小白不懂区块链,但是需求很大,如果深入研究把东西教给大家。 验证需求 MVP 简单落地页 广告投放 重点:市场比你的产品要重要的多,一个没有市场的软件应用仅仅是个产品而已,大部分开发人员都是有个点子,花了几个月把产品做出来,结果发现没有人购买。这样的产品,即使花再大的力气也没什么卵用,产品成功的最重要因素,不是人,不是市场的运营也不是产品,而是 是否有一群人愿意付费购买。所以在确定不是伪需求之前一定要上个线,走两步,验证需求的第一步,mvp,就是最小化可行性产品,开发产品时最好先做一个原型。通过测试收集用户的反馈,快速迭代,最终适应市场的需求。做个独立页面,是否有用户原因购买,不需要开发完成。 营销和流量 建立跟踪,底层最重要的是数据,前提是建立好数据的跟踪。 最初的推广 Reddit Product Hunt v2ex 一定要和用户建立联系 浏览页面时弹出层,留下优享,数据证明非常有效 SEO 一定要优化,兵家必争之地,SEO做好会产生长期价值,时间长了会发现,每天的稳定流量大部分来自SEO,对于程序员没什么难度,认真做好每个细节就好。

April 30, 2021 · 1 min · Egbert Ke

长连接和短连接

首先,连接指的是传输层的TCP连接 连接就是连接,没有长短之说 是长是短取决于你是否关闭连接 建立连接后进行一次读写就马上关闭,这条连接对你来说就是短连接,如HTTP0.9, HTTP 1.0(默认关闭,支持Keep-Alive)就是这样 HTTP 1.1协议的headers中默认有Connection: Keep-Alive,告诉HTTP服务器不要关闭连接,后续的HTTP请求继续用这条连接,那这条连接对你来说就是一条长连接 另外,socket的SO_KEEPALIVE选项跟http中的Keep-Alive是完全不同的东西,前者是服务器在一条连接至少空闲2小时后发送探活包检测客户端是否还有响应,意在检测半开连接并关闭,后者前文应该已经说明白了。

April 30, 2021 · 1 min · Egbert Ke

使用Privoxy转发http到socks

国内服务器ping不通github,正好有一台香港的socks server,如果可以将http转发到这台server,问题就解决了。 privoxy是一款不进行网页缓存且自带过滤功能的代理服务器,针对http、https协议。通过其过滤功能,用户可以保护隐私、对网页内容进行过滤、管理Cookie,以及拦阻各种广告等。1 privoxy官网 大概意思是从http协议到其他协议的转换,另外可以做一些http内容的过滤、修改等。 安装privoxy(ubuntu) apt-get install privoxy 默认privoxy服务已经通过systemctl管理,systemctl status/stop/start privoxy查看/停止/启动privoxy 配置文件在/etc/privoxy/config 在文件末尾加上forward-socks5 / host:port . 将host:port替换成你的socks local server 最后按个.表示转发到socks server之后不用再转发到某个http server了 如果想这个privoxy服务可以被外部访问的话,比如本机通过这个privoxy进行科学上网,可以将配置文件中listen-address 的localhost改成0.0.0.0 最后,重启服务: systemctl restart privoxy https://zh.wikipedia.org/wiki/Privoxy ↩︎

April 29, 2021 · 1 min · Egbert Ke

Java传递函数实现懒执行

看下面这个方法: public static JSONObject call(byte[] img, String algName, String algUrl) { long startTime = System.currentTimeMillis(); try { HttpResponse resp = OkHttpUtil.post(algUrl, MediaType.parse("application/octet-stream"), img, connectTimout, readAndWriteTimeout); // 省略代码块... } catch (Exception e) { // 省略代码块... } } 方法的入参是图片二进制流,模型名称和模型地址,方法的操作是用图片调用对应的模型,然后做一些日志记录、监控指标上报、错误处理等操作,最终返回模型的json格式结果。 可以看到其中模型的调用方式是确定的,直接将图片放在http body中,content-type为application/octet-stream 现在有一个模型,调用方式不一样,需要以form-data的格式把数据传过去,图片的名字必须为image, 像这样: OkHttpUtil.post(url, null, "image", img, null, 10000L, 10000L) 两者唯一的区别只是调用方式不一样,如果能把调用方式抽象出来单独传递的话,那是极好的。像Python这类的动态语言是很容易实现的,直接将函数作为参数传递,之后用()调用运算符调用即可: def func(): return "world" def outter(fun): print("hello, {}".format(fun())) outter(func) # "hello, world" 联想到Java中是否也可以这样呢,Java也是可以支持函数式编程的,自然也是可以的。实现方式如下 定义一个函数式接口: @FunctionalInterface public interface Lazy<T> { T value(); } 增加一个重载call方法,需要额外传入Lazy类型的参数httpHolder...

March 25, 2021 · 1 min · Egbert Ke