万树IT:Net学习大总结(二)

来源:互联网 发布:checkmate交易系统源码 编辑:程序博客网 时间:2024/06/05 19:17
网络通信-结构图


WebAPI:基于Rest 架构风格,采用Http协议,使用Asp.net 编程模型进行实现,其常见的规范和约束:

URLAPI 使用名称;

使用Http行为来表述行为:Get,POST,PUT,Delete;

请求和响应约定序列化方式,Content-Type,Accept;

返回状态码尽可以和http返回状态一致,比如200代表成功,500 代表服务端异常;

无状态可方便扩展;

使用HATEOAS约束,对客户端提供一个URL,响应中返回你所有资源的URL及行为方式,后续客户端可根据响应中的链接进行资源访问,无论服务端如何变化,而对客户端而言始终透明,以此降低客户端的维护成本。

WCF:采用SOAP 协议,是以RPC-XML 规范为依据,使用WSDL 进行描述和定义,支持http/s ,TCP,MSMQ 等通信协议;

定义契约,实施开发,客户端集成方式有多种,可以直接引用服务,可以继承ClientBase,可以通过ChannelFactory 信道工厂创建客户端实例,当然无论采用方式都是采用客户端代理模式的方式来透明实现,在代理中有很多技巧:比如实现服务端的负载均衡,比如自定义读取客户端WCF相关的配置文件和其它配置进行解耦方便维护;

WCF内部很多基础实施已然有很多扩展点,对客户端的认证 可以使用 UserNamePassowrdValidator 进行扩展,授权 可以使用  IAuthorizationPolicy 进行扩展并使用CAS(Code Access Securty) 和 特性技术,全局异常点可以对 IErrorHandler  进行扩展,服务行为 可以对 IServiceBehavior 进行扩展,而且这些扩展代码实现并能基于配置完成;

C#-结构图


数据类型
总体分为值类型和引用类型,值类型包括 int,double,enum,float等,其特点是不变性;引用类型包括:string , class, interface 等,这里面尤其说明的是string 也有不变性,strng a="1" 和 string b="1" 中 a 和 b 是指向同一个引用,而且 string a="1"+"2"  中间其实生成了临时的新对象并占用了一定内存,建议使用 StringBulider ; 值类型和引用类型的转换为装箱和拆箱,影响性能,要尽量少的强制类型转换,可以使用泛型进行强类型约定;

集合,List  无序,可重复,线程非安全,存在泛型,复杂度为 O(n)  ; Dictionary  字典,key 不可重复,线程非安全,存在泛型,查找复杂度 O(1);HashTable  字典,key 不可重复,线程安全,查找复杂度 O(1);  当然还有 Queue,Stack 等 , 一般情况有对应的线程安全集合在前面加Concurrent,如 ConcurrentQueue,ConcurrentDictionary  ;

委托和事件都可以进行内部解耦,回调,广播,只是委托更加灵活,可以做为函数参数传入,而事件只能在内部调用;当然委托和事件的定义也不同,事件是建立在委托定义之上,更强调的是消息通知。

类和接口,多态,封装,继承,是面向对象的基本数据和特性,通过设计模式和设计原则能很清晰的熟悉面向对象的方式方法;如5大原则:开闭原则,单一原则,依赖倒置原则,里氏替换原则,接口隔离原则;其定义不再赘述。

并发-结构图


有高并发的开发需求,首先要规划你的硬件、软件架构,那规划的依据是量化的数据,如PV,QPS;还要清楚软件的特性和用什么技术,然后还要通过性能测试进行辅助,如JMeter , 根据测试工具压测,得出整体服务的响应时间,吞吐量,另外还要对数据进行分析,看是否存在数据错乱的情况。

缓存,主要是避免数据库IO的瓶颈,而在内存进行处理,当然单机缓存容量有一定局限,可以N台机器互联共享内存,则采用分布式缓存,在高并发情况下,使用缓存有一个思路是 相关业务操作及代码实现可以完全在缓存中操作,有些数据可以先预热到缓存中,服务运行的时候可以直接从缓存中读取,那缓存中数据更改后最终要同步到数据库,可以异步+队列的方式进行消息订阅和发送或者采用轮询定时从缓存中取出数据写入到数据库,在设计过程中格外注意同步失败或出现故障的情况,要有重试机制;其实在独立模块,独立服务中,有些服务并发并不高,那数据可以直接先写入到数据库中,而后再被缓存起来;最后 依据CAP定律,如果服务可用,并是容量分区这里是如果采用分布式缓存,最后只能是弱一致性,所以我们设计是解决90%以上的问题(当然如果能解决99.999%的问题更好了),另外10% 可以人工介入加以解决。

限流,高并发情况下肯定不能将全部请求全部接受并一次性处理那服务有被搞崩溃的可能,那就可以将部分重复请求丢弃,可以使用Nginx 的 对客户端IP进行限制,同时高并发下肯定有些重要数据资源会存在竞争,如何保持数据一致性,使用锁机制,悲观锁会严重影响性能,但不会存在脏读,写错的情况,乐观锁,会存在脏读的情况,但能保证数据写入没有问题,一般我们采用分布式锁,使用Redis 的SETNX 特性,Redis 是单线程,存在事务,但事务没有回滚机制,Redis的事务是命令集的方式,如 SETNX 如果不存在Key 值则返回true, 如果已存在Key 值则返回false  , 如果返回false 代表请求已存在,则请求被直接丢弃,其实Redis 的 SETNX 和 Membcached 的Add 有点类似,然后使用队列将请求串行化,到数据库基本访问不会太高,最后的数据库起码要最好主从模式,避免单一故障,最好数据冗余。

算法,对请求进行限流有个很常用的手法,令牌桶,我们先申请访问的token, 并注入到一个桶容器中,设置容器的最大token 量,超过的请求直接丢弃,当请求访问时验证token 是否存在,如存在则正常处理后续业务逻辑并删除token, 否则直接丢弃请求,以上算法的实现方式可以使用 Redis 中的 SETNX +  Delete  命令实现;

队列,有很对成熟的队列消息中间件,其中RabbitMQ 是较为常用,支持消息的持久化,避免中心服务DOWN 机后消息丢失;支持ACK机制,当消费者宕机或其它网络原因导致没有收到消息,则队列会进行重发消息,直到消费者确认收到通过BasicAck 命令进行发送则消息从队列中删除;有限流机制,可以通过内存大小,磁盘大小及上游流量大小三种方式对请求进行限流;可以集群,但各服务器队列进程不互相通信,所以需要客户端实现分布式,算法可以采用哈希一致性;
原创粉丝点击