从 Dagger 到 Hilt,谷歌为何执着于让我们用依赖注入?

开始

说到依赖注入,做 Android 的人都会想到一个库:Dagger;说到 Dagger,大家的反应普遍是一套三连:牛逼、高端、我才不用。

又牛逼又高端,为什么不用?因为太难了。是吧?又难学又难用。大多数的人在学习 Dagger 的路上就被直接劝退了,剩下的这一小撮人*终排除万难,学会并且用上了 Dagger,但多半都是用着用着就掉进了自己亲手用 Dagger 搭建的迷宫里,怎么也绕不清楚,而且越陷越深,就这么成年累月地被它折磨。

有人可能会说:难用就别用呗?拆出来啊。

拆?哼哼。你对 Dagger 一无所知。

而就在上个月,Android 团队又在 Jetpack 里面又增加了一个新的依赖注入库:Hilt。这个 Hilt 是专门针对于 Android 平台的依赖注入库,它是基于 Dagger 的。

啊?基于……Dagger?这次到底是真正的神器到来,还是又一个大坑?

%title插图%num

依赖注入是什么?

Dagger 的名字取自有向无环图 DAG (directed acyclic graph):

%title插图%num

因为程序里的依赖关系拼接起来就是一个或者多个有向无环图:

%title插图%num

DAG-er,Dagger,取了个谐音,Dagger 是匕首的意思。而这次的 Hilt 是刀柄的意思,匕首很难用是吧?来,给你个柄。

说得很好听,到底有没有那么好用啊?这是个复杂的问题,且听我慢慢道来~

%title插图%num

依赖注入有什么用

Hilt 好不好用,我们先来看看它是个什么。它是个用注解来进行配置的依赖注入库。注解是它的写法,首先它是个依赖注入库,对吧?什么是依赖注入?一个类里有两个变量,这两个变量就是它的依赖:

%title插图%num

要初始化一个依赖,有两种方法:*,你这个类自己初始化:

%title插图%num

第二,让外部帮你初始化。

其中这第二种,让外部帮你初始化你的依赖,就叫依赖注入。关键在于初始化是谁做的,至于*后一步是你把结果拿过来,还是说你连拿都不用拿,*后一步的赋值工作也让外部来帮你做了,这都不重要,只要初始化工作是外部做的,就都叫依赖注入。

所以 Factory 的使用是依赖注入吗?

%title插图%num

是的。

Builder?

%title插图%num

也是。

带参数的构造函数?

%title插图%num

也是!

这些都属于由外部来提供依赖的初始化,所以都是依赖注入,并不是非要像 Dagger 那样使用注解的像魔法一样的才叫依赖注入。也就是说,其实我们每个人都已经在使用依赖注入了。虽然很多人在面对 Dagger 的时候会问「依赖注入到底有什么用」,但其实 Dagger 并不是提供了依赖注入的能力,而是为依赖注入提供了一种更简单的方式。依赖注入本来就是有用的,这个问题不想明白,不管是 Dagger 还是现在的 Hilt,你都用不好。

Dagger 让我们可以用注解的方式来配置依赖关系,让依赖注入变得更方便。不过由于功能复杂,导致它的上手非常困难;再加上刚才我说的,很多人对于依赖注入的作用以及 Dagger 的定位都没搞清楚,这两个原因加起来,就导致很多人还没学会 Dagger 就把它弃了,让 Dagger 成为 Android 史上*受冷落的优质库。这样的结果不论是对 Dagger 还是对我们,都是很可惜的。

而 Hilt 的出现,就直接解决了 Dagger 太复杂的这个问题。

%title插图%num

Hilt 怎么帮助我们进行依赖注入

Hilt 是 Google 专门针对 Android 平台做的一个依赖注入库。它不是从里到外全新开发的,而是基于 Dagger 做的,它的下层还是 Dagger。

为什么不直接去优化改进 Dagger,而要基于它做一个新库呢?因为 Hilt 做的事其实也并不是对 Dagger 进行优化,而是场景化:针对 Android 开发制定了一系列的规则,通过这些规则大大简化了这套工具的使用。例如在 Dagger 里,你要对某个类的依赖进行注入,你需要手动获取依赖图和执行注入依赖操作:

%title插图%num

而在 Hilt 里,注入会自动完成:

%title插图%num

因为 Hilt 会自动找到 Android 的系统组件里面那些*佳的初始化位置——比如 Activity 的 onCreate() ——然后在这些位置注入依赖。所以,为什么不是去优化 Dagger,而是做了个新库?因为 Hilt 本身并不是一种优化,而是场景化,或者说,它是一种针对场景的优化。总之,它是不通用的,只能给 Android 用,所以不能放在 Dagger 里。

有点明白了吧?

那它具体怎么用呢?大概是这样的:

我们程序里有些对象是全局共享的,比如线程池,或者 Retrofit 对象,这种东西我们通常会把它放在 Application 对象里,或者做成单例的:

%title插图%num

而如果用 Hilt,你也可以把它做成自动注入的依赖:

%title插图%num

还有些对象是局部共享的,比如某个 Activity 会把一些显示用的数据共享给它内部的一些 View 和 Fragment。这一类情况我们的做法通常是获取外部 Activity 对象然后强转,再去拿它内部的对象:

%title插图%num

而如果用 Hilt,你可以把这个对象直接声明出来,让它自动注入:

%title插图%num

这不只是一个「美观」的差别,依赖注入可以让你的程序更加灵活,比如如果你的 View 可以在多个不同的 Activity 里显示,那你在 View 里面要怎么强转?你要转成谁?

%title插图%num

很麻烦,是吧?而如果用依赖注入,这些就都是自动的。

除了共享的对象,不共享的也可以用依赖注入的方式来进行初始化,因为依赖注入的作用除了对共享对象提供一致性支持,也可以让我们在创建任何对象的时候省一些思考和力气:

  1. @Inject newUser: User

总之,如果一个组件可能会被被共享,或者不会被共享但可能会在多处使用,你都可以使用 Hilt 来把它配置成依赖注入的加载方式。

加载的方式可以选择直接调用构造函数:

%title插图%num

或者指定子类或实现类:

%title插图%num

或者干脆给出具体的代码:

%title插图%num

加载的作用域可以选择默认的每次都初始化,也可以设置成全局单例的:

%title插图%num

也可以设置成针对任何 Activity、Fragment、View 或者 ViewModel 的局部共享:

%title插图%num

简单又强大,好用又灵活。具体的写法你可以去看文档,或者过段时间我会有一次公开课,到时候也会提前通知大家。

到这里有的人可能会分个叉可能会想:诶 ButterKnife 或者现在 Jetpack 推出的 ViewBinding 它们提供的功能,Hilt 提供了吗?因为如果提供了,我在用了 Hilt 之后,不就可以把 ButterKnife 和 ViewBinding 扔掉了?

不好意思,Hilt 不提供它们的功能。Hilt 和 Dagger 虽然用法和 ButterKnife 很像,都是给变量加注解,然后变量会自动赋值,但它们的功能定位是不一样的:Hilt 和 Dagger 是做依赖注入的,而 ButterKnife 和 ViewBinding 是做视图绑定的。

这可不是个文字游戏,依赖注入和视图绑定是有本质区别的:依赖注入是由外部对对象进行初始化,也就是所谓的控制翻转;而视图绑定是让变量去指向一个已经有了的 View,它的依赖依然是由依赖持有者自己决定的,这是一个本质的区别。

%title插图%num

Dagger 为什么难用

这么看来,Hilt 还是很好用的,是吧?那有些人就又有问题了:哎,Hilt 这么好用,那Dagger 真的难用吗?到底难用在哪了?

其实说白了,Dagger 的难用主要在于这个框架太强大和灵活了,导致你要遵守很多约定才能正确使用它。比如在 Hilt 里,一个注解就能让 Activity 内部的依赖自动被注入,而 Dagger 需要手动注入;再比如在 Hilt 里如果你想让一个对象只在 Activity 内部被共享而不是全局共享,也就是一个注解能解决的问题,而在 Dagger 里面你需要先去创建一个自定义的注解。这些难吗?每个都不难的,对吧?但把它们放在一起,让你灵活搭配使用,就有点难了。

另外,Dagger 被大家普遍认为难的另一个原因刚才我也说过了:很多人连依赖注入都不太懂的。所以我再说一遍:如果一个组件可能被共享,或者可能在多处被使用,你可以使用依赖注入来初始化它。然后,在需要依赖注入的场景里,使用 Dagger 能让你的依赖注入写起来更简单。*后,Hilt 进一步简化了这个事情。先知道它是什么,再去用它。

服务器内存缓存清理

1、内存查看
free -h #以GB为单位展示当前系统内存数据
free -m #以MB为单位展示当前系统内存数据

2、直接清除缓存
echo 1 > /proc/sys/vm/drop_caches
echo 2 > /proc/sys/vm/drop_caches
echo 3 > /proc/sys/vm/drop_caches
#说明
#echo 1 > /proc/sys/vm/drop_caches:表示清除pagecache,当前产链服务器缓存主要在这里。
#echo 2 > /proc/sys/vm/drop_caches:表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。
#echo 3 > /proc/sys/vm/drop_caches:表示清除pagecache和slab分配器中的缓存对象。

3、脚本清除
(1)root账号登陆服务器
(2)新建文件夹 /opt/clean和/opt/clean/logs
(3)新建freemem.sh脚本
(4)给freemem.sh脚本赋权777

3.1、脚本内容
#! /bin/sh
used=`free -m | awk ‘NR==2’ | awk ‘{print $3}’`
free=`free -m | awk ‘NR==2’ | awk ‘{print $4}’`
echo “===========================” >> /opt/clean/logs/mem.log
date >> /opt/clean/logs/mem.log
echo “Memory usage before | [Use:${used}MB][Free:${free}MB]” >> /opt/clean/logs/mem.log
if [ $free -le 4000 ] ; then
sync && echo 1 > /proc/sys/vm/drop_caches
used_ok=`free -m | awk ‘NR==2’ | awk ‘{print $3}’`
free_ok=`free -m | awk ‘NR==2’ | awk ‘{print $4}’`
echo “Memory usage after | [Use:${used_ok}MB][Free:${free_ok}MB]” >> /opt/clean/logs/mem.log
echo “OK” >> /opt/clean/logs/mem.log
else
echo “Not required” >> /opt/clean/logs/mem.log
fi
exit 1

3.2、设置脚本定时执行
(1)使用crontab -e命令编辑crontab,文末添加

0 6 * * * /opt/clean/freemem.sh
# (0 6 * * * )为cron表达式,可根据实际需求自行调整时间

(2)重启crond服务

/sbin/service crond restart

服务器磁盘读取暴涨_CPU、内存、存储、带宽,一次性搞清楚服务器资源评估

不知道您在开发应用系统、申请服务器资源时有没有经常遇到CPU、内存、存储、带宽等概念?是不是有时候也搞不懂这些概念都是什么,更搞不清楚如何评估资源需求,申请少了了系统不够用,申请多了造成浪费,甚至无法通过审批。不管你有没有遇到,反正我是经常遇到[哈欠]

#服务器# #内存# #存储# #带宽#

本文结合日常工作经验对CPU、内存、存储、带宽等基本概念进行基本介绍并聊一聊如何有效的评估资源需求,不妥之处,欢迎评论区留言交流!

CPU核数(C)

CPU是中央处理器,其表征了服务器的处理能力,CPU个数越多,核数越多,那么服务器的处理能力就越强。这里要说明的是,CPU个数和核数不一样,因为现在的CPU往往是多核的,也就是一个CPU有多个核心,因此CPU核数=CPU个数*每个CPU的核数。

不考虑超线程的情况下,服务器的CPU核数表征服务器同一时间能够运行的进程/线程个数。实践中,经常会说到4c、8c、16c、32c,这些都是指CPU的核数。

对于一般的业务系统,没有复杂的业务运算,对性能要求比较低,可能8c、甚至4c就够用了;而对于一些计算密集型的系统,如大数据类的系统,往往需要配置较多的CPU核数,32c、64c比较常见。

# 总核数 = 物理CPU个数 X 每颗物理CPU的核数

# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

# 查看物理CPU个数

cat /proc/cpuinfo| grep “physical id”| sort| uniq| wc -l

# 查看每个物理CPU中core的个数(即核数)

cat /proc/cpuinfo| grep “cpu cores”| uniq

# 查看逻辑CPU的个数

cat /proc/cpuinfo| grep “processor”| wc -l

%title插图%num

内存(G)

众所周知,服务器的存储分为内存和外存(磁盘存储)。在内存中的数据靠近CPU,读取和处理的速度非常快,在磁盘上的数据读取和处理的速度慢不少。因此,很多业务系统会使用内存进行性能加速。

如何评估需要多大内存的服务器,这个主要看需要把多少数据灌到内存里进行计算。如果是一般的业务系统,数据量不大,8G、16G、32G的内存也就够用了;对于大数据、人工智能、数据挖掘、BI等处理数据量较大、对处理要求较高、设计上使用内存计算的一些平台,可能需要32G、64G、128G,甚至更高。

具体评估时,可以找一个需要内存计算的场景,把可能处理的数据量测算一下(比如数据表的行数、列数、字段长度、字段类型等),就可以得出大概的内存需求。

存储(G、T)

内存中的数据虽然快,但不可保存、易丢失,因此对于需要持久化的数据还是要保持在磁盘上,比如日志文件、数据文件、系统文件等。跟个人终端一样,服务器磁盘的大小也远大于内存的大小,基本是500G、1T、2T、4T这种。

磁盘概念比较好理解,那么怎么评估呢?

一种评估方式就是测算每天的日志文件、数据文件等新增文件的大小,按照数据清洗策略,测算一定周期内日志、数据文件的总大小,再加上程序文件、冗余备份等需要的大小,就可以得到应用系统需要的磁盘大小,

同样的,一般业务系统可能500G、1T就足够了,但对于数仓、大数据平台这种大数据量的处理系统,动辄好多个T都很正常。当然了,对于实际的企业应用来说,现在存储很少是直接一块一块硬盘的方式挂在服务器上,多是以外挂的方式存在,方便文件共享和管理。

带宽(M)

这个概念大家应该比较熟悉,因为在应用系统中经常涉及到系统的交互和数据的传输,这些都需要依赖于网络,如果网络带宽不够那么数据传输和系统交互的效率就很低,直接影响应用系统的性能。常说的带宽有百兆、千兆、万兆等,现在百兆在企业里很少存在了,基本都是千兆和万兆。

对于应用系统来说,一是要看系统的级别及其对性能的要求有多高,二是要看数据传输的大小和系统交互的频次。如果基本没有跨设备的数据传输和高频的跨设备的系统交互,那么千兆往往够用了;如果经常在跨设备上进行大量数据传输,那么还是万兆吧,不然就一个感觉:好慢啊!!

总结

上面介绍了CPU、内存、存储、带宽的基本概念和评估方法,希望对您申请资源有帮助。但这里必须要强调一点:资源的使用都是有成本的,要节约,不要浪费,不要盲目扩大资源需求,毕竟闲置的资源都是白花花的人民币啊。

节约资源,从每一个应用系统做起。

下一代 IDE:Eclipse Che 究竟有什么奥秘?

Eclipse Che被Eclipse官方称为下一代IDE,作为老牌的IDE,被其寄予厚望的Eclipse Che到底有什么特点,在这篇文章中我们来一探究竟。

%title插图%num

开发团队的Kuberentes原生IDE

Eclipse Che对开发团队来进行Kubernetes开发使能,提供了一键生成开发者工作空间的功能,消除了团队本地环境配置的操作。Che可以将Kubernetes应用更容易地发布至开发环境,并且提供了一个基于浏览器的IDE,使得开发者可以从任何机器进行编码、测试和运行应用程序等操作,所有的一切只需要提供一个浏览器即可。

%title插图%num

功能特性

生产运行环境

Eclipse Che可以支持各种容器,甚至是多容器的运行环境。可以在Kubernetes、OpenShift或者Docker环境中运行,Chec可以使用从DockerHub或者开发者自己的镜像私库,通过添加基于SSH的Agent,使得生产镜像通过终端和语言服务可以具有开发环境功能,停止时,Che也可以保存工程相应的关键状态信息。支持和实现此项特性的基础能力主要包括:

  • 容器运行环境
  • Compose运行环境
  • SSH访问
  • 根用户终端访问
  • 预构建和自定义的组件
  • 工作空间快照

    %title插图%num

工作空间的开发模式

通过Agent为工作空间添加开发者服务包括语法自动补齐、错误检查和调试工具等。针对不同语言提供智能提示,可以启用根用户或者SSH访问方式。支持和实现此项特性的基础能力主要包括:

  • 语言服务器
  • 智能提示与重构
  • 调试器
  • 工作空间Agent
  • 智能命令
  • SSH访问
  • 根用户终端访问

    %title插图%num

可使用任何IDE

可以在任何设备上进行工作,无需安装软件,因为Eclipse Che IDE已经提供了内建方式。也可以使用开发者自己喜欢的桌面IDE,只需要挂载Che工作空间即可,一切可根据用户自行选择。支持和实现此项特性的基础能力主要包括:

  • 浏览器IDE
  • RESTful 工作空间API

%title插图%num

团队开发

基于生产镜像创建定制的团队可用的组件和运行环境,包括开发所需要的工具。所有人都可以使用这样的组件或者拷贝工作空间来快速创建可以用于生产环境的应用。甚至可以通过添加示例代码来实现对新人进行培训的目的。支持和实现此项特性的基础能力主要包括:

  • 组件运行环境
  • 团队工作空间
  • 项目示例

    %title插图%num

语言服务协议

语言服务协议(Language Server Protocol )是由Microsoft, Codenvy, Red Hat 和 IBM共同开发的协议,包括语法分析,高亮以及在Eclipse Che内的重构代码。协议用于在客户端工具和语言服务之间进行功能特性的集成,比如自动不起、定义跳转和搜索所有引用等。

%title插图%num

调试器

Che可以在开发者的工作空间中插入调试代理以允许变量监控和替换、断点设定、但不调试和其他常用的调试操作。调试器可以与组件或者用户工作空间进行关联。

%title插图%num

SSH / 终端

Che向工作空间关联的操作系统中添加SSH守护进程,使用ssh连接开发者自己的IDE比如Eclipse,上传死钥或者使用Che为每个工作空间创建密钥对。通过Che的浏览器终端,开发者可以访问自己的工作空间,并且具有工作空间所关联操作系统的根用户权限。

%title插图%num

组件

组件指的是工作空间的运行环境配置,包含运行环境所需要的构建文件(recipe)和元数据信息比如标签、描述信息、环境名称以及安全策略等。组件在用户的仪表盘中被展示,组件标签tag可以用于过滤可用的工程代码示例。组件的构建文件可以是Kubernetes YAML、Dockerfile或者Docker Compose文件,可以通过这些文件的方式来创建潜入到工作空间的运行环境。Che已经提供了30+的内建的组件可以用于开发者的工作,当然也可以创建自己的组件。

%title插图%num

RESTful的工作空间

所有的Che服务都可以通过RESTful API进行访问,无论是通过工作空间的master还是agent,Che都提供了可以使用的API进行操作。工作空间master提供了工作空间管理和用户管理,而在每一个工作空间中,agent就是一个微型的提供了项目相关API的Che服务器,比如Che通过RESTful JDT wrapper提供了100+的Java智能提示能力。Che使用Swagger用于浏览和管理API。

%title插图%num

可扩展的云IDE(Cloud IDE)

Che提供了一个可以从本地或者远端设备上进行访问的免安装的浏览器IDE。简、快、美:这是IDE和开发者所期待的。IDE使用了跨浏览器的JavaScript和CSS来实现,通过浏览器来进行使用,使用浏览器不同的tag页面可以打开不同的工作空间,每个空间消耗100M以下的内存,流畅的用户交互体验也不会因工作空间在远端而受到影响。Eclipse Che基于Eclipse Theia提供了VSCode体验的WebIDE功能,提供了*新的工具协议,包括语言服务、调试适配器以及和VSCode扩展的兼容性。对于更倾向于使用个人桌面IDE的用户,Che同样支持。同时提供了很多流行的工具包括:

  • 嵌入式的Orion编辑器
  • 按键绑定
  • 全球化的键盘支持
  • git / subversion工具

%title插图%num

多工程管理

Che是一个真正的IDE平台,识别项目并绑定至仓库并指定类型,不同项目类型被赋予不同行为,比如Java项目被添加时,Che会添加RESTful JDT core的功能到相应的工作空间。工作空间可以有多个工程,每个工程都有自己的类型,虽然共享于一个工作空间,每个工程都可以被独立的构建和运。当下,Che的工程类型仍然有限,主要包括JavaScript、Maven和空工程类型。后续将会进一步和社区生态即可提供更多选择。

%title插图%num

命令

Command是运行在工作空间所在操作系统的一个进程,可能是用户、工作空间或者项目相关。
命令具有不同类型,不同类型的命令具有特定的行为,比如Maven命令类型就包含生命周期阶段运行相关的内容。命令执行时,可以对项目和其他资源进行操作,允许用户跨项目和模块执行命令,执行时并与一定的上下文相关联。

%title插图%num

预览

提供预览的功能,可以针对项目的上下文和工作空间,创建和显示用于预览的Web页面,同时,和预览功能结合,通过相应的命令,在工作空间中可以更好地启动和调试。

插件

Che可以通过使用定制化内建的插件或者使用者自己的插件来进行扩展。可以通过使用Che提供的方式生成用户自己的插件,用户可以编写插件来操作IDE、Che服务器或者工作区代理,插件会由Che在合适的时间插入到应该插入的位置。

%title插图%num

%title插图%num

整体架构

%title插图%num

%title插图%num

用户视角

  • 开发者
    可以使用Che作为IDE进行任何框架和语言的编写,可以有助于工程和运行环境更加具有可移植性,同时上云更加简单。
  • 产品负责人
    可以通过将Che嵌入到产品之中,只需要通过API进行控制即可。三星、SAP和红帽等使用Che创造了很好的开发者体验。比如SAP的WebIDE

    %title插图%num
    再比如Codenvy,做了企业级的Che使用封装

    %title插图%num

  • 扩展提供者
    可以使用组件、模版、扩展和插件进行新的开发者工具的创建,更好地利用和扩展使用方式。

%title插图%num

总结

Eclipse Che有强大的背景公司的技术力量的支持,有众多既有用户的追随,是后续云IDE选型中不可忽视的一个选择项。

作者简介:淼叔,资深架构师,PMP、OCP、CSM、HPE University讲师,EXIN DevOps Professional与DevOps Master认证讲师,曾担任HPE GD China DevOps & Agile Leader,帮助企业级客户提供DevOps咨询培训以及实施指导。熟悉通信和金融领域,有超过10年金融外汇行业的架构设计、开发、维护经验,在十几年的IT从业生涯中拥有了软件开发设计领域接近全生命周期的经验和知识积累。

原文链接:https://blog.csdn.net/liumiaocn/article/details/108267949

如何用Chrome读懂网站监测Cookie

网站监测工具用于标识用户的 Cookie 分为第1方 Cookie 和第3方 Cookie,这两者本质上没有什么区别,只是身份不同。Cookie 有 Domain 属性,当 Cookie 的 Domain 与当前访问的域名不同时,这个 Cookie 为第3方 Cookie,反之为第1方 Cookie。

由于 Domain 的不同,第1方 Cookie 记录的是用户在指定站点的行为,第3方 Cookie 记录的是用户在不同站点的行为。网站监测工具为你的站点创建了第1方 Cookie,这个 Cookie 属于你的站点,仅能用于记录你站点的用户行为,同时网站监测工具也创建了第3方 Cookie(属于它自己的Cookie),这个 Cookie 用于记录所有部署了监测代码站点的用户行为。

以 Chrome 为工具,我们来看看 Cookie 是怎么样的。

查看Cookie

步骤:打开 Chrome > 访问 www.zhihu.com > 按下 F12 打开 DevTools > 切换到 Application 面板 > 打开左侧 Cookies > 选择 www.zhihu.com。

可以看到,Cookie 有各种属性:

• Name:Cookie 名称。

• Value:Cookie 值。

• Domain:Cookie 域名,代表能读写这个 Cookie 的域。假设在 DevTools 这里 Domain 为“.zhihu.com”(*前面带点),则所有以“zhihu.com”结尾的域名都能读写这个 Cookie。假设 Domain 为“zhihu.com”(*前面不带点),此时 Cookie 仅为当前域所用。如果创建 Cookie 时不声明 Domain,则 Domain 的*前面不带点。如果创建 Cookie 时声明 Domain,则无论声明时有没有带点,在 DevTools 都会自动带点,所声明的域及其所有子域都能读写这个 Cookie。

• Path:Cookie 的有效访问路径,代表基于 Domain 下能读写这个 Cookie 的页面路径。假设 Domain 为 “.zhihu.com”,Path 为 “/”,则 zhihu.com 根目录下所有页面路径都能读写这个 Cookie,如果 Path 为 “/question”,则 Cookie 仅在 question 页面路径下能被读写。

• Expires/Max-Age:Cookie 的过期时间,采用协调世界时(UTC),与中国标准时间相差8小时。时间格式为 ”yyyy-mm-ddThh:mm:ss.sssZ”,T是分隔日期和时分秒的符号,”.sss” 代表毫秒,Z 表示 UTC 零时区。如果创建 Cookie 时默认不填,则此值为 Session,即关闭浏览器自动清除 Cookie。

• Size:Cookie 的大小。

• Httponly:是否允许客户端读写Cookie,常见客户端方法有 document.cookie。

• Secure:是否只能通过 Https 协议读写 Cookie。

• SameSite:跟第3方 Cookie 的读写限制有关,我们后面会讲到。

• Priority:Cookie 的优先级,有 Low/Medium/High 这3种值,当 Cookie 超出浏览器存储上限时,优先级低的 Cookie 将被清除。

第1方Cookie

网站监测工具标识用户常用第1方Cookie,即Cookie的Domain为当前访问站点的顶级域名。以Google Analytics为例(以下简称GA),下面这个蓝底色的就是GA标识用户的Cookie,它的Domain为”.zhihu.com”,所以它为第1方Cookie。

GA 标识用户的 Cookie,Domain 为 ”.zhihu.com”,意味着这个 Cookie 在 zhihu.com的所有子域名下,都能被读写。因此,zhihu.com、www.zhihu.com、daily.zhihu.com、static.daily.zhihu.com 在用同一套监测代码的时候,标识用户所用的 Cookie 是一样的。

GA 标识用户的 Cookie 名称为 “_ga”,它的值是这样构成的:

• 版本号:GA1 为版本相关信息,所有被 GA 监测的站点几乎都一样。

• Domain长度:2为 “_ga” 这个 Cookie 的 Domain 长度,”.zhihu.com” 长度为2。当被监测的站点为 ”xxx.com.cn” 时,Domain 长度为3。当被监测的站点使用多级域名例如 ”www1.www2.xxx.com” 时,在 GA 的这个 Cookie,Domain 依然为顶级域名 ”.xxx.com”,长度依然为2。

• 唯一的随机数:GA 生成的随机数字,具有唯一性。

• 首次访问的时间戳:用户首次访问站点,GA 获得的时间戳,你可以打开 Chrome DevTools 的 Console 面板,用 new Date 把它转换成中国标准时间。这个时间再加上2年,等于这个 Cookie 的 Expires/Max-Age 的中国标准时间,也就是说 GA 标识用户的 Cookie 有效期为2年,2年之后 Cookie 被清除。

从GA的JS代码,也能看出这个值的构成:

那么,这个第1方 Cookie 属于被监测的站点,但又是由 GA 创建,这是怎么一回事?

GA 的 JS 代码包含创建 Cookie 的方法,这段 JS 被嵌入到网站,相当于网站自己创建了 Cookie,因此这个过程不存在跨域的问题。目前市面上的网站监测工具都是用这样的方法来创建第1方 Cookie 的。换言之,GA 这段 JS 也能够读写这个站点的所有第1方 Cookie(已设置 Httponly 的除外)。

第3方Cookie

网站监测代码在发起请求时,能创建 Domain 不同于当前站点的 Cookie,也就是第3方 Cookie,它一般用于追踪用户在不同站点的访问行为。

以百度统计为例,只要你的站点部署了百度统计代码,就能看到这个名为 ” HMACCOUNT_BFESS” 的第3方 Cookie,它看起来就是这样的字符串:

这时右键选中 Cookie,选择 ”Show Requests With This Cookie”:

打开了 Network,点击第1个请求,拉到 Request Headers 会发现有2个 Set-Cookie,说明这个第3方 Cookie 这是由服务器端设置的:

第1个的末尾标记了黄色符号,代表这个 Cookie 没有创建成功,因为创建时没有设置 SameSite 和 Secure。第2个 Cookie,也就是 ”HMACCOUNT_BFESS”,因为同时满足 SameSite=None 和 Secure=Ture 这两个条件,Cookie 能被创建。

SameSite 属性是什么?这是一个限制第3方 Cookie 创建、读写的属性。从 Chrome v80 开始,对第3方 Cookie 的限制就严格了许多。现在想要创建第3方 Cookie,需要满足以下条件:

①通过 Https 协议

②设置 SameSite 为 None

③设置 Secure 为 True

当一个 Cookie 作为第3方 Cookie 时,它能不能被读写,由 SameSite 决定。当然这个读写,还是必须先取决于 Cookie 的 Domain,否则就成跨域了。SameSite 有以下3种值:

①Strict

假如 Cookie 的 SameSite为Strict,则当它作为第3方 Cookie 时会被完全禁止读取,尽管你可能在 DevTools 的 Application 面板还能看到这个 Cookie。

②Lax

假如 Cookie 的 SameSite 为 Lax,那么当请求为以下类型,才能读写这个第3方 Cookie:

Lax也是Chrome的默认设置。

③None

想要关闭 SameSite 属性,可以设置第3方 Cookie 的 SameSite 属性为 None,要想读取 Cookie 同时还必须设置 Secure 为 True。这也是为什么我们看到百度统计的 Cookie 设置了 SameSite=None 和 Secure 属性。

第1方 Cookie 和第3方 Cookie 在网站监测都很重要,如今 Chrome 对第3方 Cookie 的限制越来越强,为网站监测工具读写第3方 Cookie 增加了一定难度。如何在合理追踪用户行为的同时保护用户隐私,这是一个值得全行业探讨的主题。
————————————————
版权声明:本文为CSDN博主「CSDN云计算」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/FL63Zv9Zou86950w/article/details/108373106

如何对磁盘IO和网络IO该进行评估、监控、定位和优化?

生产中经常遇到一些IO延时长导致的系统吞吐量下降、响应时间慢等问题,例如交换机故障、网线老化导致的丢包重传;存储阵列条带宽度不足、缓存不足、QoS限制、RAID级别设置不当等引起的IO延时。

一、评估 IO 能力的前提

评估一个系统IO能力的前提是需要搞清楚这个系统的IO模型是怎么样的。那么IO模型是什么,为什么要提炼IO模型呢?

(一) IO模型

在实际的业务处理过程中,一般来说IO比较混杂,比如说读写比例、IO尺寸等等,都是有波动的。所以我们提炼IO模型的时候,一般是针对某一个特定的场景来建立模型,用于IO容量规划以及问题分析。

*基本的模型包括:IOPS,带宽和IO的大小。如果是磁盘IO,那么还需要关注:

  • 磁盘IO分别在哪些盘
  • 读IO和写IO的比例
  • 读IO是顺序的还是随机的
  • 写IO是顺序的还是随机的

(二)为什么要提炼IO模型

不同模型下,同一台存储,或者说同一个LUN,能够提供的IOPS、带宽(MBPS)、响应时间3大指标的*大值是不一样的。

当存储中提到IOPS*大能力的时候,一般采用随机小IO进行测试,此时占用的带宽是非常低的,响应时间也会比顺序的IO要长很多。如果将随机小IO改为顺序小IO,那么IOPS还会更大。当测试顺序大IO时,此时带宽占用非常高,但IOPS却很低。

因此,做IO的容量规划、性能调优需要分析业务的IO模型是什么。

二、评估工具

(一)磁盘IO评估工具

磁盘IO能力的评估工具有很多,例如orion、iometer,dd、xdd、iorate,iozone,postmark,不同的工具支持的操作系统平台有所差异,应用场景上也各具特色。

有的工具可以模拟应用场景,比如orion是oracle出品,模拟Oracle数据库IO负载(采用与Oracle相同的IO软件栈)。

模拟Oracle应用对文件或磁盘分区进行读写(可指定读写比例、IO size,顺序或随机)这里就需要提前知道自己的IO模型。如果不知道,可以采用自动模式,让orion自动的跑一遍,可以得出不同进程的并发读写下,*高的IOPS、MBPS,以及对应的响应时间。

比对DD,仅仅是对文件进行读写,没有模拟应用、业务、场景的效果。Postmark可以实现文件读写、创建、删除这样的操作。适合小文件应用场景的测试。

(二)网络IO评估工具

  • Ping:*基本的,可以指定包的大小。
  • IPerf、ttcp:测试tcp、udp协议*大的带宽、延时、丢包。
  • 衡量windows平台下的带宽能力,工具比较多:NTttcp、LANBench、pcattcp、LAN Speed Test (Lite)、NETIO、NetStress。

三、主要监控指标和常用监控工具

(一)磁盘IO

对于存储IO:Unix、Linux平台,Nmon、IOstat是比较好的工具。Nmon用于事后分析,IOstat可用于实时查看,也可以采用脚本记录下来事后分析。

1. IOPS

  • 总IOPS:Nmon DISK_SUMM Sheet:IO/Sec
  • 每个盘对应的读IOPS :Nmon DISKRIO Sheet
  • 每个盘对应的写IOPS :Nmon DISKWIO Sheet
  • 总IOPS:命令行iostat -Dl:tps
  • 每个盘对应的读IOPS :命令行iostat -Dl:rps
  • 每个盘对应的写IOPS :命令行iostat -Dl:wps

2.带宽

  • 总带宽:Nmon DISK_SUMM Sheet:Disk Read KB/s,Disk Write KB/s
  • 每个盘对应的读带宽:Nmon DISKREAD Sheet
  • 每个盘对应的写带宽:Nmon DISKWRITE Sheet
  • 总带宽:命令行iostat -Dl:bps
  • 每个盘对应的读带宽:命令行iostat -Dl:bread
  • 每个盘对应的写带宽:命令行iostat -Dl:bwrtn

3.响应时间

  • 每个盘对应的读响应时间:命令行iostat -Dl:read – avg serv,max serv
  • 每个盘对应的写响应时间:命令行iostat -Dl:write – avg serv,max serv

4.其他

磁盘繁忙程度、队列深度、每秒队列满的次数等等。

(二)网络IO

1.带宽

  • *好在网络设备处直接查看流量(比较准),如果在业务的服务器也可以查看
  • Nmon:NET Sheet
  • 命令行topas:Network:BPS、B-In、B-Out

2.响应时间

简单的方法,可采用ping命令查看ping的延时是否在合理范围,是否有丢包现象。

有些交换机对ping命令设置了较低的优先级,可能在回复、转发ping包的时候有延迟,因此ping的结果不一定能反映真实情况。如果需要更为精确的测量可以探针捕获从某服务器建立TCP连接时发送的SYN包后开始计时起,到其收到对端发回的TCP SYNACK后的时间差。

更为准确、利于后期分析的方法是采用专业的网络设备在网络设备的端口处进行报文捕获和计算分析。

四、性能定位与优化

(一)对磁盘IO争用的调优思路有哪些?

典型问题:针对主要争用是IO相关的场景下,调优的思路有哪些?主要的技术或者方法是什么?

一、首先要搞清楚IO争用是因为应用等层面的IO量过大导致,还是系统层面不能承载这些IO量。

如果应用层面有过多不必要的读写,首先解决应用问题。

举例1:数据库里面用于sort的buffer过小,当做sort的时候,有大量的内存与磁盘之间的数据交换,那么这类IO可以通过扩大sort buffer的内存来减少或避免。

举例2:从应用的角度,一些日志根本不重要,不需要写,那么可以把日志级别调低、甚至不记录日志,数据库层面可以加hint “no logging”。

二、存储问题的分析思路

存储IO问题可能出现在IO链路的各个环节,分析IO瓶颈是主机/网络/存储中的哪个环节导致的。

IO从应用->内存缓存->块设备层->HBA卡->驱动->交换网络->存储前端->存储cache->RAID组->磁盘,经过了一个很长的链条,分析思路:

  • 1、主机侧:应用->内存缓存->块设备层→HBA卡->驱动
  • 2、网络侧:交换网络
  • 3、存储侧:存储前端->存储cache->RAID组->磁盘

1、主机侧

当主机侧观察到的时延很大,存储侧的时延较小,则可能是主机侧或网络存在问题。

主机是I/O的发起端,I/O特性首先由主机的业务软件和操作系统软件和硬件配置等决定。例如,在“服务队列满”这一章节介绍的I/O 队列长度参数(queue_depth),当然,还有许多其他的参数(如: Driver 可以向存储发的*大的 I/O、光纤卡DMA Memor区域大小、块设备并发数、HBA卡并发数)。

若排查完成,性能问题还是存在,则需要对组网及链路、存储侧进行性能问题排查。

2、网络侧

当主机侧观察到的时延很大,存储侧的时延较小,且排查主机侧无问题时,则性能问题可能出现在链路上。

可能的问题有:带宽达到瓶颈、交换机配置不当、交换机故障、多路径选路错误、线路的电磁干扰、光纤线有损、接口松动等。带宽达到瓶颈、交换机配置不当、多路径选路错误、线路的电磁干扰等。

3、存储侧

如果主机侧时延与存储侧时延都很大且相差较小,说明问题可能出现在存储上。首先需要了解当前存储侧所承载的IO模型、存储资源配置,并从存储侧收集性能数据,按照I/O路径进行性能问题的定位。

常见原因如硬盘性能达到上限、镜像带宽达到上限、存储规划(如条带过小)、硬盘域和存储池划分(例如划分了低速的磁盘)、thin LUN还是thick LUN、LUN对应的存储的缓存设置(缓存大小、缓存类型,内存还是SSD)。

IO的Qos限制的磁盘IO的带宽、LUN优先级设置、存储接口模块数量过小、RAID划分(比如RAID10 > RAID5 > RAID6)、条带宽度、条带深度、配置快照、克隆、远程复制等增值功能拖慢了性能、是否有重构、Balancing等操作正在进行、存储控制器的CPU利用率过高、LUN未格式化完成引起短时的性能问题、cache刷入磁盘的参数(高低水位设置),甚至数据在盘片的中心还是边缘等等。

具体每个环节 都有一些具体的方法、命令、工具来查看性能表现,这里不再赘述。

(二)关于低延迟事务、高速交易的应用在IO方面可以有哪些调优思路和建议?

典型问题:关于近期在一些证券行业碰到的低延迟事务、高速交易的应用需求,在IO模型路径方面可以有哪些可以调优的思路和建议?

对于低延迟事务,可以分析一下业务是否有持久化保存日志的需要,或者说保存的安全程度有多高,以此来决定采用什么样的IO。

1.从业务角度

比如说业务上不需要保存日志,那就不用写IO。或者保存级别不高,那就可以只写一份数据,对于保存级别较高的日志,一般要双写、或多写。

2.从存储介质角度

  • 1)可以全部采用SSD
  • 2)或者采用SSD作为存储的二级缓存(一级缓存是内存)
  • 3)或者存储服务器里面采用存储分级(将热点数据迁移到SSD、SAS等性能较好的硬盘上)
  • 4)可以采用RAMDISK(内存作为磁盘用)
  • 5)增加LUN所对应的存储服务器的缓存

3.从配置的角度

普通磁盘存储的LUN,可以设置合理的RAID模式(比如RAID10)去适应你的业务场景。

分条的深度大于等于一个IO的大小、有足够的宽度支持并发写。

4.IO路径的角度

采用高速的组网技术,而不用iSCSI之类的低速方式。

(三) 网络IO问题定位思路和方法

与磁盘IO类似,网络IO同样需要分段查找和分析。通过网络抓包和分析的工具,诊断网络的延时、丢包等异常情况出现在哪一段,然后具体分析。

同时,抓主机端的IPtrace有助诊断不少的网络问题,参考文章http://www.aixchina.net/Article/177921

(四)误判为IO问题的案例

很多时候,应用响应时间很慢,看似是IO问题,实则不然,这里举两个例子。

1.案例分享:

Oracle buffer等待占总时间的大头,在一个场景中,Oracle的awr报告top10事件的*名是:buffer busy waits

buffer busy waits是个比较general的等待,是session等待某个buffer引起的,但具体是什么buffer并不清楚,比如log sync等待也会引起buffer busy wait。

这是个连带指标,分析是暂且不管,需要看看他临近的问题事件是什么。

awr报告top10事件的第二名是enq:TX – index contention。这里的临近事件就是enq:TX – index contention, index contention常由大量并发INSERT 造成的 index split 引起,也就是说不断更新索引的过程中,二叉树不断长大。需要分裂,分裂的时候,其他Session就需要等着(这里的分析需要些数据库知识)。

之后的调优过程中,将索引分区,避免竞争。调整后重新测试,Index contention、Bufferbusy wait双双从top10事件中消失了。

这类数据库相关的等待事件非常常见,看似是等待IO,实际上是数据库的规划设计有问题。

2.案例分享:

Ping延时间歇性暴增。某业务系统的响应时间很不稳定,该系统有两类服务器构成,可以简单理解为A和B,A为客户端,B为服务端,A处业务的响应时间非常不稳定。

*步:从各类资源(CPU、内存、网络IO、磁盘IO)中追查原因。*终发现A与B直接的网络延时非常不稳定。A ping B,在局域网环境,按理说延时应该是0ms-1ms之间,而我们在业务高峰时发现,隔一小段时间就有100-200ms的延时出现。即使在没有业务的情况下,Ping也30-40ms的延时。

第二步:开始排查网路。换A的物理端口、换交换机、换网线、换对端的物理端口等等一系列措施之后,发现问题依然存在。

第三步:采用网络探测设备,从交换机两侧端口抓包,分析一个tcp连接的建立过程时间消耗在哪里。分析后发现,200ms的延时,都是在B测。即一个tcp连接建立过程在A侧和交换机侧几乎没有什么时间消耗。

第四步:B侧多台分区共用一个物理机。猜测是否是分区过多导致。当只有一个LPAR启动的时候,没有ping的延时,当启动一部分LPAR时候,延时较小,当所有LPAR均启动,Ping 延时较大。

问题根本原因:此时,问题水落石出,原来是由于分区过多导致了B回复A的ping有了延时。那么为什么会出现这种情况呢?一个物理机上CPU资源是有限的(本环境中是3颗),即使只有一个LPAR,其上面的N个进程也会去轮流使用CPU,何况此时是M台LPAR,MN个进程去轮流使用这三个CPU,当然调度算法并不是这么简单,这里仅仅是从理论上做个说明。

假设每个CPU时间片是10ms,那么*端情况下,一个进程要等到CPU需要等待(MN-1)*10(ms)/3。况且,这么多LPAR的进程轮询一遍CPU,CPU里面的cache 数据估计早就被挤走了,重新加载是比较耗时的。

应对方法:之前LPAR也设置了保障的CPU(MIPS数量的保障),但只有数量没有质量(上述提到的CPU cache问题,即亲和性问题)。

将重要的LPAR分配dedicated CPU,保证CPU资源的质量,保证轮询CPU的客户尽量少,这样CPU cache中的数据尽量不被清走。经验证,Ping延时基本消失,方法有效。本案例是一起看似是网络问题,但实际是资源调度方式的问题

顺便提一句,很多情况下,客户端的响应时间不稳定都是由服务器端的服务能力不稳定造成的。一般情况下都是应用、数据库的问题造成。而本案例是操作系统层面答复Ping出现间歇性延时,很容易误导我们的分析判断。

CPU有个禁区,内核权限也无法进入!

神秘项目

我是CPU一号车间的阿Q,是的,我又来了。

*近一段时间,我几次下班约隔壁二号车间虎子,他都推脱没有时间,不过也没看见他在忙个啥。

前几天,我又去找他,还是没看到他人,却意外地在他桌上发现了一份文件,打开一看是一个代号为SGX的神秘项目,还是厂里领导亲自带头攻坚。

%title插图%num

仔细看了看,原来,自从上次的攻击事件(详情:为了这个技术,操作系统把 CPU 害惨了!)发生以来,领导一直忧心忡忡,虽然当时依靠操作系统提供的办法暂解了燃眉之急,不过治标不治本,我们自身的缺陷一直存在,保不准哪天还要翻车。

这个代号为SGX的神秘项目全称Software Guard Extensions,志在全面改革,提升咱们CPU的安全能力!

%title插图%num

偷听会议

我瞬间不高兴了,这么重要的项目,居然没找我参加?

随即,我来到了领导的办公室,果然他们几个在开着秘密会议,而我就凑在一旁偷听。

“诸位,你们都是咱们厂里的核心骨干,关于这次安全能力提升的事情,大家回去之后有没有什么想法,请畅所欲言!”,我听到领导在讲话。

核心骨干?难道我阿Q不是核心骨干吗?真是气抖冷!

沉闷了一小会儿,隔壁二号车间虎子才说到:“咱们现在不是有安全访问级别吗,从Ring0到Ring3,已经可以很好到隔*应用程序的攻击了啊”

%title插图%num

领导摇了摇头,“尽管如此,但是一些恶意软件可以利用操作系统的漏洞可以获取到Ring0的权限,咱们现有的安全保护就荡然无存了”

“那也是操作系统的锅,要改进也该让他们做啊,关我们什么事呢?”,虎子继续说到。

“你忘记前段时间针对咱们CPU发起的攻击了吗?”

此话一出,会场瞬间安静了。就这水平,领导居然请他来不请我!

领导缓了缓,接着说到:“咱们不能总依赖操作系统的安全保护,咱们自己也得拿出点办法。我觉得现有的安全机制不够,操作系统漏洞频出,很容易被攻破,咱们现在不能信任操作系统,得彻底全面的改革!”

这时,五号车间的代表说话了:“领导,我回去调研了一下,了解到咱们的竞争对手推出了一个叫TrustZone的技术,用于支持可信计算,号称提供了一个非常安全的环境专门支持对安全性要求*高的程序运行,像什么支付啊、指纹认证之类的,咱们要做的话可以参考一下”

听完TrustZone的介绍,三号车间老哥仿佛找到了灵感,激动的说到:“有了!咱们可以在内存中划出一片特殊的区域,作为*高机密的空间。将高度机密的程序代码和数据放在这里面运行,再引入一种新的工作模式,咱们CPU只有在这种模式下才允许访问这个安全空间,否则就算是有Ring0的权限也不能访问!

%title插图%num

引进一个新的工作模式,这种思路倒是很新鲜,大家纷纷议论开来。

“这个安全空间技术上要怎样实现呢?”

“线程怎么进入和退出安全空间?恶意程序进去了怎么办?”

“怎么调用外部普通空间的函数呢?外部函数被攻击了怎么办?”

“需要系统调用怎么办?中断和异常怎么办?”

短短一小会儿时间,大家就七嘴八舌提了一堆问题出来···

领导给他们几个一一分配了任务,下去思考这些问题的解决办法,过几天再进行讨论。

在他们散会离场前,我匆忙离开了。

%title插图%num

主动出击

这可是个表现的好机会,要是能解决上面的问题,领导说不定能让我加入这个项目组。

对于安全空间实现问题,既然是从内存上划出来的区域,自然得从内存的访问控制上做文章。我跟咱们厂里内存管理单元MMU的小黑还算有些交情,打算去向他请教一番。

听完我的需求,小黑不以为意,“就这啊,小事一桩,访问内存时我会进行权限检查,到时候除了之前已有的检查,再加一道检查就可以:如果发现是要访问安全空间的页面,再检查一下当前的工作模式是否正确”

其他几个问题我也有了自己的想法,安全空间按照创建-初始化-进入-退出-销毁的顺序进行使用。

创建:通过执行ECREATE指令创建一个安全空间,

初始化:通过执行EINIT指令对刚才创建的安全空间进行初始化

进入 & 退出:通过执行EENTER/EEXIT指令进入和退出安全空间,类似于系统调用的SYSENTER/SYSEXIT指令。提前设置好入口地址,进入安全空间后需要从指定的地方开始执行,避免外面的程序乱来。执行这两条指令的同时CPU进行安全模式的切换。

中断 & 异常:遇到中断和异常,需要转而执行操作系统内核处理代码,而操作系统是不能被信任的。需要执行AEX指令退出,将在安全空间执行的上下文保存起来,以便回头继续执行。

系统调用:系统调用有点麻烦,需要进入操作系统内核空间,因为不能信任操作系统,同样需要先退出安全空间,执行完系统调用再进来。

函数调用:安全空间和外部可以互相调用函数,普通空间调用安全空间函数叫ECALL,安全空间调用外部空间函数叫OCALL。调用的方式类似操作系统的系统调用,不同的是操作系统的函数是内核提供,安全空间的函数是应用程序自己定义的

%title插图%num销毁:通过执行EREMOVE指令销毁一个安全空间

我还给这个安全空间取了一个名字,叫:Enclave,自然而然咱们CPU的工作模式就分了Enclave模式和非Enclave模式。

%title插图%num

内存加密

随后,我把我的这些想法整理出来,来到了领导办公室,主动申请加入SGX项目组。

领导显然对我的到来有些意外,不过看完我准备的材料还是满意的同意了我的申请,让我也参与下一次的讨论会,真是功夫不负有心人!

很快就到了下一次的会议,我再也不用在门外偷听了。

%title插图%num

会议上我的方案得到了大家的一致认可,只有八号车间的代表不以为然:“安全空间的方案是很好,但是还差一个*重要的东西,要是加上这个,那就完美了!”

“是什么?”,大家齐刷刷的望向了老八。

“这些形形色色的攻击方式,*终都是要读写内存数据,而他们屡屡得手的根本原因在于什么?”,老八说到。

大家一头雾水,不知道他想表达什么。

“老八,你就别卖关子了,快说吧!”

老八站了起来,说到:“其根本原因就在于内存中的数据是明文,一旦数据泄漏就可能造成严重后果。而如果我们把安全空间的内存数据加密了呢?即便我们的防线都失守了,对方拿到的也只是加密后的数据,做不了什么!”

老八的话如当头一棒,我怎么就没往这个方向考虑。

“加密?那什么时候解密呢?”,虎子问到。

%title插图%num

“问得好,我建议咱们厂里内存管理部门设置一个内存加密引擎电路MEE(memory encryption engine),对安全空间的数据进行透明的加解密,数据写入内存时加密,读入咱们CPU内部时再解密!”

虎子一听说到:“唉,这个好,建议全面推广,干嘛只在安全空间用啊”

老八拍了拍虎子的头:“说你虎,你还真虎,这玩意对性能影响不可小觑,怎么能随便用呢,好钢要用到刀刃上!”

“好!老八这个建议好。我决定这个项目就由老八来牵头!”,领导拍案而起。

%title插图%num

散会后,虎子笑我忙活半天还是没有当上牵头人,我倒是很看得开,能一起参与就不错了,学到技术才是王道~

%title插图%num

彩蛋

SGX项目上马后,咱们CPU的安全性有了很大的提升,然而我们花了这么大力气打造出的这个安全空间真的如铁桶一般,牢不可破吗?

预知后事如何,请关注后续精彩……

受限于故事形式,SGX技术的很多实现细节不便展开,感兴趣实现原理的朋友参考阅读下面的文章:

SGX技术的分析和研究:

http://www.jos.org.cn/html/2018/9/5594.htm

Intel SGX学习:

https://zhuanlan.zhihu.com/p/50894009

Intel 官方文档:

https://software.intel.com/sites/default/files/article/413936/hasp-2013-innovative-instructions-and-software-model-for-isolated-execution.pdf