作者简介:wade,叽里呱啦攻城狮一枚,曾就职于苏宁,同花顺等,9个月大粿粿的爸爸。

前言

“工欲善其事,必先利其器”

在 2019 年进行数仓建设时,选择一款易用、方便、高效的调度系统被摆在非常突出的位置,感谢前同事马振洋同学和杨孟霏同学的付出,最终有缘选择了 DolphinScheduler的前身 EasyScheduler (后面使用 ES 代替),版本为 1.1,差不多成了第一批在生产上使用海豚调度产品的吃瓜群众,同时我们也在密切关注社区的变化,并成功在 2020 年 8月份升级至现在的 DolphinScheduler 1.3.2 版本(再次感谢杨孟霏同学,你是最棒的),在稳定性和功能丰富性上有了大幅度提升。

写在开头,先说下成绩,每天运行的工作流实例 1500+,任务实例达到了 6000+,今天就是以用户视角,从管理,开发,运维三个角度谈一下一年多使用 DS ( DolphinScheduler 的缩写,后面使用这个来代替)的感受,为社区其他同事提供一个避坑参考,也希望把用户的真实感受反馈给社区,和社区共同进步  up!!!!!

一、管理篇

DS 作为数仓处理工作实际上的运维管理者,对 DS 的管理能力非常看重,如何管理好 DS 上的众多玩家和成千上万的任务,保证系统稳定健康,一直是我们孜孜不倦的追求,首先我们带着问题出发,DS 能够回答的问题又有哪些?

模块

核心诉求

权限

○ 生产上数据源、资源文件、项目的权限管控问题

○ Worker分组权限

○ 报警分组权限

○ 工作流权限

账号

○ 工作流负责人如何指定

○ 离职人员账号如何处理

○ 运维账号如何分配

系统

○ 系统稳定性如何保障

○ 元数据丢失如何快速恢复

1.1 权限

○ 数据源

数据源中心进行数据源配置,支持主流关系型数据库数据源或者开源大数据框架,个人建议线上环境部署使用公共账号,配置示例如下:

这样有几个好处:

1. 大量减少数据源个数,方便后续进行IP或者连接账号的统一管理,方便赋权,进行权限控制

2. 当有人离职时,即使账号被删除,不会对已有工作流运行产生影响(离职账号被删除还会引发别的问题,后面讲)

3. 数据源被授权之后,右侧出现的编辑和删除动作及其危险,应该属于管理员操作,普通开发不应该具有编辑或者删除的权限,目前 DS 这一块没有做的很完美,有条件的话可以进行二次开发,让前端直接禁用

○ 资源文件

有些脚本运行需要在资源中心配置资源文件,比如 datax 同步需要的 json 文件,目前在 DS 上面同样也有广泛的用途,这个功能可以摆脱服务器的限制,做到配置全 web 操作,上一张已经配置好的图片,具体怎么使用,官方说明里面有,不再赘述。

目前遇到的几个影响体验的点

1.默认上传路径为 hdfs 路径,datax 调用的是本地路径,因此需要把文件从 hdfs 下载到本地,发现重新上传之后,执行下载不起作用,没有覆盖原来的文件,建议写脚本进行判断

2.资源授权被文件挤占,导致无法多选,一次性不能赋权太多,建议前端对这一块进行修改

○ 项目

在 ES 时代,由于没有跨项目依赖功能,所有项目只能混在一起,搜索任务只能依靠工作流名称,得益于 DS 提供的跨项目依赖功能,果断进行项目的拆分,合理进行布局

合理创建项目应该遵循以下几个原则:

1. 按照团队角色进行分类(BI 团队、AI 团队、数仓团队)

2. 按照数仓应用进行分类

3. 按照数仓层次进行分类

4. 业务开发项目和非业务项目进行拆分

5. 不同的调度周期也可以作为考虑因素

强烈建议大家禁用页面上的删除按钮,是个非常危险的存在,工作流不可以赋权,项目一旦被赋权之后,可以看到下面所有的工作流

线上环境权限建议配置如下:

模块

管理员

开发人员/运维人员

账号

增删改查

可以改密码

数据源

增删改查

可查

资源

增删改查

可查

项目

增删改查

可查

工作流

增删改查

可查

监控中心

可见

可见

安全中心

可见

不可见

1.2 账号

目前不建议大家直接删除已离职账号,直接删除会导致两个问题的发生

1. 由该账号创建的数据源会失效,工作流无法运行,使用公共数据源可以规避这个问题

2. 由该账号创建的定时会失效,界面无法查到,因为对应的用户 ID 找不到了

【解决方案】:暂时可以更改离职人员密码,账号不可登录即可

○ 负责人

目前调度系统界面上显示的为修改人,当对工作流进行编辑/保存之后,修改人立刻发生变化为最后一次修改工作流的人,通过查看调度系统后台数据库,发现还有一个创建人ID,界面上未显示,这两类角色均无法表示此工作流的实际负责人

【创建人】:一般为初始负责人,但是由于工作流会发生移交或者离职,导致工作流负责人发生变化

【修改人】:修改人只是临时修改,有可能是组内其他同事修改,或者管理员在线上修改,也无法表示工作流的实际负责人

【负责人】:数仓项目实际开发中某个业务模块的负责人,对该工作流负责

【解决方案】:目前建议进行二次开发,批量在界面进行授权,以方便后续的问题排查

1.3 系统

建议 DBA 定期进行备份,同时数据定期备份至数仓进行二次保证,一旦工作流被意外删除,可以做到快速恢复,不会影响生产

总结:1.权限控制粒度比较粗,一旦授权即拥有所有权限(增删改查)、生产的危险性比较高,无法控制到工作流层级。

2.主要升级:支持了跨项目间依赖

DS 目前的权限体系个人觉得还处于从 0 到 1 的过程中,权限授权太大,甚至可以删除项目,这是极其危险的动作,缺少任务负责人、操作记录审计等一系列系统保护的功能。

编辑注:后续社区希望实现“用户-角色-权限”+ 审计的方式来实现权限管控,对此有兴趣贡献的伙伴欢迎来联系我微信: taskflow

二、开发篇

上一篇管理篇讲的更多的是开发的外围准备工作,现在就深入开发本身来理解一下 DS 的设计原则和最佳实践,根据官方的设定,整体按照 “项目 --> 工作流 --> 节点任务”  三个层次去进行开发,可以做到各种技术栈开发的节点混排,当节点任务特别多的时候,建议引入 SUB_PROCESS 子工作流进行封装和屏蔽。

2.1 整体概述

数据开发整体在画布进行操作,组织成一个 DAG 图进行运行,官方提供的可以配置的节点还是比较多的,具体操作可以参考官方使用文档,这里主要对于其中主要的组件作一个补充说明。

2.2 重点组件

目前在叽里呱啦主要使用了【shell】、【sub_process】、【sql节点】、【depend节点】进行离线数仓的开发。大致位置如下图:

○ shell

配置方式 1 如图:

说明: Worker 分组为 Spark 并不是真正的 Spark 任务,只是命名而已,需要将 sh 脚本线下放到 Spark Worker 分组的这台机器上,让调度系统可以识别,脚本输入框调用路径与 sh 脚本实际存放路径一致即可。

配置方式 2 如图:

这种方式相对于 1 来说区别在于:

1. 上传 sh 脚本可以在调度系统完成,通过资源文件直接上传,不需要线下通过 jumpserver(跳板机) 上传到服务器

2. 直接显示代码,可以更清晰的定位问题,不需要再下载服务器上的代码来看

主要问题:

1. shell 节点无法看到代码,虽然可以暴露代码,如果代码太长,或者依赖的资源文件比较多的情况,配置和运维的难度系数还是比较高

2. shell 节点实践过程中,会出现 shell 节点日志报了失败,调度任务处于成功的情况,猜测 DS 虽然可以吊起 shell 脚本,但是对于 shell 脚本的控制力没有那么强,没有进行深度的集成

3. shell 脚本一旦运行,调度系统无法对 shell 脚本进行停止等操作,需要额外人工运维

4. shell 脚本的运行日志五花八门,没有统一格式,需要具体问题具体分析

5. 资源文件中 datax 的 json 中的用户名/密码是明文显示,存在安全风险,可以对datax 进行二次开发

总结:shell 节点可以运行包括jar包、py脚本、sh脚本,因此具备非常强的兼容性和灵活性,可以作为最后的备选方案,但是同时也有很多的缺陷需要注意,如果可以使用DS原生的节点任务,还是建议使用特定的节点任务

○ SUB_PROCESS

这个节点的出现,一开始我不是很理解,一个代码可以在多个地方执行的场景,运行多次是对资源的极大浪费,可以一次调用然后依赖执行就行了,但是其实这个节点第二个作用在于可以在任务节点和工作流之间,再架设一层实现对多任务节点的分类,在大型应用场景中(比如会员画像,复杂报表统计),可以使用该组件对代码进行封装,整体布局变得更加清晰,下面我们就以生产为例来说一下:

假如我们要加工的指标有 20+,DS 无法支持多段 sql 的执行,更是加剧了这种多节点的情况,这是一个绩效统计的代码,节点多达 28 个,后续迭代维护可能导致节点任务进一步增加,示意图如下:

使用了 SUB_PROCESS 节点之后,通过分类归纳,对于这种多节点任务进行可重构,   DS 的强大之处在于可以不同节点进行混排,完全取决于开发人员,使的外层节点任务可以降到 10 个以下,很方便去定位问题(没有放绩效、给的是标签工作流,理解原理即可)

子节点任务的配置需要先设定一个工作流,定时不需要设置,在主工作流中进行引用即可

总结:这个节点对于复杂工作流的重构提供了一种思路,建议大家可以去尝试下,单个工作流的节点任务连接线最好不要有交叉,节点数量控制在 20 个以内为宜。

○ SQL节点

sql 节点可以说是数仓使用最多的节点了,SQL 语法取决于你的数据源是什么类型的数据库,这里主要讲解数仓使用最多的 Hive,相比于 shell 脚本,配置起来更加简单,提交一段查询就可以,直接贴一段生产代码

【 sql 参数】:hive调参命令 set 被省略了

【 UDF 函数】:这个可以不用管,一般 udf 不需要临时添加,试过用资源文件配置,sentry 机制不允许,一般会注册成永久 udf,直接在sql语句里面使用即可

【自定义参数】:按照图示配置即可

【前置 sql/后置sql 】: 执行简单 drop 语句,不建议在这里去写业务代码,主要功能在于保障数仓的任务执行是可以重跑的。

【彩蛋】

这个地方的 SQL 语句除了可以进行数据 ETL,还可以配合邮件系统将 SQL 执行结果直接发送到邮件,可以实现部分数据提取、监控的功能,但是属于轻量级,不建议大规模使用,邮件系统容易崩溃,配置如下。

PS 踩坑教训:

1. 变量名、参数变量设置 [yyyyMMdd] 之间不要存在空格,否则空指针警告

     2. 代码里面的变量引用必须要有变量命名,即使注释了也不行,否则空指针警告

     3. SQL 不要以 “;” 结尾,目前不支持

     4. 代码中不要出现 ?” ,? 属于保留字,会导致代码无法执行

     5. 正则表达式慎重,可能会出现意想不到的后果

○ depend 节点

设计初衷主要是为了应对跨工作流依赖的情况,整个数据加工管道是由多个工作流组合,对于跨工作流要有好的机制来实现这个依赖,整个依赖关系图大致如下:

需要在 B,C,D,F,G 里面配置相应的依赖节点

比如 B 配置依赖 A 和 E 节点,定期扫描,依赖属于强依赖,需要等到 A 和 E 同时执行完成,且在 B 扫描的时候都完成,当 B 的 depend 节点运行时,A 和 E 如果已经已经启动,depend 节点会一直处于运行中状态,直到检测上游任务是一个失败or成功的状态。

遇到的主要问题如下:

1. 从 B 的视角我知道依赖的是谁,但是从 E 的视角来看,我并不知道 B,C,F 依赖了我,一旦工作流数据有问题,无法判断 E 执行了之后,还需要执行 B,C,E

2. 这种扫描方式属于被动扫描,E 执行之后是没办法主动触发起 B,C,E,在工作流失败,需要主动拉起后续任务的时候会极其困难

【解决方案】

1. 可以根据数据库的 json 依赖配置信息自行加工一个依赖列表,寻找到需要拉起的 BCE

2. 上游任务执行失败之后,后续任务扫描肯定会失败,因此只要把失败的任务逐层手动拉起即可

○ 补充说明

由于某些功能比较新颖、Hive 的特性不支持、节点操作起来繁琐等原因,暂时没有进行使用,被放弃的组件如下:

节点

现状

未使用原因

PROCEDURE

未使用

hive目前还不支持 store procedure,遇到 hivesql 无法解决的问题,建议直接写脚本处理

MR

未使用

代码量大,维护成本高,HiveSQL 无法处理的情况,写 UDF 进行扩展

SPARK/Flink/Py

未使用

未使用 spark,hive on spark只需要设置参数即可,flink 使用 shell 节点代替了

Http/sqoop/datax

未使用

没有调通,datax直接使用shell脚本进行调度

Conditions

未使用

没有找到业务场景

总结:上面总结了四种主要的节点任务配置范例和遇到的挑战,给了一些解决方案,社区也在加紧这一方面的开发,期待中

功能极其丰富,基本可以囊括数据开发的各个方面,且对于 RDBMS 和大数据组件也有很好的支持,

在一些细节处理上还不够完美,缺少列表依赖功能,级联重跑功能

编辑注: 列表依赖功能,级联重跑其实社区也有规划

三、运维篇

三分开发,七分运维,运维的难度系数可以说远胜开发,有没有被莫名其妙的问题搞得晕头转向,作业失败排查靠什么?靠经验,经验有时候并不可靠,靠日志?日志打得不完善,无从查起。。。一旦我们上线一个新的工作流,随之而来的运维工作会立刻提上日程,今天就一起看下 DS 这一块是如何实现的?

3.1 流程把控

在 ES 时代,假如在测试环境配置了一个工作流,要想发布到线上,同样的流程需要在线上再操作一遍,这个过程不但无聊而且很容易出现人为错误,浪费时间,感谢社区,急开发之所急,上线了导入导出工作流这个功能,之前一直没有体验这个功能,直到最近在做流程管控,对这个功能重新重视起来,并进行了实战,现在汇报一下我的实战结果。

首先看一下新老流程对比

(补充说明:dev:开发环境, fat:测试环境)

server

大数据

说明

dev

dev/fat

○  server 后端的 dev 环境和 fat 对应大数据测试环境,集群规模:5台

○  测试环境的 dev 和 fat 的区别就是 ODS 层的数据源更换

fat

pre/rc

rc/prd

○  server 的 rc 环境和 prd 环境对应大数据的生产环境,集群规模:70 台左右

○  使用生产数据进行验证

prd

老流程采取在线上集群开辟一个逻辑 test 库的形式进行开发,这种方式在上线到正式库的时候,需要手动修改代码,导致上线时间被无限拉长,甚至需要一天的时间来专门发布调试,切换成新的流程之后,大大缩短了上线发布的时间,基本可以控制在 20 分钟以内,具体操作也比较简单,导入导出工作流即可,保证线上和线下数据源名称是一致即可。

目前遇到的主要问题点

 1. 从测试环境导出的 json 文件,导入生产后,描述会丢失

         2. 如果已经有该工作流,新导入的是一个新的工作流,不是覆盖,需要先修改原来的工作流,然后

再去调整工作流依赖,如果依赖特别多的话,可以直接增量改线上的工作流

         3. SUB PROCESS 子流程组件导入会多出一些异常的工作流,需要进行清除

         4. 工作流归属队列 default 会变成 flink,这个问题要 check下,不是所有的都这样(default 和 flink 自己创建的)

         5. 同步任务导出到生产上之后,依赖的资源文件无法修改

         6. jar 包任务和 flink 实时任务目前不包括

总结:遇到很多细节问题,可能是这个功能大家用的还不够多,导致没有进行大的改善,但是这个功能还是非常强大的,可以大大缩短开发上线时间,如果生成全局代码,使用 Git 管理也是个不错的选择

3.2 实例监控

问题 1:工作流实例在夜间运行,失败了怎么才能快速发现?

答案:DS 目前没有接通企业微信或者钉钉等,可以安排每天安排一个专人值班,扩展整体调度监控邮件,扩展电话告警功能,失败立即给值班人员电话,可以做到快速修复

编辑注: 已经接通了企业微信,钉钉也有 PR 的

问题 2:  运维时如何快速找到失败的工作流?

可以根据时间和状态进行失败、等待等任务筛选,也可以通过名称进行模糊搜索

工作流实例是除了工作流定义之外,被打开最多的页面,执行用户和 host 的筛选框基本上不会被使用,状态目前只能支持单选,还不支持多选,在多状态选择时有一些问题,支持模糊搜索,还不支持精确搜索,需要社区可以尽快完善这个功能

问题 3: 如何快速查看节点日志?

这个可以从两个路径进入节点日志

1. 点击进入工作流,双击节点任务

节点配置右上角有查看日志,弹出节点执行日志

2. 或者复制节点任务,至任务实例查询,最右侧的查看日志

sql 节点任务的日志之前是直接替换?为真正的日期,现在改成显示变量名,反而有点不适应,没有显示 yarn 执行详细情况,有时候排查问题会比较麻烦

问题 4: 系统运行资源情况,调度各时段执行情况如何有效监控?

目前 DS 提供了首页整体流程和任务、以及按照人员维度统计的柱状图,还有监控中心模块,形成了一个初步的监控手段

解决方案:针对整体流程和任务运行情况的统计,进行二次开发,进行邮件发送

人员维度统计工作流数量意义有限,更多的还是希望可以看到每个时间段的资源消耗情况和任务执行进度情况的进度条,方便去合理安排工作流定时和优化长耗时任务,监控中心可以用来辅助排查像资源紧张导致的任务长时间提交不上去的情况。

总结:目前由于对于调度任务整体运行情况依然缺乏把控,社区版本可以做到对于job层级的监测,需要进行一些扩展工作

DS 提供了像首页概览、监控中心等模块,但整体监控的粒度还是较粗,希望看到任务执行时 yarn 资源消耗情况,MR 执行详情,更方便的定位问题。

四、最后

使用 DS 一年多以来,最大的感受是,社区愿意倾听广大用户的心声,不断完善和发展,任何一款产品都不是天生强大,需要所有人的共同努力,不断的给到正反馈,才能形成合力,开源的意义就是让大家都参与进来,贡献自己的力量!

最后也要给社区以诚挚的敬意,希望在未来的道路上变得更好,给大家提供更优质的作品。

编辑注: 叽里呱啦是国内最早一批使用 DolphinScheduler(2019 年开源不久就开始使用了) 的公司,wade 同学的文章非常具有实践意义,写的也非常用心,全文 7000+ 字的实践一气呵成,有实践趟坑也有解决方案(这里竖起大拇指)。Dolphin 今年刚成为 Apache 顶级项目,要走的路还挺长,那在这里我们也真诚呼唤更多热爱开源的伙伴加入到开源共建队伍中来,一起让本土开源做的更好,让更多人用上易用的、易维护的、稳定的大数据智能调度,诚如小海豚的 Slogan:

欢迎参与开源共建

近 2 年国内开源的迅猛崛起,参与贡献过开源项目已成为很多公司招聘的加分和优先项,参与开源的过程可以使自己的各方面能力得到快速成长,毕竟社区高手众多。DolphinScheduler 社区发展十分蓬勃,为了做更好用、易用的智能调度,真诚欢迎热爱开源的伙伴加入到开源社区中来,为中国开源崛起献上一份自己的力量,让本土开源走向全球

参与 DolphinScheduler 社区有非常多的参与贡献的方式,包括:

贡献第一个PR(文档、代码) 我们也希望是简单的,第一个PR用于熟悉提交的流程和社区协作以及感受社区的友好度。

社区汇总了以下适合新手的问题列表:https://github.com/apache/dolphinscheduler/issues/4124

如何参与贡献链接:https://dolphinscheduler.apache.org/zh-cn/community/development/contribute.html

来吧,DolphinScheduler开源社区需要您的参与,为中国开源崛起添砖加瓦吧,滴水汇聚亦可成江河。

参与开源可以近距离与各路高手切磋,如果您想参与贡献,可以添加社区小助手

微信(easyworkflow) 手把手教会您( 贡献者不分水平高低,有问必答,关键是有一颗愿意贡献的心 )。添加小助手微信时请说明想参与贡献哈,邀请加入贡献者种子孵化群!

来吧,开源重在参与,我们非常期待您的参与。

作者简介:wade,叽里呱啦攻城狮一枚,曾就职于苏宁,同花顺等,9个月大粿粿的爸爸,欢迎数据开发、数据平台研发的同学联系我微信:viking107270626,欢迎大家多多交流。

戳原文,立刻奔向

DolphinScheduler 
的 github 仓库一起玩耍,来个 star 先收藏也是好的~

我在叽里呱啦折腾 DolphinScheduler 的日子的更多相关文章

  1. 为了省钱,我用1天时间把PHP学了!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你在通往架构师的路上吗? 程序员这个行业就像是在不断的打怪升级,突破每一阶段的瓶颈期 ...

  2. 架构师根本不会被语言限制住,php照样可以用领域驱动设计DDD四层架构!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你在通往架构师的路上吗? 程序员这个行业就像是在不断的打怪升级,突破每一阶段的瓶颈期 ...

  3. 读jQuery源码 - Deferred

    Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...

  4. 2016中国APP分类排行榜参选入围产品公示

    2016中国APP分类排行榜参选入围产品公示   由中国科学院<互联网周刊>.中国社会科学院信息化研究中心.eNet硅谷动力共同主办的2016中国APP分类排行榜发布暨颁奖晚宴即将举行.此 ...

  5. 8.1搜索专练DFS和BFS

    这是第一次全部做出来的依次练习了,有一些都是做过两遍了的,但是还是错了几回,更多时候我还是应该多注意下细节,就好像章爷笑我 的一样,像什么vis[]标记没清0,什么格式错误,还有什么题目没看清,还是的 ...

  6. 与Google轻轻地擦肩而过

    第一集 因为那几年三天两头往硅谷里飞,所以我实在记不清这个故事到底是发生在98年还是99年夏天某日的一个下午. 那天我和Excite.com的创始人Mark V. H.在Palo Alto的一家餐厅共 ...

  7. 利用hashtable和time函数加速Lisp程序

    程序功能是从一个英文文本中得到单词表,再得到押韵词表.即输出可能这样开始: a ameoeba alba samba marimba... 这样结束: ...megahertz gigahertz j ...

  8. soundPool和audiofocus

    audiofocus试验: 使用soundPool来写一个播放音频的porject. 资源初始化: setContentView(R.layout.activity_main); Button bt1 ...

  9. EventBus猜想 ----手把手带你自己实现一个EventBus

    本文是什么 本文是一篇怀着推測角度学习一个未知东西(EventBus)的文章. 先推測EventBus是怎样实现的. 依据推測去模仿他的实现. 查看源代码.验证猜想. 更深入的去理解他. 转载请注明出 ...

随机推荐

  1. CSS基础学习(一)

    1.设置背景颜色:background-color 例:background-color:#d0e4fe;或background-color:blue; 2.字体颜色·:color 例:color:r ...

  2. 软件推荐 ---一款优秀的通信组件 HP_Socket

    * HP-Socket 官方网站:http://www.jessma.org* HP-Socket 项目主页:http://www.oschina.net/p/hp-socket* HP-Socket ...

  3. [NOI2011]阿狸打字机

    题意:一开始是个空串s,有三种操作:(1.末尾加一个字符 2.末尾减一个字符 3.存储该字符串) 思路: 一开始在trie树上动态加点很好处理,3操作的时候记录一下此时trie树上的pos,同时记录d ...

  4. C#语言中的类型转换方法(unfinished)

    一.C#中的数据类型 1.数值类型 2.字符类型 3.字符串类型 4.布尔类型 5.枚举类型 6.Object类型 二.常见的类型转换 从转换方式的角度,类型转换分为隐式转换与显式转换两种. 其中,隐 ...

  5. vscode的一些优化设置

    @ 目录 编辑代码区的字体设置 控制台字体设置 设置文件自动保存 自动猜测文件编码,防止乱码 关闭vscode的受限模式 取消每一次打开vscode都默认打开上次编辑的文件 编辑代码区的字体设置 控制 ...

  6. es6.4.2api

    这是讲数据库的数据导入到es里  所有用到了mysql! 1.依赖 <?xml version="1.0" encoding="UTF-8"?> & ...

  7. Arduino WeMos D1 开发环境搭建

    更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年9月2日. WeMos D1介绍 WeMos D1开发板全称是WeMos D1 WiFI UNO R3开发板,基 ...

  8. Spring框架系列(2) - Spring简单例子引入Spring要点

    上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件 ...

  9. 《ECMAScript 6 入门》【三、字符串的扩展】(持续更新中……)

    前言: 本篇介绍 ES6 对字符串的改造和增强.一.字符的 Unicode 表示法 字符的 Unicode 码点必须在\u0000~\uFFFF之间,\uxxxx形式表示一个字符,其中xxxx表示字符 ...

  10. SAP Column tree

    code as bellow *&---------------------------------------------------------------------* *& I ...