为了账号安全,请及时绑定邮箱和手机立即绑定
3.2 电话和短信

Phone 设置项中可以模拟来电和短信:From:选择或输入电话号码;CALL DEVICE:点击来电;HOLD CALL:点击保持通话;END CALL:点击结束通话;SMS message:输入模拟消息的正文内容;SEND MESSAGE:点击发送短信。

3.1 模拟电话

模拟10086来电;gsm call 10086模拟接听来电;gsm accept 10086模拟挂断来电;gsm cancel 10086下面是完整会话示例。pt@Win10-Panda:~$ telnet localhost 5554Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.Android Console: Authentication requiredAndroid Console: type 'auth <auth_token>' to authenticateAndroid Console: you can find your <auth_token> in'C:\Users\panda\.emulator_console_auth_token'OKauth KeGgPVHDN7YifXfZAndroid Console: type 'help' for a list of commandsOKgsm call 10086OKgsm accept 10086OKgsm cancel 10086OK

2.5 电话模拟命令

命令说明gsm {call\accept\cancel\busy} phonenumber模拟电话的呼入、接听、挂断、繁忙。gsm {data\voice} statedata state 命令用于更改 GPRS 数据连接的状态,data voice state 则用于更改 GPRS 语音连接的状态。gsm hold将通话状态更改为 hold。只有在当前状态为 active 或 waiting 时,才能将通话状态更改为 hold。gsm list列出所有呼入电话和外拨电话及其通话状态。gsm status报告当前的 GSM 语音/数据连接状态。相关的值就是前述 voice 和 data 命令的值。

3.1 微信小程序 API

uni-app 的 API 与微信小程序 API 基本一致。掌握微信小程序 API 对后面的开发很有帮助。微信小程序 API 文档:https://developers.weixin.qq.com/miniprogram/dev/api/

3. Zookeeper 的会话

Zookeeper 是一个 C/S 架构的服务,也就是 Client — Server 的形式。在我们使用 Zookeeper 时,都是使用 Zookeeper 的客户端向服务端发送请求,然后由服务端做出响应返回到客户端。在这个过程中,Zookeeper 的客户端需要与 Zookeeper 服务端建立连接,建立一个连接就是新建一个会话,那么会话的状态也就是 Zookeeper 客户端与 Zookeeper 服务端的连接状态。接下来我们从会话的结构开始进行讲解:

3.1 打包为微信小程序

注册微信小程序账号,获取到 AppID,我们后面配置的时候会用到。在 HBuilderX 工具栏,点击发行,选择小程序-微信。输入小程序名称和 AppID,单击发行就可以了。这样我们就会获得一个微信小程序的打包文件,接下来我们来发布微信小程序项目,打开微信小程序开发者工具,导入刚刚生成的微信小程序项目的打包文件,在微信小程序开发者工具中先测试一下,项目运行是否正常,项目测试没有问题后,点击右上角>>按钮,上传代码就可以发布微信小程序了,最后等待微信团队审核通过,别人就可以在线上访问到你的项目了。

1. 数据转成电信号

数据转换成电信号还是比较简单的,将字符根据指定的编码转换成唯一的二进制编码,然后将二进制的 01 映射成高低电平就可以传输出去了。

3.3 会话层

通过传输层,建立了数据的传输通道。不同应用有自己不同的会话标识,所以传输过来的数据根据会话标识能够知道跟电脑的哪个应用在通信的。

2. 服务快速失败之服务熔断机制

服务熔断机制的服务快速失败所实现的目标,和我们在上述小节中所介绍的普通的服务快速失败所实现的目标相同,都是为了保证,在某一微服务发生故障时,不影响后续微服务的正常运行。雪崩效应产生原理在上述小节中,各位同学已经对什么是雪崩效应有所了解,如上图所示,我们所讲的服务熔断也是为了避免和解决雪崩现象的发生,只不过所采用的手段不同而已,那么接下来,就让我们来看一下基于服务熔断机制的服务快速失败的概念是什么吧。针对服务熔断机制,我们先来介绍什么是熔断?熔断这一名词,其实不是来源于计算机相关专业,而是来源于电子工程相关专业。熔断的核心是断路器,对于断路器来说,我们可以将断路器理解为一根保险丝,在日常生活中,当我们家庭用电超过负载时,保险丝就会迅速烧断,阻止由于电流过大而烧毁整个家庭电路。同样地,熔断我们也可以像保险丝那样理解,即在计算机相关领域中,由于中断上游的故障服务,而保全整体的服务的措施就被称为熔断,而实现中断上游的故障服务所采取的核心措施就是我们的断路器。服务熔断机制就是把这些概念都统一起来,然后封装到 Hystrix 中,且最终应用于我们的微服务项目中间,通过配置断路器,来保全我们整体的微服务项目,这就是 Hystrix 所提供的服务熔断机制。Tips: 1. 在实际工作中,我们需要灵活的去配置微服务项目中,各个领域的微服务所对应的断路器配置,包括间隔时间、持续时间等关键属性,切记不要凭感觉去配置; 2. Hystrix 本身所提供的服务熔断机制并不是很好用,往往需要我们在项目中集成其他的微服务服务中间件来一起集成使用,单独使用 Hystrix 服务熔断机制的项目很少见。

3.1 关于微服务监控平台

技巧 1如果我们的微服务监控平台没有任何数据,或者说,在打开微服务平台之后,各参数一直处于 loading 状态,这个时候,我们只需要在服务端调用任意一个服务接口即可,这样在微服务监控平台,我们就能看到被监控实例的参数了。技巧 2如果我们在访问 /actuator/hystrix.stream 路径时,系统找不到对应的路径,即报 404 异常,那么我们需要在对应项目的启动类中添加一个 Bean :@Beanpublic ServletRegistrationBean hystrixMetricsStreamServlet() { ServletRegistrationBean registration = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registration.addUrlMappings("/hystrix.stream"); return registration;}这样我们就能正常访问 /actuator/hystrix.stream 下的路径了。

4.2 豆瓣网

豆瓣网 (douban) 是一个社区网站,提供关于书籍、电影、音乐等作品的信息,还提供书影音推荐、线下同城活动、小组话题交流等多种服务功能。豆瓣网已经达拥有 300 万注册用户,访问量每天则超过两千万,是一个应用 Python 开发的非常成功的 Web 2.0 站点。豆瓣网的后端采用了 Quixote 框架,Quixote 框架是一个使用 Python 开发的轻量级 Web 框架。

4.1 主要泄漏信息

IP 地址,物理地址网站后台访问地址,密码信息家庭成员信息,电话信息生日(很多人的秘密是生日日期)公司信息,同事信息

1.2 没有验证通信方身份

通信双方无法确认对方的身份是否正确。案例1:本地电脑有木马,路由表被踹改,www.baidu.com 的域名被解析到另一台虚假的服务器,此时你在浏览器访问的百度就是黑客的另一个钓鱼网站,然后给你推送了很多虚假消息,此时客户端很难知情。案例2:路由表没问题,但是目标服务器被人黑了,处理不了请求,此时有其它服务冒充提供服务。案例3:某个资源只有特定用户有查询的权限,黑客通过伪造该客户端一样的请求来查询,服务端只是简单的根据入参判断,并无法知道对应客户端的真实性,于是消息很容易泄漏。

1.1 客户端-服务端模型:

客户端,是指发起请求的一方。也就是浏览器,或者指爬虫程序。通过发起请求,来获取想要的网页。服务端,请求的响应端,是 web 服务端。web 服务,是一个虚拟意思上的机器的概念。可以是一个计算机集群,也可以是一个软件或者程序。客户端,通过发送一个请求给服务端,然后进行等待。服务端按照客户端的请求,返回客户端需要的数据。这个过程,我们称之为经典的客户端——服务端模型。

2. 什么是服务监控平台

Hystrix 中的服务监控平台,就是对微服务项目进行监控的平台,包括服务运行的状态、服务有无宕机、服务异常信息监控等内容,为开发者和运维者提供了比较友好地界面支持,开发者和运维者可以直接通过观察服务平台界面,来判断具体微服务的状态信息,从而更好地对微服务进行控制。默认的 Hystrix 中间件已经为我们封装好了微服务监控平台,但是需要通过引入依赖的方式来使用它,接下来就让我们来看一下如何搭建该服务监控平台吧。

2. 域名服务器类型

权威域名服务器:能够决定域名和 IP 的关系。本地域名服务器:一般由本地运营商提供,不能解析域名,通常是缓存域名解析和帮用户到权威域名服务器查询解析结果。公共域名服务器:跟本地域名服务器类似,只是它不是某个运营商提供的,是全网公用的。

2.1 微前端

微前端 尚处在发展时期,其核心概念和 微服务 相似。现阶段较为常用的微前端框架为 single-spa 和 qiankun,后者是基于前者实现的。该技术能做到 技术栈无关,即一个应用,能由多个不同技术的子应用构成,同时做到子应用的相互隔离,这里的隔离就可以选择采用 Web Components 实现。

3. Zookeeper 客户端

使用 Zookeeper 客户端连接 Zookeeper 服务,我们需要使用 ./zkCli.sh 命令:# 进入 bin 文件夹cd /usr/local/zookeeper/apache-zookeeper-3.6.1-bin/bin/# 连接命令./zkCli.sh # 连接时输出信息Connecting to localhost:2181...# 出现下面这一行时,表示我们连接成功[zk: localhost:2181(CONNECTED) 0] 这里我们就可以使用上一节学习过的命令来操作节点了,我们来测试一下:# 获取根节点的子节点ls /# 输出默认的子节点 zookeeper[zookeeper]# 创建根节点的子节点 imooccreate /imooc# 输出创建成功信息Created /imooc# 创建后再次获取根节点的子节点ls /# 输出两个子节点[imooc, zookeeper]# 我们可以给节点设置数据set /imooc wiki# 然后我们再获取 imooc 节点的数据get /imooc# 输出我们设置的信息wiki# 最后我们测试一下删除命令delete /imooc# 删除后再次获取根节点的子节点ls /# 输出子节点 zookeeper,imooc 节点被删除[zookeeper]# 退出 Zookeeper 客户端命令quit通过上面的学习,我们知道了如何部署单机模式的 Zookeeper 服务,以及如何通过 Zookeeper 客户端连接 Zookeeper 服务端,来对 Znode 节点进行操作。那么 Zookeeper 是如何为我们提供服务的呢,接下来我们就来了解单机模式下的 Zookeeper 的工作流程。

2. 需求分析

业务场景: 模拟微信聊天,每个客户端和服务端建立连接,并且可以实现点对点通信(单聊),点对多点通信(群聊)。设计思路: 我们要实现的是点(客户端)对点(客户端)的通讯,但是我们大部分情况下接触的业务都是客户端和服务端之间的通讯,客户端只需要知道服务端的 IP 地址和端口号即可发起通讯了,那么客户端和客户端应该怎么去设计呢?思考:难道是手机和手机之间建立通讯连接,互相发送消息吗?这种方案显然不是很好的方案,第一: 客户端和客户端之间通讯,首先需要确定对方的 IP 地址和端口号,显然不是很现实。第二: 即使有办法拿到对方的 IP 地址和端口号,那么每个点(客户端)既作为服务端还得作为客户端,无形之中增加了客户端的压力。其实,我们可以使用服务端作为中转站,由服务端主动往指定客户端推送消息,如果是这种模式的话,那么 Http 协议是无法支持的,Http 是无状态的,只能一请求一响应的模式,只能使用 TCP 协议去实现了。

2. 几种常用的客户端-服务器消息传递方式

http 最常用的协议,用于客户端主动向服务器发送请求,单向传递;ajax HTTP 的扩展版,底层还是 HTTP 协议,只不过客户端是无刷新的;comet 也是基于 HTTP 封装的,使用 HTTP 长连接的方式,原理大致是将 HTTP 的timeout 设置较长,服务器有数据变化时返回数据给客户端,同时断开连接,客户端处理完数据之后重新创建一个 HTTP 长连接,循环上述操作(这只是其中一种实现方式);websocket 这是 HTML5 中的新标准,基于 socket 的方式实现客户端与服务端双向通信,需要浏览器支持 HTML5;Adobe Flash Socket 这个也是使用 socket 的方式,需要浏览器支持 flash 才行,为了兼容老版本的浏览器;ActiveX object 只适用于 IE 浏览器;目前尚没有一种方式能兼容所有的浏览器,只能针对软件的目标客户人群做一定的兼容。sse 服务端单向推送。

1. 为什么需要Cookie和Session?

在 Web 程序中,对会话的跟踪是很一件非常重要的事情。通常,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能互不干扰。然而大部分的 Web 应用程序都是使用HTTP 协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。如果 Web 服务上没有这种的会话追踪功能,那么大部分网站都会陷入一片混乱。特别是对于电商网站而言,如果我添加一次购物车就需要登录一次确认身份,那对于用户体验而言是糟糕透的。会话(Session)跟踪是 Web 程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。正是有了 Cookie 和 Session 这样的会话跟踪技术,弥补了 HTTP 协议无状态的不足,才使得我们可以无差别的访问网站,即只需要一次登录,后续所有的操作通过 Cookie 或者 Session 便能自动识别为该用户,并维持在一个会话中。

3.1 四字命令介绍

这里我们列出常用的四字命令进行介绍:conf: 查询 Zookeeper 服务的配置信息。# 对客户端开放的端口,默认 2181clientPort=2181# 安全的客户端的端口secureClientPort=-1# 数据文件目录dataDir=/usr/local/zookeeper/apache-zookeeper-3.6.1-bin/data/version-2# 数据文件大小dataDirSize=67108880# 日志文件目录dataLogDir=/usr/local/zookeeper/apache-zookeeper-3.6.1-bin/data/log/version-2# 日志文件大小dataLogSize=914# 心跳检测间隔毫秒tickTime=2000# 最大客户端连接数maxClientCnxns=60# 最小的会话超时时间minSessionTimeout=4000# 最大的会话超时时间maxSessionTimeout=40000# 客户端端口列表备份日志clientPortListenBacklog=-1# 服务idserverId=0cons: 列出连接到 Zookeeper 服务的所有客户端的完整连接和会话详细信息。包括接收和发送的数据包数量、会话id、操作延迟、最后执行的操作等信息。/127.0.0.1:44244[0](queued=0,recved=1,sent=0)crst: 重置服务端的连接和会话统计信息。Connection stats reset.dump: 适用于 Leader 节点,列出未完成的请求和临时节点。envi: 列出服务器的环境信息。Environment:zookeeper.version=3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMThost.name=fbbc740a6217java.version=1.8.0_261java.vendor=Oracle Corporationjava.home=/usr/local/java/jdk1.8.0_261/jrejava.class.path=/usr/local/java/jdk1.8.0_261/jre/libjava.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/libjava.io.tmpdir=/tmpjava.compiler=<NA>os.name=Linuxos.arch=amd64os.version=4.19.128-microsoft-standarduser.name=rootuser.home=/rootuser.dir=/usr/local/zookeeper/apache-zookeeper-3.6.1-binos.memory.free=142MBos.memory.max=889MBos.memory.total=192MBruok: 测试服务是否处于正确运行状态,如果正常返回 imok,否则返回空。srst: 重置服务的统计信息。srvr: 列出服务的详细信息。Zookeeper version: 3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMTLatency min/avg/max: 0/0.0/0Received: 9Sent: 8Connections: 1Outstanding: 0Zxid: 0x2Mode: standaloneNode count: 5wchs: 列出服务的 Watcher 的简要信息。wchc: 按会话列出服务的 Watcher 的详细信息。wchp: 按路径列出服务带有 znode 列表的 Watcher 的详细信息。如果 Watcher 的数量多,会影响服务器性能,请谨慎使用。dirs: 以字节为单位显示快照和日志文件的总大小。datadir_size: 67108880logdir_size: 914

2. 传统 UDP 客户端和服务器建立过程

同样,我们展示了通过 C 语言 Socket API 编写 UDP 客户端和服务器程序的步骤,如下:图中的矩形方框都是 C 函数。对比 TCP 客户端、服务器的建立过程,我们发现 UDP 客户端可以调用 connect 函数,但是并不会去连接服务器,只是和本地接口做绑定;UDP 服务器是没有 listen 和 accept 调用的。对于 UDP 客户端来说,connect 函数的调用是可选的。接下来,我们就探讨一下如何用 Java 语言编写 UDP 客户端和服务器程序。

3.1 电量

Battery 设置中共用4项参数可以调节,模拟设备的电池属性,了解应用在不同条件下的运行情况:Charge level:设置当前电量值,百分比;Charger connection:设置充电器连接状态,是否连接充电器;battery health:设置电池监控状态,正常或者损坏等;Battery status:设置电池状态,正在充电或者已经充满等。

203 Non-Authoritative Information

文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝,非权威性信息。适用场景请求借助代理服务器访问原始服务器,拿到数据后,代理服务器并没有把原始服务器的头部元数据完全拷贝过来,只是简单的把消息体传给前端的客户。甚至代理服务器把消息体都做了编码,这时候头部的 Content-Encoding就跟原始服务器不同了。

2.3 服务消费者

我们在服务提供者的同级新建项目服务消费者,使用 Spring Initializr 来初始化,以下是服务消费者的项目信息:pom.xml初始化完成,我们在 pom.xml 文件中加入需要的依赖。<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.cdd</groupId> <artifactId>zookeeper-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zookeeper-consumer</name> <description>zookeeper-consumer Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.1.0</version> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>application.properties依赖导入后,我们在 application.properties 配置端口信息server.port=9090接下来我们编写使用 Curator 客户端连接 Zookeeper 服务的代码。CuratorService在项目主类的同级新建目录 service 目录,在 service 目录下新建 CuratorService 类:@Componentpublic class CuratorService implements ApplicationRunner { private static CuratorFramework client; private static final String PROVIDER_NODE = "/imooc/provider"; private static List<String> PROVIDER_SERVER_LIST; private static int NUMBER_OF_REQUESTS = 0; @Override public void run(ApplicationArguments args) throws Exception { // 构建 CuratorFramework 客户端,并开启会话 buildCuratorClient(); // 获取服务列表 getAListOfServiceAddresses(); // 开启对 PROVIDER_NODE 子节点变化事件的监听 startMonitoring(); } /** * 构建 CuratorFramework 客户端,并开启会话 */ private void buildCuratorClient() { // 使用 CuratorFrameworkFactory 构建 CuratorFramework client = CuratorFrameworkFactory.builder() .sessionTimeoutMs(10000) // Zookeeper 地址 .connectString("127.0.0.1:2181") // 重连策略 .retryPolicy(new RetryForever(10000)) .build(); // 开启会话 client.start(); System.out.println(">>> 服务消费者连接 Zookeeper "); } /** * 获取服务列表 * * @throws Exception Exception */ private void getAListOfServiceAddresses() throws Exception { Stat stat = client.checkExists().forPath(PROVIDER_NODE); if (stat == null) { throw new RuntimeException("服务地址未注册到 Zookeeper"); } else { PROVIDER_SERVER_LIST = client.getChildren().forPath(PROVIDER_NODE); } } /** * 开启对 PROVIDER_NODE 子节点变化事件的监听 */ public void startMonitoring() { // 构建 CuratorCache 实例 CuratorCache cache = CuratorCache.build(client, PROVIDER_NODE); // 使用 Fluent 风格和 lambda 表达式来构建 CuratorCacheListener 的事件监听 CuratorCacheListener listener = CuratorCacheListener.builder() // 开启对 PROVIDER_NODE 节点的子节点变化事件的监听 .forPathChildrenCache(PROVIDER_NODE, client, (curator, event) -> // 重新获取服务列表 PROVIDER_SERVER_LIST = curator.getChildren().forPath(PROVIDER_NODE)) // 初始化 .forInitialized(() -> System.out.println(">>> CuratorCacheListener 初始化")) // 构建 .build(); // 注册 CuratorCacheListener 到 CuratorCache cache.listenable().addListener(listener); // CuratorCache 开启缓存 cache.start(); } /** * 轮询策略,按顺序获取服务地址 * * @return 服务地址 */ public String roundRobin() { if (PROVIDER_SERVER_LIST.isEmpty()){ throw new RuntimeException(">>> 服务提供者地址列表为空"); } int i = NUMBER_OF_REQUESTS % PROVIDER_SERVER_LIST.size(); NUMBER_OF_REQUESTS++; return PROVIDER_SERVER_LIST.get(i); }}在 CuratorService 中,我们提供了创建 Curator 客户端的方法,获取服务地址列表的方法,对父节点的子节点变化事件开启监听的方法,以及对服务的负载均衡策略的方法轮询策略。在服务消费者启动时,连接 Zookeeper 服务,获取已注册的服务地址列表,并对服务地址临时节点的父节点开启监听。监听到子节点的变化事件时,则重新获取服务地址列表。ConsumerController这里我们使用 RESTful 的风格来调用服务消费者的方法,在 service 同级创建目录 controller ,在 controller 中创建 ConsumerController 类:@RestController@RequestMapping("/consumer")public class ConsumerController { @Autowired private CuratorService curatorService; @Autowired private RestTemplate restTemplate; /** * 调用方法 * http://localhost:9090/consumer/callMethod * * @return String */ @GetMapping("/callMethod") public String callMethod() { // 轮询策略获取服务地址 String s = curatorService.roundRobin(); // 使用 RestTemplate 远程调用服务的 /provider/callMethod 方法,String.class 为返回值类型 return restTemplate.getForObject("http://" + s + "/provider/callMethod", String.class); }}我们使用了 RestTemplate 来远程调用 RESTful 风格的接口,所以我们需要把 RestTemplate 注入到 Spring IOC 容器中。RestTemplate我们在服务消费者项目的主类中注入Bean RestTemplate :package cn.cdd.zookeeper.consumer;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@SpringBootApplicationpublic class ZookeeperConsumerApplication { public static void main(String[] args) { SpringApplication.run(ZookeeperConsumerApplication.class, args); } @Bean public RestTemplate restTemplate(){ return new RestTemplate(); }}controller 编写完毕后,我们就可以对我们的服务消费者进行测试了。

7. 错误信息

如果状态码是 4xx,服务器就应该向用户返回出错信息。一般来说,返回的信息是键值对形式的数据,将 error 作为键名,出错信息作为键值即可。比如,在一个提供查询学生信息的 API 中,要求客户端提供正确的 API key(可以理解为输入了正确的用户名和密码)才能访问,如果提供的 API key 不正确,此时服务器应拒绝访问,并返回错误信息。这样,客户端就知道了为何没能查到信息,修改成正确的 API key 即可。{ error: "Invalid API key"}

2. 数据的封装

试想一下,如果你在电脑上使用聊天工具,跟对方说了一句 你好,对方的电脑如果只收到了 你好的电频信号,是不能直接解析出来信息的。电脑解析电平信号需要解决很多问题:这个电信号我该用什么规则解析出正确的字符?这信息是谁发给我的?我的电脑现在运行着微信/ QQ /邮件服务等,它到底跟哪个应用交互的?对方的地址是什么,我要怎么回复出去?等等问题很多,所以信息的发送不止是简单的电信号转换,还要给我们的数据添加额外的很多标识,让对方机器清楚你是谁,哪里来的,跟我这台电脑的哪个程序交互等信息。网络模型就很详细的说明了里面具体要处理的事情,这里根据标准的 ISO 七层模型讲解。

4.1 Zookeeper 客户端处理 ACL 请求

在 Zookeeper 客户端中,当我们使用 addauth digest mooc:mooc 命令来添加认证用户信息时,Zookeeper 客户端会使用 ClientCnxn 客户端类的 addAuthInfo 方法来封装请求信息,把请求类型包装成权限类请求,封装完毕后发送给服务端。// 添加认证信息,参数一:授权类型,参数二:认证信息的字节数组public void addAuthInfo(String scheme, byte[] auth) { // 判断当前客户端状态 if (this.state.isAlive()) { // 封装认证信息 scheme:digest this.authInfo.add(new ClientCnxn.AuthData(scheme, auth)); // 封装请求头 -4为请求头的xid,100为请求类型:auth this.queuePacket(new RequestHeader(-4, 100), (ReplyHeader)null, new AuthPacket(0, scheme, auth), (Record)null, (AsyncCallback)null, (String)null, (String)null, (Object)null, (WatchRegistration)null); }}简单地介绍了 Zookeeper 客户端处理权限类请求的过程,接下来就是 Zookeeper 服务端的处理过程了。

4. 乐观锁

乐观是一种积极的解决问题的态度。所谓乐观锁认为系统中的事务并发更新不会很频繁,即使冲突了也没事,大不了重新再来一次。基本思想:每次提交一个事务更新时,查看要修改的数据从上次读取以后有没有被其它事务修改过,如果修改过,那么更新就会失败。实现方案:在实体中增加一个版本控制字段,每次事务更新后就将版本 (Version) 字段的值加 1。Tips: 乐观锁本质就是版本控制管理的实现,记录的每一次更新操作都会以版本递增的方式进行记录。一个事务在更新之前,先获取记录的当前版本号,更新时,如果版本还是最新的则可以更新,否则说明有事务比你先更新,则需要放弃。或者重新查询到最新版本信息后再更新。所以,在乐观锁的实现中,冲突是常态。实现过程:在学生实体类中添加新属性,用来记录每次更新的版本号。public class Student implements Serializable {//省略…… @Versionprivate Long version;//省略…… }stu = (Student) session.get(Student.class, new Integer(1));System.out.println("当前版本号:"+stu.getVersion);//模拟延迟,如果在这个时间内有其它事务进行了更新操作,此事务的更新不会成功Thread.sleep(30000);stu.setStuName("Hibernate");transaction.commit();好了,悲观也好,乐观也好,只是一种解决问题的态度。对于这两种态度,咱们要总结一下。乐观锁:优势:性能好,并发性高。缺点:用户体验不好,可能会出现高高兴兴去更新,却告知已经有人捷足先登了。悲观锁:优势:锁住记录为我所用,没修改完成之前,其他事务只能瞪眼瞧着,时间虽然延迟,至少心里有底。缺点:并发性不好,性能不高。Hibernate 的其它性能优化:随时使用 Session.clear()及时清除 Session 缓存区的内容;1+N 问题 ( 一条 SQL 语句能解决的问题用了很多条 SQL 语句来实现) ;使用 Criteria 查询可以解决这个问题;Lazy 加载:需要时,使用 get() 方法发出 SQL 语句。使用类似于 from Student s left join s.classRoom c 的关联查询语句。缓存使用:在对象更新、删除、添加相对于查询要少得多时, 二级缓存的应用将不怕 n+1 问题,因为即使第一次查询很慢,之后直接缓存命中也是很快的,刚好又利用了 n+1。

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号