未来十年我们需要什么样的分析数据库?
本文来自于 Doris Summit 2022 演讲实录,演讲人:陈明雨
十年对于数据库意味着什么?
身处在日新月异的时代,我们见惯了技术的兴起与繁荣、变迁与衰落,甚至是朝荣夕灭。信息技术以前所未有的速度更迭,给周遭事物带来了颠覆性地变化。数据库亦是如此,无数数据库悄然湮没在技术更迭的浪潮里,直到在浩渺如海的代码片段中都找不到些许印记。而有的则历久而弥新,经受了时间的考验,彰显出强大的生命力,并以更加繁茂的姿态扎根生长。
十年对于数据库而言,可能是一段从诞生到消逝的完整软件生命周期,也可能是迈过里程碑之后的全新旅程。
所以从 MySQL 1.0 版本诞生,到具备颠覆性意义的 MySQL 5.7 版本正式发布,时间跨度刚好是十年,而十年之后的故事,大家已经都知道了。
所以从 Benoit、Thierry、Marcin 联合创建 Snowflake,到在纽交所成功上市、成为软件行业有史以来最大规模的IPO,再到全面开启云数据仓库时代,时间跨度也差不多十年。
而对于 Apache Doris,十年意味着什么?
留个悬念,在回答这个问题之前,我们不妨来回顾下社区发展历程。
尽管最早的历史可以追溯到 2008 年的百度凤巢广告系统,但彼时非 SQL 的单机查询引擎加 KV 存储系统在产品形态上与 OLAP 还有着较大的差异。
正式确立 OLAP 数据库这一形态是在 2013 年。通过自研全列式存储引擎 OLAP Engine 并基于 Apache Impala 改造了全新的 MPP 查询引擎,自此,Doris 真正成为了具备大数据量下高效支持数据分析能力的 OLAP 数据库,并在百度内部大规模应用,成为了百度内部统一的 OLAP 分析平台。
往往一个内部项目的发展会有两种演进模式,一种是随着需求的增加系统架构日益臃肿,当面对较为灵活的需求,常因改动成本过大而被彻底重构。另一种则是长期服务某一固定场景、需求逐渐收敛乃至停滞,最终被快速革新的外部技术彻底取代。而开源则是内部项目的一场新生,在更广阔的应用场景、更多样的开发者群体以及更高效的研发模式加持下开启新的篇章。
于是在数个版本的迭代与优化后,2017年 Doris 的前身在 GitHub 上开源,2018 年进入 Apache 基金会孵化,并正式更名为 Apache Doris。(GitHub 地址:https://github.com/apache/doris)
时至 2022 年,正是 Apache Doris 在 OLAP 领域深耕的十年之际。
# 我们该如何回顾过去的 2022 年?
2022 年,外部世界正处在前所未有的变化之中,无数魔幻时刻在现实中发生。需要庆幸的是,技术和开源的力量帮助我们穿越了许多不确定性。而这一年势必成为 Apache Doris 发展历程中有着浓墨重彩的一年,我们从几个角度来回顾一下 Apache Doris 过去一年的发展:
社区重要指标
过去一年中:
- 社区累计贡献者的数量从 200 余位增长至近 420 位,同比增长超过 100% ,目前仍在持续上升中。
- 每月活跃贡献者的数量从 50 位增长至 100 位,同样呈现翻倍增长的趋势。
- GitHub Star 数量从 3.6k 增长至 6.8k,多次登上 GitHub Trengding 日/周/月度榜单前列。
- 全部 Commits 数量从 3.7k 增长至 7.6k,过去一年新提交代码量超越了以往多年累加总和。
从这些数据中,我们可以感受到 2022 年是 Apache Doris 全面爆发的一年,各个维度数据指标几乎都有了 100% 的增长。这一年的努力也使 Apache Doris 成为了全球大数据和数据库领域最为活跃的开源社区之一,上方 GitHub Contribution 增长趋势图更是证明了这一点。而这一切,正是由社区所有的用户和开发者共同创造的。
另外值得纪念的是,在 2022 年 6 月, Apache Doris 迎来了开源以来最重要的里程碑之一,正式从 Apache 孵化器毕业、成为了 Apache *项目。
开源用户规模
得益于社区成立的专职工程师团队,为 Apache Doris 社区用户提供义务的技术支持,2022 年我们在用户连接与沟通方面变得更加顺畅,可以更直面用户、去倾听用户真实的声音。
在过去的一年里,Apache Doris 已经在互联网、金融、电信、教育、汽车、制造、物流、能源、政务等数十个行业应用落地,尤其是在以海量数据著称的互联网行业。在中国市值或估值排行前 50 的互联网公司中,有 80% 企业在长期使用 Apache Doris 来解决自身业务中的数据分析问题,其中包含了百度、美团、小米、腾讯、京东、字节跳动、网易、新浪、360、 米哈游、知乎等头部知名企业。
在全球范围内,Apache Doris 已经得到了超过 1000 家企业用户的认可,并且这一数字仍在快速增长中。这 1000 多家企业用户中,绝大多数与社区有着直接联系,并通过各种方式参与到社区建设中来。他们中的许多企业用户也参与到本次 Doris Summit 的议题分享中,将自身基于真实业务场景的实践经验分享给大家。
版本更新迭代
如果说过去版本将使用和运维的简易性作为第一追求的话,那么 2022 年发布版本则是在性能、稳定性、易用性等多方面特性的全面进化。
- 4 月份社区发布了自开源以来的首个 1 位版本—— Apache Doris 1.0,在 1.0 版本中,意义非凡的向量化执行初次与大家见面,标志着 Apache Doris 开始迈入极速数据分析时代。
- 6 月份发布的 1.1 版本,我们对向量化引擎进行了进一步完善和优化,并将其作为正式功能默认开启。与此同时,社区建立了 LTS 版本发布机制,以每月发布一个 3 位版本的速度,对 1.1 版本进行快速地 Bug 修复和功能优化,力求满足更多社区用户在稳定性方面的高要求。
- 在综合考虑版本迭代节奏和用户需求后,我们决定将众多新特性在 1.2 版本中发布。同时期社区的稳定性和质量保障工作也取得了显著的成效,测试 Case 得到了极大程度地丰富,并在 Master 分支上构建了流水线。通过一系列质量手段,Apache Doris 的代码质量和稳定性得到进一步提升,这也使得版本发布有着更加严格的准出标准。
- 12 月初 1.2 版本正式面世。这一版本的发布不仅使查询性能有了近十倍的提升,同时我们还推出了过去半年时间里研发的诸多重磅功能,包括 Unique Key 模型 Merge-on-Write 的数据更新模式、支持无缝对接多种数据湖的 Multi-Catalog 多源数据目录、Java UDF 、Array 数组类型和 JSONB 类型等,让 Apache Doris 在更多数据分析场景具备了更强的适应性和可能性。
- 我们也针对系统稳定性进行了大量的工作,一方面,利用 SQL Smith 等自动化测试工具以及各个知名开源项目的测试用例,构建了数以百万计的测试用例集;另一方面,通过社区准入流水线和完善的回归测试框架,保证了代码合入的质量。因此1.2 版本不论从功能、性能还是稳定性方面,都是一次厚积薄发后的全面进化,也是对所有开发者在 2022 年辛苦付出的最好回报。
核心特性演进
核心特性方面,社区的研发力量主要围绕四个方面开展工作,分别是性能、实时性、半结构化数据支持与 Lakehouse。
- 查询性能提升。从 1.0 版本面世到 1.2 版本发布,Apache Doris 在性能方面取得了极为显著的成绩。在单表场景上,Apache Doris 荣登 Clickhouse 公司推出的 Clickbench 数据库性能榜单,并取得了前三名的优秀成绩。在多表关联场景上,得益于向量化执行引擎及各种查询优化技术,相对 2021 年底发布的 0.15 版本 ,Apache Doris 在 SSB 和 TPC-H 等标准测试数据集下均取得了数倍乃至数十倍的性能提升。这一系列性能方面的优化,已经成功让 Apache Doris 跻身全球数据库性能最优阵列中!
- 实时场景优化。 在 1.2 版本中,我们在原有 Unique Key 数据模型上实现了Merge-On-Write 的数据更新方式,查询性能在高频更新时有 5-10 倍的提升,实现了在可更新数据上的低延迟实时分析体验。另外还实现了轻量 Schema Change 功能,对于数据的加减列不再需要转换历史数据,可通过 Flink CDC 等工具快速便捷地同步上游事务数据库中的 DML 或 DDL 操作,使数据同步工作能够更加流畅统一。
- 半结构化数据支持。 目前 Apache Doris 支持了 Array 和 JSONB 类型,其中 Array 类型不仅能更方便地存储复杂的数据结构,还可以通过 Array 函数满足用户行为分析等场景的业务需求。而 JSONB 是一种二进制 JSON 存储方式,它不但比纯文本 Text JSON 的访问性能快 4 倍,同时也有更低的内存消耗。通过 JSONB 可以方便地导入各种 JSON 格式的日志数据结构,并能取得优异的查询效率。这也是 Apache Doris 在日志分析领域所做的探索之一。
- Lakehouse。在最新发布的 1. 2 版本中,我们引入了全新的 Catalog 概念,正式将 Apache Doris 迈入湖仓一体时代。通过简单的命令便可以方便地连接到各自外部数据源并自动同步元数据,实现统一的分析体验。通过 Native Format Reader、延迟物化、异步 IO、数据预取等多项针对外部数据源的性能优化,并充分利用自身的高性能执行引擎和查询优化器,在对外表访问性能上,Apache Doris 可以达到 Trino/Presto 的 3- 5 倍、Hive 的 10-100 倍。
2023 RoadMap
承前而启后,2023 年,Apache Doris 社区在以上几方面特性持续完善的同时,也将开启更多有意义的工作。全年的 RoadMap 以及明年 Q1 的具体计划,可以参考以下的全景图:
稳定的版本发布和迭代速度对于开源软件至关重要。在 2023 年,我们将以每季度一个 2 位版本的节奏,开始 Apache Doris 2.x 版本的迭代。同时,针对每个 2 位版本,我们也将以每月一个 3 位版本的速度进行功能维护和优化。
从功能角度来看,后续研发工作将会围绕以下几个主要方向展开:
高性能
高性能是 Apache Doris 不断追求的目标,过去一年在 Clickbench、TPC-H 等公开测试数据集上的优异表现,已经证明了其在执行层以及算子优化方面做到了业界领先。未来我们也会不断优化各个场景下的性能表现,回馈用户极速的数据分析体验,具体包括:
- 更复杂SQL性能提升: 2022 年我们已经启动全新查询优化器的设计与开发,而这一成果在 2023 年一季度就将与大家见面。全新查询优化器提供了丰富的规则模型,实现了更智能的代价选择,可以更高效地支撑复杂查询,能够完整执行 TPC-DS 全部 99 个SQL。同时全新查询优化器还具备全查询场景的自适应优化,便于用户在面对不同分析负载和业务场景时都获得一致性的使用体验。
- 更高的点查询并发: 高并发一直是 Apache Doris 所擅长的场景,而 2023 年我们将会进一步加强这一能力,通过 Short-Circuit Plan、Prepare Statement、Query Cache 等一系列技术,实现单机数万 QPS 的超高并发支持,并具备随集群规模的拓展进而线性提升并发的能力。
- 更灵活的多表物化视图: 在过去版本中,通过强一致的单表物化视图,Apache Doris 加速了固定维度数据的分析效率。而全新的多表物化视图将会解耦 Base 表与 MV 表的生命周期,通过异步刷新和灵活的增量计算方式,满足多表关联以及更复杂 SQL 的预计算加速需求,这一特性将在接下来的 2023 年第一季度与大家见面!
高性价比
成本和效率对企业而言是赢得市场竞争的关键,对数据库而言亦是如此。过去 Apache Doris 凭借在易用性方面的诸多设计帮助用户大幅节约了计算与存储资源成本,后续我们也会引入一系列云原生能力,在不影响业务效率的同时进一步降低成本,具体包括:
- 更低的存储成本: 我们将探索与云上对象存储系统和文件系统的结合,帮助用户进一步降低存储成本,包括更完善的冷热数据分离能力,将冷数据智能转移至更廉价的对象存储或文件系统中。结合单一远程副本、冷数据 Cache 以及冷热智能转换等技术,保证业务查询效率不受影响的同时实现存储成本大幅降低,这一功能将于 2023 年第一季度发布。
- 更弹性的计算资源: 剥离存储与计算状态,引入仅用于计算的 Elastic Compute Node 。由于不存储数据,弹性计算节点具备更加快速的弹性伸缩能力,便于用户在业务高峰期进行快速扩容,进一步提升在海量数据计算场景(如数据湖分析)的分析效率,这一功能已经处于最终调试阶段,即将与大家见面。后续我们还将通过对集群内存和 CPU 运行指标的监控和自动策略配置,实现自动的节点扩缩容(Auto-scaling)。
混合负载
随着用户规模的极速扩张,越来越多的用户将 Apache Doris 用于构建企业内部的统一分析平台。这一方面需要 Apache Doris 去承担更大规模的数据处理和分析,另一方面也需要 Apache Doris 同时去应对更多分析负载的挑战,从过去的实时报表和 Ad-hoc 等典型 OLAP 场景,扩展到 ELT/ETL 、日志检索与分析等更多场景的统一。为了能更好适配这些场景,许多工作已经进入紧锣密鼓的研发中,并将于 2023 年陆续与大家见面,具体包括:
- 更灵活的 Pipeline 执行引擎* *:**与传统的火山模型相比,Pipeline 模型无需手动设置并发度,可以实现不同管道之间的并行计算,充分利用多核的计算能力,实现更灵活的执行调度,提升在混合负载场景下的综合性能表现。
- Workload Manager: 在性能提升的同时,也亟需完善的资源隔离和划分的能力。我们将会基于 Pipeline 执行引擎实现更细粒度和更灵活的负载管理、资源队列以及共享隔离等功能,兼顾多种混合负载场景下的查询性能与稳定性。
- 轻量级容错: 轻量级容错能力也是我们后续持续完善的地方,既能利用 MPP 的高效率又能对错误进行容忍,以更好适应用户在 ETL/ELT 场景的挑战。
- 函数兼容与多语言UDF: 与此同时,后续也将支持 Hive/Trino/Spark 函数的兼容性以及多语言的 UDF,来帮助用户更灵活地进行数据加工,也可以更方便地从其他数据库系统迁移到 Apache Doris。
多模数据分析
在过去 Apache Doris 更多是是擅长于结构化数据分析,随着对半结构化、非结构化数据分析需求的增加,从 1.2 版本起我们增加了 Array 和 JSONB 类型以实现数据的 Native 支持,后续版本仍将持续加强这一能力,为日志分析场景提供性价比更高、性能更强的解决方案,具体包括:
- 更丰富的复杂数据类型* *:**除 Array/JSONB 类型以外,2023 年第一季度我们将增加对 Map/Struct 类型的支持,包括高效写入、存储、分析函数以及类型之间的相互嵌套,以更好满足多模态数据分析的支持。后续将支持更加丰富的数据类型,包括 IP、GEO 地理信息等数据类型,并会探索在时序数据场景的高效数据分析。
- 更高效的文本分析算法: 对于文本数据,我们将引入更多的文本分析算法,包括自适应 Like、高性能子串匹配、高性能正则匹配,Like 语句的谓词下推、Ngram Bloomfilter 等,同时基于倒排索引实现全文检索能力,在日志分析场景提供比 ES 更高性能和性价比的分析能力。这些功能都已经处于就绪阶段,将在 2023 年初与大家见面。
- 动态 Schema 表: 传统数据库在设计之初 Schema 是静态的,Schema 变更时需要执行 DDL ,而这一操作往往具有阻塞性。在越来越多的现代数据分析场景中,表结构会随时间推移而变化,因此我们引入了 Dynamic Table,可以根据数据写入自动适应 Schema ,不再需要执行 DDL,由过去的人工干预数据结构进化为数据自驱动,极大提升了灵活数据分析的便捷性。这一功能将在 2022 年第一季度正式发布。
Lakehouse
随着数据湖技术的发展,分析性能成为发挥数据湖效用、挖掘数据价值最大的掣肘。基于一款简单易用和高性能的查询分析引擎在数据湖之上构建分析服务,成为新的技术趋势。在过去一年,通过在数据湖上的诸多性能优化、结合自身的高性能执行引擎和查询优化器以及,Apache Doris 实现了数据湖上极速易用的分析体验,性能较 Presto/Trino 有 3-5 倍的提升。在 2023 年,我们将会继续完善这一能力,具体包括:
- 更简易的数据对接: 在 1.2 版本中我们发布了 Multi-Catalog,支持了多种异构数据源的元数据自动映射与同步,实现了数据湖的无缝对接,后续将对 Delta Lake 的支持以及 Iceberg、Hudi 等更多数据格式的支持。
- 更完整的数据湖能力支持: 提供数据湖上数据的增量更新与查询,还会支持将分析结果写回数据湖、外表写入内表,实现数据分析流程的全闭环。同时还将支持多版本 Snapshot 读取和删除,并进一步在 Apache Doris 为数据湖数据提供物化视图。
实时性与存储引擎优化
数据价值会随着时间推移而降低,因此实时性对于高时效性要求的用户而言至关重要。在 1.1 版本中我们在 Compaction 和 Flink 实时写入方面进行了诸多优化,同时 1.2 版本的 Merge-on-Write 数据更新模式进一步使 Apache Doris 在实时更新与极速查询得以统一。2023 年我们将会持续强化对存储引擎的优化,具体包括:
- 更稳定的数据写入: 通过一系列 Compaction 操作和批量数据写入方面的优化,节省资源开销,降低写放大问题,并结合全新的内存管理框架提升写入过程的内存稳定性,进而提升系统稳定性。
- 更完善的数据更新支持: 过去部分列更新是通过 Agg 模型上的 Replace_if_not_null 来实现的,后续我们将会增加 Unique Key 模型上的部分列更新支持,并完整实现 Delete、Update、 Merge 等数据更新的操作。
- 更统一的数据模型: 当前 Apache Doris 的三种数据模型在各个场景均有丰富的应用,后续我们将尝试统一现有几种数据模型,使用户在使用体验上更加统一。
易用性和稳定性
除了功能方面的丰富与完善,更简单、更易用、更稳定同样也是 Apache Doris 一直追求的目标,2023 年我们将在以下几方面出发,让用户具有更简易和放心的使用体验:
- 简化建表: 目前 Apache Doris 在建表时分区已经支持了时间函数,后续我们将进一步消除 Bucket 设置,帮助用户最大程度简化建表建模。
- 安全性: 目前已经实现基于 RBAC 模型的权限管理机制,使用户权限更安全可靠;并对 ID-federation、行列级别权限,数据脱敏等进行了优化,后续将进一步完善。
- 可观测性: Profile 是定位查询性能问题的重要手段,后续我们将加强对 Profile 的监控并提供可视化 Profile 工具,帮助用户更快定位问题。
- 更好的 BI 兼容性和更完善的数据集成迁移方案: 当前各 BI 工具可以通过 MySQL 协议连接到 Apache Doris,后续我们将对主流 BI 软件进一步适配,保证更佳的查询体验。随着 DBT、Airbyte 等新兴数据集成和迁移工具的兴起,越来越多用户使用此类系统将数据同步至 Apache Doris ,后续我们也会提供对此些系统的官方支持。
开启下一个十年!
或许有读者或听众还记得我在开头提的问题,对于 Apache Doris,十年意味着什么?
有两层含义,上一个十年和下一个十年。
上一个十年,是 Apache Doris 起源的十年。从诞生到开源、从默默无闻到被越来越多人熟知和使用,开源赋予了 Apache Doris 更加旺盛的生命力和创造力。
而下一个十年,则是一场新的旅程。
正如我在本次 Doris Summit 分享的主题,New Journey of Apache Doris。如果说过去 Apache Doris 更多是服务于在线报表场景和 Ad-hoc 分析的 OLAP 引擎的话,那么在所有社区和开发者的努力下,当前 Apache Doris 已经具备了更为广阔的定位,即极速、易用、实时、统一的多模分析型数据库。
这其中的统一,既包含了架构的统一、也包含了业务和数据的统一。用户可以通过 Apache Doris 构建多种不同场景的数据分析服务、同时支撑在线与离线的业务负载、高吞吐的交互式分析与高并发的点查询;通过一套架构实现湖和仓的统一、在数据湖和多种异构存储之上提供无缝且极速的分析服务;也可通过对日志/文本等半结构化乃至非结构化的多模数据进行统一管理和分析、来满足更多样化数据分析的需求。
这是我们希望 Apache Doris 能够带给用户的价值,不再让用户在多套系统之间权衡,仅通过一个系统解决绝大部分问题,降低复杂技术栈带来的开发、运维和使用成本,最大化提升生产力。
“我们已经出发了太久,以至于忘记了为什么出发。”
希望通过这一定位的转变迎接下一个十年的挑战,或许技术趋势会有变化,架构将会革新,但我们解决用户数据分析问题的初衷不会改变。
希望继续带着上一个十年出发的初心,开启下一个十年的旅程。
推荐阅读
-
未来十年我们需要什么样的分析数据库?
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
反传销网8月30日发布:视频区块链里的骗子,币里的韭菜,杜子建骂人了!金融大V周召说区块链!——“一小帮骗子玩一大帮小白,被割韭菜,小白还轮流被割,割的就是你!” 什么区块链,统统是骗子 作者:周召(知乎金融领域大V,毕业于上海财经大学,目前任职上海某股权投资基金合伙人) 有人问我,区块链现在这么火,到底是不是骗局? 我的回答是: 是骗局。而且我并不是说数字货币是骗局,而是说所有搞区块链的都是骗局。 -01- 区块链是一种鸡肋技术 人类社会任何技术的发明应用,本质都是为了提高社会的生产效率。而所谓区块链技术本质不过是几种早已成熟的技术的大杂烩,冗余且十分低效,除了提高了洗钱和诈骗的效率以外,对人类社会的进步毫无贡献。 真正意义上的区块链得包含三个要素:分布式系统(包括记账和存储),无法篡改的数据结构,以及共识算法,三者互为基础和因果,就像三体世界一样。看上去挺让人不明觉厉的,而经过几年的瞎折腾,稍微懂点区块链的碰了几次壁后都已经渐渐明白区块链其实并没有什么卵用,区块链技术已经名存实亡,沦为了营销工具和传销组织的画皮。 因为符合上述定义的、以比特币为代表的原教旨区块链技术,是反效率的,从经济学角度来说,不但不是一种帕累托改进,甚至还可以说是一种帕累托倒退。 原教旨区块链技术的效率十分低下,因为要遍历所有节点,只能做非常轻量级的数据应用,一旦涉及到大量的数据传输与更新,区块链就瞎了。 一方面整条链交易速度会极慢,另一方面数据库容量极速膨胀,考虑到人手一份的存储机制,区块链其实是对存储资源和能源的一种极大的浪费。 这里还没有加上为了取得所谓的共识和挖矿消耗的巨大的能源,如果说区块链技术是屎,那么这波区块链投机浪潮可谓人类历史上最大规模的搅屎运动。 区块链也验证不了任何东西。 所谓的智能合约,即不智能,也非合约。我看有人还说,如果有了智能合约,就可以跟老板签一份放区块链上,如果明年销售业绩提升30%,就加薪10%,由于区块链不能篡改,不能抵赖,所以老板必须得执行,说得有板有眼,不懂行的愣一看,好像还真是那么回事。 但仔细一想,问题就来了。首先,在区块链上如何证明你真的达到了30%业绩提升?即便真的达到老板耍赖如何执行? 也就是说,如果区块链真这么厉害,要法院和仲裁干什么。 人类社会真正的符合成本效益原则的是代理制度。之前有人说要用区块链改造注册会计师行业,我不知道他准备怎么设计,我猜想他思路大概是这样的,首先肯定搞去中心化,让所有会计师到链上来,然后一个新人要成为注册会计师就要所有会计师同意并记录在链上。 那我就请问了,我每天上班累死累活,为什么还要花时间去验证一个跟我无关的的人的专业能力?最优做法当然是组织一个委员会,让专门的人来负责,这不就是现在注册会师协会干的事儿吗?区块链的逻辑相当于什么事情都要拿出来公投,这个绝对是扯淡的。 当然这么说都有点抬举区块链了,区块链技术本身根本没有判断是非能力,如果这么高级的人工智能,靠一个无脑分布式记账就能实现的话,我们早就进入共产主义社会了。 虽然EOS等数字货币采用了超级节点,通过再中心化的方式提高效率,有点行业协会的意思,是对区块链原教旨主义的一种修正,但是依然无法突破区块链技术最本质的局限性。有人说,私有链和联盟链是区块链技术的未来,也是扯淡,因为区块链技术没有未来。如果有,说明他是包装成区块链的伪区块链技术。 区块链所涉及的所有底层技术,不管是分布式数据库技术,加密技术,还是点对点传输技术等,基本都是早已存在没什么秘密可言的技术。 比特币系统最重要的特性是封闭性和自洽性,他验证不了任何系统自身以外产生的信息的真实性。 所谓系统自身产生的信息,就是数据库数据的变动信息,有价值的基本上有且只有交易信息。所以说比特币最初不过是中本聪一种炫技的产物,来证明自己对几种技术的掌握,你看我多牛逼,设计出了一个像三体一样的系统。因此,数字货币很有可能是区块链从始至终唯一的杀手应用。 比特币和区块链概念从诞生到今天已经快10年了,很多人说区块链技术在爆发的前夜,但这个前夜好像是不是有点过长了啊朋友,跟三体里的长夜有一拼啊。都说区块链技术像是90年代初的互联网,可是90年代初的互联网在十年发展后,已经出现了一大批伟大的公司,阿里巴巴在99年都成立了,区块链怎么除了币还是币呢? 正规的数字货币未来发展的形式无外乎几种,要么就是论坛币形式,或者类似股票的权益凭证等。问题是论坛币和股票之前,本来也都电子化了,区块链来了到底改变了什么呢? 所有想把TOKEN和应用场景结合起来的人最后都很痛苦,最后他们会发现区块链技术就是脱裤子放屁,自己辛苦搞半天,干嘛不自己作为中心关心门来收钱?最后这些人都产生了价值的虚无感,最终精神崩溃,只能发币疯狂收割韭菜,一边嘴里还说着我是个好人之类的奇怪的话。 因此,之前币圈链圈还泾渭分明,互相瞧不起,但这两年链圈逐渐坐不住了,想着是不是趁着泡沫没彻底破灭之前赶快收割一波,不然可能什么都捞不着了。 前段时间和一个名校毕业的链圈朋友瞎聊天,他说他们“致力于用区块链技术解决数字版权保护问题”,我就问他一个问题,你们如何保证你链的版权所有权声明是真实的,万一盗版者抢先一步把数据放在链上怎么办。他说他们的解决方案是连入国家数字版权保护中心的数据库进行验证…… 所以说区块链技术就是个鸡肋,研究到最后都会落入效率与真实性的黑洞,很多人一头扎进链圈后才发现,真正意义上的区块链技术,其实什么都干不了。 -02- 不是蠢就是坏的区块链媒体 空气币和区块链的造富神话,让区块链自媒体也开始迎风乱扭。一群群根本不知道区块链为何物的妖魔鬼怪纷纷进驻区块链自媒体战场,开始大放厥词胡编乱造。 任何东西,但凡只要和区块,链,分,分布式,记账,加密,验证,可追溯等等这些个关键词沾到哪怕一点点,这些所谓的区块链媒体人就会像狗闻到了屎了一样疯狂地把区块链概念往上套。 这让我想起曾经一度也是热闹非凡的物联网,我曾经去看过江苏一家号称要改变世界的“物联网”企业,过去一看是生产路由器的,我黑人问号脸,对方解释说没有路由器万物怎么互联,我觉得他说得好有道理,竟无言以对。 好,下面让我们进入奇葩共赏析时间,来看看区城链媒体经常有哪些危言耸听的奇谈怪论 区块链(分布式记账)的典型应用是*?? 正如前面所说,真正意义上的区块链分布式记账,不光包括“记”这个动作,还包括分布式存储和共识机制等。而*诞生远远早于区块链这个词的出现,勉强算是“分布式编辑”吧,就被很多区块链媒体拿来强行充当区块链技术应用的典范。 其实事实恰恰相反,*恰恰是去中心化失败的典范,现在如果没有精英和专业人士的编辑和维护,*早就没法看了。 区块链会促进社会分工?? 罗振宇好像就说过类似的话,虽然罗振宇说过很多没有逻辑的话,但这句话绝对是最没逻辑思维的。很多区块链自媒体也常常用这句话来忽悠老百姓,说分工代表效率提高社会进步,而区块链“无疑”会促进分工,他们的理由仅仅是分工和分布式记账都共用一个“分”字,就强行把他们扯到一起。 实际情况恰恰相反,区块链是逆分工的,区块链精神是号召所有人积极地参与到他不擅长也不想掺合的事情里面去。 区块链不能像上帝一样许诺他的子民死后上天国,只能给他们许诺你们是六度人脉中的第一级,我可以赚后面五级人的钱,你处于金字塔的顶端。
-
视频会议场景中的空间音频--为何选择空间音频这一主题? 首先,为什么选择空间音频这一主题?我在视频会议领域工作了近二十年,我们的目标一直是让声音更清晰、视频更清晰。但在过去的 20 年中,视频会议的产品形态并没有发生本质的变化。去年元宇宙比较火,微软、Facebook都在做基于VR和元宇宙的企业协作研究,我们也进行了这方面的探索。 一开始,我们想从纯技术角度研究空间音频技术如何应用于视频会议场景,但在研究过程中,我们发现这是一个非常复杂的场景。因为视频会议本质上是人与人之间的交流。人与人之间的沟通是多维度的信息传递,声音、图像、眼神、肢体语言、触觉都是人与人之间沟通的要素,音频只是其中之一。本次分享从沟通与交流的角度,从视频会议的应用场景出发,分析视频会议产品需要什么样的空间音频技术以及如何实现。 02 空间音频与沉浸式交流
-
阿里味 "的《Redis核心实践全彩手册》给你,还学不会转行--Redis基本是必考点。在 "阿里味 "的《Redis核心实战全彩手册》里,你还是学不会转行--Redis基本是必考点: - Redis 常见的性能问题有哪些?Redis 最常见的性能问题有哪些,如何解决?--性能相关 - Redis 缓存的雪崩、击落和穿透到底意味着什么?如何处理?--缓存相关 - Redis 主从集群有哪些常见问题?如何解决?--可用性 - 现有的 Redis 实例有 6GB 的存储空间,预计将来会扩展到 32GB,你能提供解决方案并分析其优势和潜在问题吗?--可扩展性相关 毕竟,10 家公司中至少有 8 家的架构系统中都有 Redis,基本上可以说是 IT 基础架构的必备系统。 因此,Redis 的开发和运维是很多大厂的重要工作,也是我们必须掌握的技术栈。 不过,Redis 毕竟是一个复杂的键值数据库,在实际使用中,有非常多的技术点需要注意,比如:各种数据结构、数据持久化机制、分片集群、主从集群等等。 一不小心,性能就会每况愈下,失去 "快 "的最大特点!
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面