此文是阅读Artech《ASP.NET Core 3 框架揭秘》和其他网友的文章记录的笔记,尽管ASP.NET Core 6正式版已经发行,并不觉得这本书会过时淘汰,相反现阶段本人认为是从早期的ASP.NET转移升级到ASP.NET Core的最佳时机,不早也不晚成本最低。一直都在关注ASP.NET Core,所以并不陌生,在.NET4.x中就使用另一种类似的技术Katana和Owin,ASP.NET Core发布后,Katana和Owin完成了使命退出。如果说ASP.NET Core最核心的两件事就是依赖注入,以及自宿主Kestrel摆脱了IIS,自此不用担心跨平台部署的需求了。
特别说明:下述内容笔记是结合.NET4.x中的知识理解的,毕竟是一个使用.NET/C#编程十多年.Neter。
1.依赖注入(DI) 1.1.简述:就是让框架来管理对象创建和销毁,不用你自己管理它们,你只负责使用它们就行。 1.2.服务实例的生命周期模式:Singleton、Scoped和Transient 1.2.1.Singleton:单例对象,相当于单例模式创建的对象或全局的静态对象,IServiceProvider对象创建的服务实例由根容器对象保管,所以同根的IServiceProvider对象针对同一类型的服务实例,提供的都是同一个对象。 1.2.2.Scoped:服务范围对象,IServiceProvider对象创建的服务实例由自己保管,所以同一个IServiceProvider对象针对同一类型的服务实例,提供的均是同一个对象。 1.2.3.Transient:临时对象,即用即建,用后即弃。针对每一次服务请求,IServiceProvider对象总会创建一个新的服务实例 1.3.服务注册、服务消费和服务释放 1.3.1.服务注册 避免Singleton服务实例将Scoped服务实例变成Singleton模式,从而导致无法及时释放,在开发模式中一定要开启验证检查。 1.3.2.服务消费 如果服务实例有多个构造函数,那么服务实例在创建选择构造函数时,就会遵循以下规则:每一个候选构造函数的参数类型集合都是要选定的构造函数参数类型的子集,也就是说优先选择所有候选构造函数参数类型集合超集的构造函数,作为选定的构造函数。如果构造函数中不存在这种子集或超集的关系,那么会抛出异常。 1.3.3.服务释放 服务实例释放,是指实现了接口IDisposable或IAsyncDisposable,在服务实例用完之后,系统会调用Dispose或DisposeAsync方法。如果没有实现这个接口,就要等着GC来回收了。 1.4.关系概述 1.4.1.ServiceProviderEngine a)关系1:IServiceCollection=>IServiceProvider=>ServiceProviderEngine b)关系2:IServiceCollection对象的BuildServiceProvider方法创建了实现接口IServiceProvider的ServiceProviderEngine对象。 c)关系3:ServiceProviderEngine实现了接口IServiceProvider,所以它是一个依赖注入容器。 d)关系4:ServiceProviderEngine实现了接口IServiceScopeFactory,它的属性RootScope返回一个IServiceScope对象,它的方法CreateScope返回一个IServiceScope对象。 e)关系5:ServiceProviderEngineScope实现了接口IServiceScope,所以上一步中返回的IServiceScope对象,可以理解为ServiceProviderEngineScope对象。
1.4.2.ServiceProviderEngineScope a)关系1:ServiceProviderEngineScope不仅实现了接口IServiceScope,还实现了接口IServiceProvider,所以可以视为IServiceScope对象是对IServiceProvider对象的封装。 b)关系2:ServiceProviderEngineScope的属性ServiceProvider,返回的就是它自己。 c)关系3:ServiceProviderEngineScope对象是由方法CreateScope创建。
1.4.3.ServiceProviderEngine种类 a)RuntimeServiceProviderEngine:采用反射的方式提供服务实例。 b)ILEmitServiceProviderEngine:采用IL Emit的方式提供服务实例。 c)ExpressionsServiceProviderEngine:采用表达式树的方式提供服务实例。 d)DynamicServiceProviderEngine:根据请求并发数量动态决定最终的服务实例提供方案(上述三种之一)。
1.4.4.要点记录 a)ServiceProviderEngine.GetService方法返回的是RootScope的ServiceProviderEngineScope对象,此时调用ServiceProviderEngineScope对象的GetService方法才会返回自己。 b)ServiceProviderEngine的属性RootScope维护着Singleton类型的服务。
1.4.5.IServiceScope和IServiceScopeFactory IServiceProvider对象利用IServiceScopeFactory创建一个代表服务范围的IServiceScope对象,后者内具有一个新创建的IServiceProvider对象,两个IServiceProvider对象逻辑上具有父子关系,实际上子对象不需要知道父对象是谁,只需要知道根节点的IServiceProvider在哪里就行。 1.5.IServiceProvider对象 Asp.Net Core中有两类IServiceProvider对象,一种是作为根容器并与应用程序具有相同生命周期的IServiceProvider对象(ApplicationServices),另一种是根据请求及时创建和释放的IServiceProvider对象(RequestServices)小结:和.Net Framework比较,就当作之前使用工厂模式创建和管理对象,现在改成框架帮你创建和管理对象就好。
2.文件系统 2.1.简述:这里的文件系统是指实现接口IFileProvider对象提供的对目录和文件的只读服务,并且具备监视文件变化的功能。从前后端分离的角度看,此项功能没什么用处,从本地配置文件管理看是有用处的,从MVC开发用处则很大。2.2.IFileProvider 2.2.1.核心方法 a)GetFileInfo方法:返回IFileInfo接口对象,用于读取文件内容。 b)GetDirectoryContents方法:返回IDirectoryContents接口对象,用于查看目录下有多少文件或子目录。 c)Watch方法:如果IFileProvider对象提供了Watch功能,可以利用他监视目录和文件的变化。 2.2.2.实现种类 a)PhysicalFileProvider:读取物理硬盘上的目录和文件。 b)EmbeddedFileProvider:读取内嵌入程序集中的文件。 2.3.IChangeToken 2.3.1.概述:IFileProvider.Watch方法返回的类型。 2.3.2.常用实现 a)CancellationChangeToken :取消令牌 b)CompositeChangeToken:代表由多个IChangeToken组合而成的复合型IChangeToken对象小结:这个相当于一个新的基础类,就是帮你读取和监视文件信息。
3.配置 3.
目录字符编码与配置文件存储引擎创建表的完整语法字段类型之整型字段类型之浮点型字段类型之字符类型数字的含义字符类型之枚举与集合字段类型之日起类型约束条件
字符编码与配置文件 \s 如果是5.X系列 显示的编码有多种 latin1 gbk 如果是8.X系列 显示的统一是utf8mb4 utf8mb4是utf8优化版本 支持存储表情 2.统一字符编码 5.x默认编码有多种 可能会导致乱码的情况 需要统一编码进行输入 my-default.ini配置文件 步骤一:拷贝一份该配置文件并修改名称为my.ini 步骤2:清空my.ini文件内的内容 步骤3:添加固定的配置信息即可 [mysqld] character-set-server=utf8 collation-server=utf8_general_ci [client] default-character-set=utf8 [mysql] default-character-set=utf8 步骤4:保存并重启服务端即可生效 net stop mysql net start mysql 存储引擎 1.什么是存储引擎 存储引擎可以理解为处理数据的不同方式 eg: 有一个a.txt文件 戴某某会放在密码箱中 张某某会转成pdf存储 李某某会做多个备份 潘某某会制作封面美化等 2. 查看存储引擎 show engines; 3. 需要了解的引擎 MyISAM 5.1之前版本MySQL默认的存储引擎 特点:存取数据的速度快 但是功能很少 安全性较低 InnoDB 5.1之后版本MySQL默认的存储引擎 特点:有诸多功能 安全性较高 存取速度没有MyISAM快 BlackHole 任何写入的数据都会立刻消失(类似于垃圾回收处理站) Memory 以内存作为数据存取地 速度快但是断电立刻丢失 4. 自定义选择存储引擎 create table c1(id int)engine=myisam; create table c2(id int)engine=innpdb; create table c3(id int)engine=blackhole; create table c4(id int)engine=memory; 1.
最近windows11的更新越来越离谱了,一个月之前发现右下方的图标不闪动了,也不能拖动了,过了几天闪动回复了,但还是不能拖动,后面发现是windows11专门设计的,真的垃圾。
说实话我对windows11还是挺满意的,感觉比windows10好看了一点,很多老应用比如资源管理器跟记事本也更新了,对平板模式支持更多了,设置专门给兼容了安卓
但是这两个更新实在是接受不了,第一个是图标无法拖动,说是为了平板模式,已经被提反馈了但是我就是不改http://t.co/g0wYarW2WS
另一个是直接将系统托盘的隐藏按钮栏给搞没了,这个重启有一定概率恢复,但是概率比较低,我一开始还以为是bug,后来发现也是微软的设置,通过设置-个性化-其他系统托盘图标-隐藏的图标菜单 设置为开就好了,没立马好的话就再重启一下。这个可真是难找,我跑到Twitter才找到这个教程:https://www.youtube.com/watch?v=d8WC36hlfHw&t=1s。
离谱的是更新后它把这个设置默认为关了,就是直接把图标全都隐藏了。
设置之前:
设置:
设置之后:
我是真不理解微软的这个操作,本来拖一下就可以的事非得进到设置里面层层找然后一个一个的选,正常人根本找不到。 我理解微软是在适配平板电脑模式,二合一电脑我也也用了几个,surface Pro6、surface go2、HUAWEI MateBook E 2022,说实话windows平板模式是真不行,一个是操作还是桌面操作一个是软件适配,UWP基本上属于死掉了,看个视频都没法看。现在windows11又是适配android又是改操作逻辑的,虽然我还是不看好,但尝试总是好的,但你他娘的别将给平板模式设计的强加到桌面模式上啊,至少给个选项啊,并且也别他娘的默认选到平板模式啊,真他娘的离谱。这样搞下去桌面市场也要丢了。
1.锁的一些基础
锁是为了保护并发场景中临界资源,保证其有序变更。锁的粒度越粗,锁住的范围越大,并发度越低。
2.本文中主要探讨常用的一些锁:行锁、间隙锁、next-key lock、表级锁、MDL。
3.行锁
分为两类,共享锁S,排他锁X,对同一行数据而言,S可以兼容S,X不能兼容其他锁。
意向锁:对小粒度数据加锁前,一般对大粒度数据加意向锁。例如,对一行记录加S,对该行记录所在的表加IS。意向锁和行锁之间的兼容性很容易推理。
为什么要有意向锁?一个表中已经有了行锁的时候,此时想要加另一个行锁,先判断和意向锁是否冲突,如果冲突,就不必对每一行的行锁进行扫描了。
4.两种常见的涉及一致性以及锁的写法
select ... for update:对读取的该行加X锁。在rr级别下,被锁住的行也是可以读的。
select ... for share mode:对读取的该行加S锁。
5.主键自增与锁
AUTO-INC locking,不等待事务完成,完成对自增长id插入的sql语句后就释放,增加并发度。后续升级用innodb_autoinc_lock_mode,如果存在批量插入情况,一次性插入的值可以确定,就可以直接一次性申请多个id,合并申请释放一次。
6.行锁、间隙锁、next-key lock
间隙锁是为了解决幻读的问题。
next锁形式是多个区间,左开右闭。
法则:
等值查询,唯一索引,next锁降级为行锁,唯一索引必须保证唯一,每次插入要检查,不一样一定能插入新行,没必要锁住行。
等值查询,最后扫描的一个行不满足条件的时间,最后一个退化为间隙锁(右开)。
访问到的对象才会加锁。走索引和全表扫描是两情况,覆盖索引不访问主键索引树,主键索引依然可以操作。
7.MDL
MDL是自动加上的,不需要显式使用,增删改查DML是读锁,表结构变更DDL是写锁。
经典死锁问题:线程A申请了DML,线程B申请DDL被阻塞,会阻塞后面所有的DML,如果查询频繁或者有重试机制,线程会爆满。
可以为DDL操作设置心跳机制。
学习数据结构的 git 代码地址: https://gitee.com/zhangning187/js-data-structure-study
1、数组 几乎所有的语言都原生支持数组类型,因为数组是最简单的内存数据结构。该章节深入学习数组数据结构和它的能力。
1.1 数组添加元素 初始化一个数组
let numbers = [0, 1, 2, 3, 4, 5, 6]; 数组尾部插入元素,只要把值赋给数组中最后一个空位上的元素即可
numbers[numbers.length] = 7; 在 JavaScript 中元素是一个可以修改的对象,如果添加元素他就会动态增长。在别的语言里面要决定数组的大小,如果添加新的元素就要创建一个全新的数组,不能简单地添加所需的元素。
使用 push 添加数组元素
numbers.push(8); numbers.push(9, 10);// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 1.1.1 数组开头插入元素 实现这个需求,要腾出数组里第一个元素的位置,把所有的元素向右移动一位。
Array.prototype.insertFirstIndex = function (value) { for (let i = this.length; i >= 0; i--) { this[i] = this[i - 1]; } this[0] = value; }; 在 JavaScript 里操作数组有个方法 unshift ,可以直接在数值插入数组的开头,该方法逻辑和 insertFirstPosition 方法得方式是一致的。
目录CompletableFuture是java8中新增的一个类,算是对Future的一种增强,用起来很方便,也是会经常用到的一个工具类,熟悉一下。
CompletionStage接口 CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发 CompletableFuture类 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合 CompletableFuture 的方法。它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作。它实现了Future和CompletionStage接口 常见的方法,熟悉一下:
runAsync 和 supplyAsync方法CompletableFuture 提供了四个静态方法来创建一个异步操作。
public static CompletableFuture<Void> runAsync(Runnable runnable)public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) 没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
runAsync方法不支持返回值。supplyAsync可以支持返回值。 示例代码
//无返回值public static void runAsync() throws Exception {CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {}System.out.println(run end ...);});future.get();}//有返回值public static void supplyAsync() throws Exception { CompletableFuture<Long> future = CompletableFuture.
函数参数类型 位置参数,关键字参数,默认参数,可变参数 位置参数: 传参时,按照实参的传递顺序,按照形参定义的顺序进行传递的传参方式
关键字参数: 穿参时, 忽略形参的顺序,按照形参等于实参的形式进行传参的传参方式 (传参时,关键字参数必须在位置参数的后面
默认参数: 在定义参数的时候,给形参一个默认的值,当调用的时候,如果不给有默认值的参数传参,就会采用默认的值
如果给有默认值的参数穿参,函数就会使用重新赋的值,当某个值变化频率较小的时候,就可以使用默认参数 ( 默认参数一定要写在形参后面
可变参数 如果函数中的参数过多,我们定义起来非常的麻烦,调用起来也非常的麻烦,因此 python给我们提供了可变参数类型。能处理比当初声明时更多的参数,会将传入的参数变成元组或键值对 *args元组参数——接收多个位置参数 def score(*nums): sum=0 for num in nums: sum=sum+num return sum
#把实际分数存放在元组里或列表里 nums1=(100, 98, 76, 89, 90) print(score(*nums1))#必须加*打散元组,不然报错
*具有打散元组或者列表的作用
**kwargs字典参数——接收多个关键字参数 def score(**kwargs): sum=0 for key in kwargs: sum=sum+kwargs[key] return sum dic={'zs':100,'ls':98} print(score(**dic)) **具有打散字典的作用
列表生成式、迭代器、生成器、yield函数 什么是迭代?
一件事情重复很多次,比如 for 循环
什么是可迭代对象?
for x in lis,tuple,str,dic[key],dic[values] 以上lis,tuple,str,dic[key],dic[values]都可以称为可迭代对象
那么专业点来说,什么是可迭代对象:具有iter()方法的,调用iter()方法,就会返回一个迭代器
迭代器有next()方法,在调用这个迭代器的next()方法时,迭代器就回返回它的下一个值,
当迭代器中没有值可 以返回了,就回抛出一个名为StopIteration的异常,停止迭代
list=[1,2,3,4] # 创建迭代器对象 it = iter(list) # 输出迭代器的下一个元素 print (next(it)) #1 print (next(it)) #2 print (next(it)) #3 print (next(it)) #4 print (next(it))#StopIteration import sys # 引入 sys 模块 list = [1, 2, 3, 4] it = iter(list) # 创建迭代器对象 while True: try: print(next(it),end=' ') except StopIteration: sys.
服务降级 什么是服务降级 在服务器压力剧增的情况下,对一些服务和页面进行有策略的不处理或者换种简单的方式处理,从而释放服务器资源以保证核心服务正常运作或者高效运作。
当架构整体的负载超过了预设的上线阈值,或者即将到来的流量预计将会超过预设的阈值时,为了保证重要的基本服务能够正常运行,可以将一些不重要或者不紧急的服务或任务进行延迟使用或者暂停使用。
降级策略 当触发服务降级时,新的请求到达时,怎么处理?可以从,微服务,分布式架构的全局来确定降级解决方案:
页面降级-可视化页面禁用点击按钮,调整静态页面 延迟服务-定时任务延迟处理、消息入MQ后延迟处理 写降级-直接禁止相关写操作的服务请求 读降级-直接禁止相关读的服务请求 缓存降级-使用缓存来解决部分读频繁的服务接口 针对后端代码的降级处理:
抛异常 返回NULL 调用Mock数据 调用Fallback处理逻辑 分级降级 结合服务能否降级的优先原则,可以做类似台风的分级处理:
服务熔断 什么是服务熔断 牺牲局部,保存整体的措施叫做熔断。
不采取熔断的后果,例子:
一旦下游服务C变的不可用,积压了大量请求,服务B的请求也会随之阻塞。
线程资源逐渐耗尽,使得服务B也变的不可用。紧接着,服务A也会变得不可用,整个服务链路被拖垮。
这种调用链路的连锁故障,叫做雪崩。
熔断机制 可以采用熔断机制来解决上面的问题。
需要注意两点:
开启熔断
在固定时间窗口内,接口调用超时比例达到一个阈值,会开启熔断。
进入熔断状态后,后续对该服务的调用,不再经过网络,而是调用本地的默认方法,达到服务降级的效果。
熔断恢复
熔断不是永久的,经过了熔断超时时间之后,服务将从熔断状态恢复,再次接受调用方的远程调用。
熔断机制的实现 Spring Cloud Hystrix
Spring Cloud Hystrix是基于Netflix的开源框架Hystrix实现的,该框架实现了服务熔断、线程隔离等一系列服务保护功能。
对熔断机制的实现,Hystrix设计了三种状态:
熔断关闭状态(Closed)
服务没有故障时,熔断器所处的状态,对调用方的调用不作任何限制。
熔断开启状态(Open)
在固定时间内,Hystrix默认是10s,接口调用出错比例达到一个阈值,Hystrix默认是50%,就会进入熔断状态。
进入熔断状态后,后续对该服务接口的调用,不再经过网络,而是调用本地的fallback方法。
半熔断状态(Half-Open)
在进入熔断开启状态一段时间后,Hystrix默认是5s,容器会进入半熔断状态。
半熔断状态尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,说明服务已经恢复,提前进入熔断关闭状态。如果成功率依然很低,则重新进入熔断开启状态。
三个状态的转化关系如下:
Sentinel
https://github.com/alibaba/Sentinel
Sentinel和Hystrix的原则是一致的:当调用链路中,某个资源出现不稳定,例如,表现为timeout,异常比例升高的时候,则对这个资源的的调用进行限制,并让请求快速失败,避免影响到其他资源,导致最终产生雪崩。
Sentinel的熔断手段:
通过并发线程数进行限制 通过响应时间对资源进行降级 系统负载保护
服务限流 什么是服务限流 限流就是为了提供稳定的服务,限制使用人数。
限流的目的是通过对并发请求进行限速,或者对一个时间窗口内的请求数量进行限速来保护系统。
一旦达到限制速率可以拒绝服务、排队或者等待。
多维度进行限流 请求到达服务接口时,可以采用多维度限流策略。
限流算法 限流算法-计数器(固定窗口)
计数器限制,每一分钟或者每一秒钟内的请求不能超过一定的次数,在下一秒计时器清零重新计算
存在的问题:
客户端在第一分钟的59秒请求了100次,又在第二分钟的1秒请求了100次,2秒内,后端要承受200次请求的压力,形成了流量突刺
限流算法-计数器(滑动窗口)
滑动窗口是细分后的计数器。它将每个时间窗口又划分成若干个时间片段,每过一个时间片段,整个时间窗口就会向右移动一格。
打满100次,客户端就拒绝访问。
时间窗口划分的越细,滑动窗口的滚动越平滑,限流效果越精确。
限流算法-漏桶
漏桶算法类似一个限制出水速度的水桶,通过一个固定大小的FIFO队列+定时取队列元素的方式实现。
请求进入队列后,会被匀速取出来处理,类似桶底部的开口匀速出水。当队列被占满后,后来的请求会直接被拒绝,类似水倒得太快溢出来。
优点是可以削峰填谷,不论请求多大多快,都只会匀速发给后端,不会出现突刺现象,保证下游服务正常运行。
缺点是桶队列中的请求会排队,响应时间拉长。
限流算法-令牌桶
令牌桶算法是以恒定的速度往桶里放置令牌,如果桶里的令牌满了就放弃,每进来一个请求去桶里找令牌,有的话拿走令牌继续处理,没有就拒绝请求。
令牌桶的优点是可以应对突发流量,当桶里有令牌时可以快速响应也不会产生漏桶队列中的等待时间。
缺点是相对于漏桶,一定程度上减少了对下游服务的保护。
https://www.cnblogs.com/junzi2099/p/14208640.html