Microsoft Ignite The Tour 深圳场次 学习小结

/ 1评 / 0

俗话说外行看热闹,内行看门道。我作为一颗青瓜,自然是去凑热闹的。当然,即使是尚未从事现实世界开发,在 Ignite 上能学习的东西也是蛮多的。

一点背景

Microsoft Ignite The Tour 是微软为全球开发者、IT专家、安全专家以及数据专家提供的为期两天,包含众多核心产品的实践性技术培训。

从之前的参会资料可以知道,Ignite The Tour 按道理是在世界各地一年一度举行的。不过这次在国内有三场,之前 2019 年 12 月在北京有一次,这次 2020 年 1 月在深圳有一次,接下来在 2020 年 3 月还会在上海有一次,所以有条件的同志们仍然有机会参加。

会展本身是有学习路线这个设定的——也就是存在一系列围绕一个特定主题的会议。当然,并不严格要求按照学习路线参加会议,但是如果能够按照路线听完整场的话,可以对给定方向有一个更立体的理解。

当然,此次会展也是微软的强力软广。会议的演示内容也是围绕着微软所提供的服务展开的。所以好玩的事情就是这总是让人情不自禁地想猜它的具体实现是什么。不过既然会展的定位是实践性技术培训的话,对原理讲解的缺失倒也无可厚非。

接下来我将会阐述我去听了的会议的核心思想以及一些个人的思考。当然,软广部分就省略不写了,一般看到思路的断崖的时候就表示接下来是演(guang)示(gao)部分。


AIML10 - 通过 AI 了解非结构化的数据

这是一个挺好玩的东西,标题取得也很大,或许是因为 AI 这个字眼总是让人条件反射般地觉得假大空。不过会议内容还是比较坚实的,因为毕竟这是一个落地的项目。

所谓非结构化数据,就是类似图片、视频、表单、未整理的文档这些难以提取出结构,或者存在一定结构但难以编写程序进行操作的数据。

在会议给出的例子中,要处理的非结构化数据是小票存根的 PDF 文档。所幸这个存根在 PDF 中切实是文字而不是直接一张图,所以一个传统的思路是将 PDF 中的文字提取出来,然后再进行操作。

但是小票的一个特点(或者说痛苦点)是结构多变。比方说可能有会员信息、折扣、抹零等等非常态化存在的信息。此时要尝试编写程序进行处理显然是复杂的。而人工读取小票再打 Excel 在数据量奇大的时候(比如你的数据库炸了,现在要从历史数据中恢复)也是不合适的。

所谓遇事不决,量子力学人工智能。我们能否训练一个网络来识别小票呢?答案是可以,巨硬已经完成了这个工作。这个工作还有一个响亮的名字:认知服务。认知服务包括常见的对图像的处理(OCR, 人脸识别、墨迹识别等)、语音识别、自然语言处理以及决策支持。当然,背后是通过某种机器学习方案实现的。至于这个某种是怎么搞的呢,或许可以考虑搜一下巨硬的论文或者专利。

THR30034 - 使用部署槽位安全地进行部署和 A/B 测试

这是一个比较传统的内容了。部署一直是一个让人头疼的问题,一个最直观的例子就是 The Epic Deployment 和杀程序员祭天等神奇操作。

现在的思路是:我可以同时运行多个实例,这些实例中的某一个是当前的生产实例,其他的可能是备份或者测试实例。当我完成了一个更新时,我可以将这个更新部署到一个实例,然后对这个实例进行测试。当该实例确定可用后,将流量导向这个新实例使之成为新的生产实例。这么做的好处是一旦新的实例出现了严重错误,或引入了新的未预见的问题时,我们仍然可用将流量切回原生产实例。这样可以绕开部署后无法回滚的问题。

我们也可以利用流量导向工具,将一定比例的流量导向一个实例,而不是直接切换到一个实例,即灰度部署;我们也可以在引入一个更改时配置新旧两个实例,通过收集用户反馈来决定要不要将该更改应用到全体,即 A/B 测试。

当然,这个操作会引入另一个问题:应用上下文的转接。如果我们的应用是存在上下文的(一般而言复杂的系统都会存在),那么当我们切换流量的时候,我们如何让旧实例将上下文转交给新实例呢?这在会议当中是没有提的。

一个个人的思路是:为啥应用程序会有状态嘛。如果我们将应用程序的状态保存在数据库中,并用会话 Cookie 进行索引,那么业务逻辑就可以是无状态的(对上下文的操作将可以是纯的)。有状态的部分则和业务逻辑剥离开,从而可以实现热切换等等操作。

MDEV20 - Microsoft Graph: 开发者入门

这个就是全篇硬广了。我去听这一场的核心原因是我需要知道 Microsoft Graph 究竟是一个怎样的东西。

看完之后只能说,挺厉害的。Microsoft Graph 这个名字其实挺有误导性的,让人感觉是一个像是 ECharts 一样的画图 API. 实际上 Graph 是一个聚合服务,用于配合 Office 365 实现一个增强型办公自动化平台。

注意到这个增强并不是在已有的平台上的些许改进,而是非常激进的功能添加,以至于让人有点担心隐私问题的那种实现,在 Graph 中也包含了。譬如摸鱼时间统计、人际关系状态等等。当然这部分还是需要通过 Office 365 喂给 Graph 才会有的内容。果然 Windows 域的木马名号不是白来的。

THR30048 - 从 eShopContainers 中学习构建 .NET Core 微服务

没啥好说的,因为没有比较深刻的印象。毕竟 15 分钟,能给出的内容也不多。这也是临时起意去听的,所以确实没啥收获。

APPS30 - 使用容器实现应用程序现代化

我个人比较喜欢老外演讲的原因是他们真的会从头讲起,对于预先知识的要求并不高,所以也能讲得更生动一些,或者说水得更多一些。毕竟技术这种东西说穿了之后有一股干巴巴的感觉。

容器已经是一个非常成熟的技术了。使用容器其实并不会对性能造成影响(当然,存储空间而言还是有些许影响的,不过你欠那点硬盘空间么),而且可以带来许多好处,最突出的优势在于资源控制和应用隔离。资源控制借助于 Linux 的 CGroup 实现,可以为应用程序单独分配时间片、内存和 IO. 应用隔离则可以避免 DLL 地狱的发生。

注意到容器技术并不特指 docker. docker 是最流行的容器技术实现。

有了容器,容器的管理自然也要顺便来一发。这时就要提到 Kubernetes, 或者说 k8s 了。(下文仍将使用 Kubernetes, 因为 k8s 听着太糟糕了。)

Kubernetes 是一个容器管理系统,可以对容器进行自动部署、监控和调度。Kubernetes 是具有主从结构的,即存在一个主节点负责收集所有从节点的工作状态和进行调度,从节点则负责运行容器并提供服务。

从节点中对容器进行操作的基本单位是 Pod. 一个 Pod 包含一个或者多个容器。当 Pod 失效时,在从节点中运行的 Kubelet 会将该 Pod 进行重启。Kubelet 同时也负责监控节点的运行状态,并向主节点汇报节点的健康程度,同时响应来自主节点的调度要求;系统的用户则连接到从节点的 Kube-Proxy 上,其将会作为 Pod 的路由。

注意到同一个节点的 Pod 之间的流量是不受限制的。Kubernetes 有主从节点和从节点之间的访问控制,但是 Pod 之间的访问控制并不原生支持。如果对 Pod 之间也需要添加访问控制,则需要配置额外的插件。

可以预见,手动配置 Kubernetes 将会是一项费时费力的工作(首先配置主从节点的角色,然后需要设置主从之间的连接,需要配置部署指令,还需要设置从节点上的容器路由)。

APPS40 - 将基础架构与 Azure Kubernetes 服务整合

硬广。毕竟题目已经给出了非常直白的硬广提示。

但指出了一点:基础架构是可以与开发分离的。之前我们一直认为架构和开发是捆绑的,一旦基础架构团队做出更改,很容易把开发带到河里;或者反过来开发要上新的库,但是架构卡着不同意。但上了容器,事情就简单很多了。当然还要管理容器,还要配置 Kubernetes. 广告的买点就是主节点的配置我们干,你只需要配置从节点就完事了,这样架构、开发和运维都可以省事。

APPS50 - 使用监控、性能和缩放增强应用

这场翻车了,演示都没能放出来,所以没啥好谈的。

但指出了一点:遥测功能还是很有必要的。最简单的遥测自然是页面访问量和错误率这种内容,我们也可以为数据库访问添加计时、为页面加载时间添加计时,以及为应用程序添加日志。这样我们在之后的运维和调试过程中能够更快地定位到问题。

BRK30075 - 使用 Xamarin 和 Azure 构建更智能的应用

Xamarin 作为过气技术,能否对标 React Native 或者 Flutter?

答案是大多数肯定的。

Xamarin 的思路在于用 C# 打通全局,这意味着 Xamarin.Android 和 Xamarin.iOS 仍然是使用 C# 进行编写的,再转编译到 IR, 如果必要(因为没记错的话 iOS 是不允许动态加载代码这个操作的)再编译到 Native. 这为开发者提供了一个用一种语言编写所有内容的可能,而无需额外引入 Objective-C/Swift 或者 Java/Kotlin. 以及随着 Xamarin 的开发,现在还有 Xamarin.Essentials 包为移动设备的各种接口(如电话、短信、传感器、摄像头等)提供了支持,不需要开发者自行编写原生模块。

Xamarin 关于 UI 的态度和 Flutter 是不一样的。Flutter 会接管绘图层,完全使用自定义控件,而 Xamarin 则将不同平台的 UI 控件统一成一致 UI 控件,在不同的平台上以对应的控件展示,给用户完全原生的体验。这一点个人认为还是萝卜青菜的。

BRK30086 - 面向数据的思维模式和 R 语言编程

所谓面向数据的思维模式,就是从数据中寻找潜在的规律,并从规律中给出模型且解释模型产生结果的意义。这与开发人员的思路的主要区别在于数据分析是一个从无到有的过程,或者说建立模型的过程;开发则是应用模型的过程。

数据分析还要求能够对模型进行解释,即为什么采用这个模型,这个模型对于数据处理的意义是什么,以及如何评估模型产生的结果的好坏。大部分时间开发的工作是把数据倒入线性代数的大缸里面一顿狂搅,得到的结果也只能两眼一抹黑地糊上去;但要做更切实的数据分析的话,还是绕不开解释性问题。

所以数据分析常用的语言是 R 而不是 Python. R 在设计上更偏向于对领域内知识的支持,意味着它对于特定的学科常用的数学工具有更好的支持;Python 则在这一方面弱许多。

OPS30 - 从失败中学习

任何足够复杂的系统都会爆炸,只是爆炸的早晚而已。

首先需要知道,任何复杂的系统都不可能是百分百运作的,任何线上的复杂系统必然隐含可能导致爆炸的 bug. 尽管我们在 OPS10 和 OPS20 中给出了如何预防爆炸和爆炸之后的对策,我们仍然不可能做出完美的系统。因为首先,这套系统不仅包含代码,也包含编写代码和维护代码的人;其次,这套系统的外部环境并非一成不变,随着环境的变更,设计也有可能随之失效。这些内容都可以从 How Complex Systems Fail 这篇论文中给出。

虽然开会很烦人,但是从爆炸中恢复的会议还是得开,而且最好是恢复后的一天之后开,因为早了的话心累,没效果;晚了的话具体的细节就忘了,也没效果。之前的 OPS20 中已经提过了当系统爆炸时我们应如何应对,OPS30 则阐述我们如何从爆炸中汲取经验,避免之后在同一个坑里跌倒。在这个会议上,应该着重于讨论三个内容:哪里出错了、为什么会出错,以及错误是如何被解决的。

哪里出错了很好理解,但是注意到我们要找出具体的哪一次提交导致了现在的错误。(啥?你还没有上版本控制?)以及尽管提交日志中会包含是谁写的代码,也不要当即算账——一个是因为开除删库的人是没法解决问题的;再者是当初在编写代码时,对方可能有充足的理由按这个方法进行设计,但是随着变更该设计失效了,这并不是编写者的错误,因为没人能完全预见未来的发展。当事后诸葛亮是没啥意思的。

为什么出错也好理解,但是注意到在总结原因时很容易掉入四个陷阱当中:推给人为错误、推给早知当初、推给人员太菜、推给运维瞎搞。

我们可以安全地假定一个正常的人是不会去故意犯错的,人为错误的产生几乎必然是因为在当时的情况下,用户的操作对他们而言是正确 (make sense) 的。所以,当遇到所谓人为错误的时候,仍然有必要深挖下去。

任何早知当初的言论在会议上都是没有必要提的,因为不要忘了,设计这套系统的人是不知道结果的。我们现在拿着结果去捅设计者是无法总结出任何有意义的结论的。

尽管人员太菜可以是一个系统爆炸的原因,但也没有必要提。相信开发者并不会故意设计出无效的系统,对于他们而言,这个系统的设计必然是其能给出的最好结果。以一种居高临下的姿态去看待问题是不会有任何收获的。

假如从此冻结生产环境,不允许你更动任何配置、进行任何新的部署,甚至不允许登录后台,那么这个生产环境能保持多长时间不爆炸呢?一年?一个月?一个星期甚至更短?很容易可以知道系统的正常运行离不开人的时刻监控和调配,单纯地甩锅给运维似乎有点不太厚道。

之后是最重要的一点:错误是如何被解决的。我们注意到有很多解决方案是来自于工作经验的,如果没人讨论这些经验性的内容的话,它将永远属于个人。这对于培养专家个体很有利,但是这会使得知识壁垒形成,在之后的运维过程中,所有的工作都必须被转交给这个人来做,一旦他因任何原因不在现场,那么工作就会严重受阻。如果这些工作经验能够在小组内分享出来,那么大家都具有相似的知识水平,在处理问题时可以进行有效合作,事半功倍。

OPS40 - 更高可靠性的部署实践

硬广。

当然,还是有技术要点的:接 THR30034 和 OPS30 来说,The Epic Deployment 之所以让人感觉痛苦,是因为这种部署操作是复杂的、难以复现且依赖于专家个体的。(尽管这对于那个特定个人来说是一个优势,因为这种部署只有他一个人可以在出问题的时候解决,这样他就会在团队内有一个稳定的位置;但我们在管理者的角度还是希望这种类型的不可替代少一些为好。)

近年来我们引入了持续集成和持续交付的概念,也就是将小片段的代码提交并作为新版本部署到测试环境中。小片段比新版本更容易控制、测试、跟踪和回滚,这使得其开发效率比大版本更新要更高。将持续集成和持续交付结合,并将部署目标设置为生产环境,就产生了持续部署。

持续集成的要点在于测试的及时性。开发人员可以在提交代码后立刻看到自己的代码的测试结果,及时的测试反馈可以辅助开发人员对代码进行及时的修正,降低在测试环境的错误概率。持续交付的要点在于自动化的部署,将目前已经通过测试的代码部署到测试环境,这个自动部署环节可以参考 APPS30 进行;持续部署则可以通过 THR30034 中提到的方法将测试环境推入生产环境。And everything works.

BRK40013 - 基于牛顿冷却定律的热度排名算法

续之前的 BRK30086. 有时我们需要针对一个问题设计一个新的算法,那么我们如何汲取灵感、设计模型并评估结果呢?

在这个例子里,我们以热榜排序为问题进行模型的设计。一个(过于)直白的设计是为待排序的内容的各项属性(比如访问量、赞同数、反对数、页面停留时间等)赋予权重,然后直接相加得到一个排序值进行排序。

这种排序方法严格依赖于权重设计。这也意味着如果我们的权重设计稍有偏差,就很容易被水军利用。而且当前设计并没有考虑时间,对于具有时效性的热榜,很容易出现少数内容始终霸榜的问题。一个方案是将时间也引入到权重当中,但是这样又很难设置时间权重使得真正有讨论价值的内容保持在榜。

那么,我们或许可以借鉴散热本身这个行为来设计一个排序模型。不过首先,我们需要对散热本身进行建模。

首先,我们收集一些实验数据,具体而言,我们可以收集静置开水的温度数据,得到初始数据集。我们可以更改一些变量来得到多组数据。

之后,我们要画一条曲线来拟合这些数据。从直观上可以看出,温度的耗散可能是指数的,即有

$$ T(t) = (T_s - T_0) e^{-kt} + T_0 $$

式中,\( T_s \) 是初始温度,\( T_0 \) 是环境温度,\( k \) 是一个常数。

现在要对某一组数据集的 \( k \) 进行估算。如果我们从上述公式中反推的话,有

$$ k = -\Delta t ln(\frac{\Delta T}{T_s - T_0}) $$

我们将这个公式带入数据集,会发现 \( k \) 即使在同一个数据集内也不是一个定值。我们该如何给定 \( k \) 呢?一个直白的方案是使用 \( k \) 的平均值。我们如何知道使用平均值而不是其他函数是可以产生一个有效的拟合呢?甚至,我们如何知道这个拟合公式是正确的呢?这就需要进行模型的检验。

一般情况下,一个检验的方案是使用 t 检验和 F 检验检查模型的均值和方差是否和数据集的均值和方差相等。但是这仅在总体符合正态分布时可以使用。我们使用 Shapiro–Wilk 检验会知道对于散热模型,它的数据并不是正态的。那么我们可以转用卡方检验检查模型的拟合程度。经过检验可以知道当使用 \( k \) 平均值进行拟合是正确的。

现在,我们有了这样一个公式,如何运用这个公式设计一个热榜系统呢?这个公式内的变量有一个:\( k \). 通过调整 \( k \) 的大小我们会发现这个值决定了曲线的陡峭程度;这个公式外的变量也存在,就是用户对内容的反馈应该影响内容的排序值。这时,我们可以按这样的思路进行设计:首先,确定时间颗粒度(即 \( \Delta t \) )的大小;之后,我们给定一定时间跨度内没有获得任何交互的内容的排序值,即可得出 \( k \) 的大小。延续这种思路,我们也可以计算在不同的访问量、点赞数、转发量的情况下对于排序值的影响,进而得出一个可解释的、突变量少的热榜算法。


一些遗憾

比较遗憾的是有许多 WinHEC 的会议由于时间冲突没能去成。不是有许多,是一场都没去;以及有些感兴趣的会议也必须做出取舍。以及这个会议的日程表是按照美式日程排的,中午的吃饭时间只有约 30 分钟,很是紧张,所有会议则都在下午 4 点半就结束了,拉开了 1.5 小时的空窗期。这一点自然是所有去过的同志们都会吐槽的。

  1. […] Docker 的最主要原因还是为了避免 Epic Deployment (APPS* 系列) 的发生。尽量地解耦 Infrastructure 和 Development. Epic Deployment […]

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注