Nginx 如何支持http和https的访问 作者: lovingyu_er 时间: 2020-09-23 17:06:00 分类: NGINX,运维优化,Swoole-PHP 评论 在配置网站的http和https访问的时候,我们一般会将http直接重定向的https的网址,我的网站在引入websocket-test测试的时候,出现了https的时候,不能测试ws的协议,安全考虑就是https网址不能访问ws,在FIrefox的浏览器中会提示: ``` DOMException: The operation is insecure. ``` 在google Chrome中会提示: ``` websocket-test.html:230 Mixed Content: The page at 'https://darrykinger.com/websocket-test.html' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://ws.domain.com:9502/uuid/api'. This request has been blocked; this endpoint must be available over WSS. ``` 原因:HTTPS是基于SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密,所以在HTTPS站点调用某些非SSL验证的资源时浏览器可能会阻止。同理ws和wss也是 解决方案: 配置nginx ,使其既支持https和http协议,我原来的网址访问都是从http自动跳转到https,在配置文件中,有了重定向的功能: ``` server { listen 80; server_name domain.com; return 301 https://$server_name$request_uri; } ``` 先将该模块配置注释掉: ``` #server { # listen 80; # server_name darrykinger.com; # return 301 https://$server_name$request_uri; # } ``` 在另外一个server模块中,增加一些修改,原来的配置如下:(....代表是省略了,因为在下面的配置中都没有更改) ``` server { listen 443 ; ssl on; root /usr/share/nginx/html/typecho; index index.php index.html index.htm; # Make site accessible from http://localhost/ server_name darrykinger.com; ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; .... location / { .... } ..... } ``` 更改后如下: ``` server { listen 80; listen 443 ssl; # ssl on; root /usr/share/nginx/html/typecho; index index.php index.html index.htm; # Make site accessible from http://localhost/ server_name darrykinger.com; ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ... ssl_prefer_server_ciphers on; location / { ... } .... } ``` 配置项目中,将原来的```ssl on;```修改为```ssl offf;```,也就是在访问该模块的时候,并不开启服务器与浏览器证书验证,但是并不是就关闭了```listen xx;```的此处的配置,用户可以在```listen xx;```里面进行灵活的配置.也就是在访问https的时候要进行证书验证,那么在访问http的时候,不进行证书的验证。 ######ssl参数: ``` Syntax: ssl on | off; Default: ssl off; Context: http, server ``` 该参数在```1.15.0```的版本中会被弃用。```The ssl parameter of the listen directive should be used instead.``` 这个```ssl```参数会被```listen```参数的配置中取代,所以,在进行配置的时候,要注意自己的nginx版本。
中台 作者: lovingyu_er 时间: 2020-09-21 10:43:38 分类: 架构学习笔记, 技术品鉴 评论 ###中台建设的愿景 1. 中台只是解决问题的一种方案,不要把中台当成问题的本身。 2. 中台的愿景问题 3. 中台的用户和客户是谁? 4. 中台建设的钱从哪里来?众筹模式?投融资模式? 5. 中台建设虽然需要兼顾各方的利益,但更多主要还是解决企业管理层对于公司长期生存与可持续发展的恐惧与焦虑问题。 6. 中台的目标怎么验证?具体到一家企业某个中台的验证指标设计,这是一个复杂过程,而且往往还会不断演进,需要结合上面提到的中台愿景、投资模式、干系人利益点以及其他相关因素来综合设计。我们用到的一些思路和想法,我会在中台的规划与设计篇再为你展开来讲。 7. 企业孵化中台的企业环境是否已经成熟,这个是很重要的。有的企业最终没有成功反而是因为走得太早了,思路太超前了,周边环境还没有就绪。 ####中台建设规划建设方法论概述 企业级问题 公司企业的未来战略问题。 做中台本质上就是在做一个企业级的架构。一个融入了平台新要素的企业级架构。面向用户与创新的平台型企业架构。 #####中台架构D4模型 整体规划到落地交付
MQTT协议 作者: lovingyu_er 时间: 2020-09-14 14:58:35 分类: 朝花夕拾 评论 ###简介 MQTT**消息队列遥测传输**(英语:Message Queuing Telemetry Transport)是ISO 标准(ISO/IEC PRF 20922)下基于**发布 (Publish)/订阅 (Subscribe)**范式的消息协议,可视为“资料传递的桥梁”它工作在 TCP/IP协议族上,是**为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议**,为此,它需要一个**消息中间件**,以**解决当前繁重的资料传输协议**,如:HTTP ####概述 可选协议包含了**高级消息队列协议**,**面向文本的消息传递协议**,**互联网工程任务组约束应用协议**, **可扩展消息与存在协议**,**数据分发服务**,**OPC UA**以及 **web 应用程序消息传递协议**。 MQTT 相较于HTTP, **能节省更多的资源**,**带来较少的传输负担**,也因为这样,在制造业中,让更多人发现 IoT 在设备、厂房的无限可能,发现原来要取机台的温度这么容易,要了解厂区的产量这么方便。 MQTT协议定义了两种网络实体:消息代理(message broker)与客户端(client)。 其中消息代理用于接受来自客户端的消息转发并转发到目标客户端。
物联网平台的物模型 作者: lovingyu_er 时间: 2020-09-09 16:03:28 分类: 架构学习笔记 评论 ###介绍 是对设备在云端的功能描述,包括设备的**属性**、**服务**和**事件**。 物联网平台通过定义一种物的描述语言来描述物模型,称之为TSL(即 Thing Specification Language),采用JSON格式,您可以根据TSL组装上报设备的数据。 就是将实体设备进行数字化,并在云端构建该实体的数据模型。在物联网平台中,定义物模型即定义产品功能。完成功能定义后,系统将自动生成该产品的物模型。物模型描述产品是什么、能做什么、可以对外提供哪些服务。 分别从:属性,服务,事件三个维度来描述一个物理实体。 | 功能类型 | 说明| | :------------: | :------------: | | 属性(property) | 一般用于描述设备运行时的状态,如环境监测设备所读取的当前环境温度等。属性支持GET和SET请求方式。应用系统可发起对属性的读取和设置请求。 | | 服务(Service) | 设备可被外部调用的能力或方法,可设置输入参数和输出参数。相比于属性,服务可通过一条指令实现更复杂的业务逻辑,如执行某项特定的任务。 | | 事件 (event) | 设备运行时的事件。事件一般包含需要被外部感知和处理的通知信息,可包含多个输出参数。如,某项任务完成的信息,或者设备发生故障或告警时的温度等,事件可以被订阅和推送。| ###物模型格式 阿里云的物联网平台,你可以在设备管理产品中,有相关的设备信息: 您可以在产品的功能定义页面,单击**物模型TSL**,查看**JSON格式的TSL**。 重点:```properties```,```events```,```services``` ``` { "schema": "物模型结构定义的访问URL", "profile": { "productKey": "产品ProductKey" }, "properties": [ { "identifier": "属性唯一标识符(产品下唯一)", "name": "属性名称", "accessMode": "属性读写类型:只读(r)或读写(rw)。", "required": "是否是标准功能的必选属性", "dataType": { "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型)、struct(结构体类型,可包含前面7种类型)、array(数组类型,支持int/double/float/text/struct)", "specs": { "min": "参数最小值(int、float、double类型特有)", "max": "参数最大值(int、float、double类型特有)", "unit": "属性单位", "unitName": "单位名称", "size": "数组大小,默认最大128(数组特有)。", "step": "步长,字符串类型。", "item": { "type": "数组元素的类型" } } } } ], "events": [ { "identifier": "事件唯一标识符(产品下唯一,其中post是默认生成的属性上报事件。)", "name": "事件名称", "desc": "事件描述", "type": "事件类型(info、alert、error)", "required": "是否是标准功能的必选事件", "outputData": [ { "identifier": "参数唯一标识符", "name": "参数名称", "dataType": { "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型)、struct(结构体类型,可包含前面7种类型)、array(数组类型,支持int/double/float/text/struct)", "specs": { "min": "参数最小值(int、float、double类型特有)", "max": "参数最大值(int、float、double类型特有)", "unit": "属性单位", "unitName": "单位名称", "size": "数组大小,默认最大128(数组特有)。", "step": "步长,字符串类型。", "item": { "type": "数组元素的类型" } } } } ], "method": "事件对应的方法名称(根据identifier生成)" } ], "services": [ { "identifier": "服务唯一标识符(产品下唯一,其中set/get是根据属性的accessMode默认生成的服务。)", "name": "服务名称", "desc": "服务描述", "required": "是否是标准功能的必选服务", "callType": "async(异步调用)或sync(同步调用)", "inputData": [ { "identifier": "入参唯一标识符", "name": "入参名称", "dataType": { "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型)、struct(结构体类型,可包含前面7种类型)、array(数组类型,支持int/double/float/text/struct)", "specs": { "min": "参数最小值(int、float、double类型特有)", "max": "参数最大值(int、float、double类型特有)", "unit": "属性单位", "unitName": "单位名称", "size": "数组大小,默认最大128(数组特有)。", "step": "步长,字符串类型。", "item": { "type": "数组元素的类型" } } } } ], "outputData": [ { "identifier": "出参唯一标识符", "name": "出参名称", "dataType": { "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型)、struct(结构体类型,可包含前面7种类型)、array(数组类型,支持int/double/float/text/struct)", "specs": { "min": "参数最小值(int、float、double类型特有)", "max": "参数最大值(int、float、 double类型特有)", "unit": "属性单位", "unitName": "单位名称", "size": "数组大小,默认最大128(数组特有)。", "step": "步长,字符串类型。", "item": { "type": "数组元素的类型(数组特有)" } } } } ], "method": "服务对应的方法名称(根据identifier生成)" } ] } ```
一条查询SQL语句在数据库执行的简单介绍 作者: lovingyu_er 时间: 2020-09-03 17:40:00 分类: MYSQL,运维优化,MYSQL -view 评论 ####MYSQL分层架构(客户端/Server层/存储引擎) 结构图大概如下:  #####1. 客户端 客户端,不同的语言有不同的实现数据库连接的驱动,比如PHP有```pdo```,Golang有```xorm```等等,属于应用程序的客户端。 #####2. Server层 Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。 1. 连接器:负责给客户端建立连接,获取权限,维持和管理连接: ``` mysql -uusername -P port -h hostname -p ``` 该命令会与服务器端建立连接,完成经典的tcp握手以后,连接器就开始进行身份验证,也就是需要你输入密码。密码错误,就会显示权限拒绝。如果认证通过,连接器就查询用户的权限,之后的操作对于权限的判断逻辑,都以来这个读取到的权限,即使管理员对这个账户的权限进行了修改,也不会影响已经存在的权限。只有再新建连接才能使用新的连接授权。连接以后,你如果不进行操作,该processlist就处于```sleep```状态。如果大于```wait_timeout```,就会自动断开连接,默认是8小时。 数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。 建立连接的过程通常是比较复杂的,所以我建议你在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。 但是全部使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。 解决方案: 1. 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。 2. 大于 mysql5.7 通过```mysq_reset_connection```来重新初始化连接资源。这个过程不需要重连和重新做权限验证。但是会将连接恢复到刚刚创建完时的状态。 2. 查询缓存 mysql拿到select语句以后,会现在缓存中看看,之前是否有执行过这条语句。之前执行过的select语句会以key-value的形式缓存在内存中。key是以查询的语句作为key,value就是查询的结果。如果命中了缓存,就直接将此value返回给客户端,会提高select的效率。 ####缓存不建议使用的原因: 查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的**查询缓存都会被清空**。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。**除非你的业务就是有一张静态表,很长时间才会更新一次。**比如,**一个系统配置表,那这张表上的查询才适合使用查询缓存。**好在 MySQL 也提供了这种“按需使用”的方式。你可以将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,像下面这个语句一样:(MYSQL8.0版本,直接将此缓存模块去掉了) ``` select SQL_CACHE * from T where ID=10; ``` 注意:**在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用 precheck 验证权限** 3. 分析器 如果没有命中缓存,就开始分析器进行工作了。 3.1. mysql开始对你的select语句进行解析了。分析器先进行词法分析:识别里面的字符串分别是什么,代表什么。 3.2. 语法分析, SQL语句是否满足MYSQL的语法:正确,进入下一步;不正确,收到错误提示:```You have an error in your SQL syntax```的错误提醒。一般会有```near```字样的提示。 4. 优化器 优化器这个时候就会涉及到表的索引设计了。如果表中多个索引的时候,优化器会决定使用哪个索引。在表的语句中有多个join的时候,会决定表的join连接顺序。比如: ``` select * from a join b using(ID) where a.c = 10 and b.d=20; ``` 这条语句既可以从表a里面取出c=10的记录ID的值,再根据ID值关联到表b,再判断b里面d的值是否等于20 也可以从表b里面取出d=20记录的ID的值,再根据ID值关联到a,再判断a里面c是否等于10. 两种执行方法的逻辑结果是一样的,但是效率会不一样,而优化器的作用就是决定选择使用哪一个方案。 经过优化器,这个语句的执行方案就确定下来了,然后进入执行器阶段。 5. 执行器 执行sql语句之前,会首先判断你有没有执行查询的权限,如果没有,就返回没有权限的错误。如果有权限,打开表继续执行。打开表的时候,执行器会根据表的引擎定义,去使用这个引擎提供的接口。 案例: ``` select * from T where ID = 10 ; ```` 5.1. 当ID没有索引的时候,调用InnoDB引擎接口,取这个表的第一行,判断ID值是不是10,如果不是,就跳过;是,就将此行存在结果集中。 5.2. 调用引擎接口取“下一行”,重复相同的逻辑判断,直到最后一行 5.3. 执行遍历,完成后,将结果集返回给客户端。 这样,语句就执行完毕了。 对于有索引的表,执行逻辑也差不多,第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。 你会在数据库的慢查询日志中看到一个 **rows_examined** 的字段,**表示这个语句执行过程中扫描了多少行**。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。我们后面会专门有一篇文章来讲存储引擎的内部机制,里面会有详细的说明。 #####3. 存储引擎 而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。 执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。不过,你也可以通过指定存储引擎的类型来选择别的引擎,比如在 create table 语句中使用 engine=memory, 来指定使用内存引擎创建表。不同存储引擎的表数据存取方式不同,支持的功能也不同。