可以直接打开 IDEA 设置 -> Plugins,在 MarketPlace中搜索SonarLint,直接安装就可以。
还可以直接在官网下载,打开页面https://www.sonarsource.com/products/sonarlint/,在页面中可以看到多种语言、多种开发工具的下载图标,点击下方的 EXPLORE即可到下载页面去下载了。虽然我们只是在 IDEA 中使用,但是它不管支持 Java 、不只支持 IDEA ,还支持 Python、PHP等众多语言,以及 Visual Studio 、VS Code 等众多 IDE。
{ "id": "chatcmpl-6rNPw1hqm5xMVMsyf6PXClRHtNQAI", "object": "chat.completion", "created": 1678179420, "model": "gpt-3.5-turbo-0301", "usage": { "prompt_tokens": 16, "completion_tokens": 339, "total_tokens": 355
}, "choices": [{ "message": { "role": "assistant", "content": "\n\nI. 介绍数字孪生的概念和背景\n A. 数字孪生的定义和意义\n B. 数字孪生的发展历程\n C. 数字孪生在现代工业的应用\n\nII. 数字孪生的构建方法\n A. 数字孪生的数据采集和处理\n B. 数字孪生的建模和仿真\n C. 数字孪生的验证和测试\n\nIII. 数字孪生的应用领域和案例分析\n A. 制造业领域中的数字孪生应用\n B. 建筑和城市领域中的数字孪生应用\n C. 医疗和健康领域中的数字孪生应用\n\nIV. 数字孪生的挑战和发展趋势\n A. 数字孪生的技术挑战\n B. 数字孪生的实践难点\n C. 数字孪生的未来发展趋势\n\nV. 结论和展望\n A. 总结数字孪生的意义和价值\n B. 展望数字孪生的未来发展趋势和研究方向"
}, "finish_reason": "stop", "index": 0
}]
}
// android.view.View.java public ViewTreeObserver getViewTreeObserver() { if (mAttachInfo != null) { return mAttachInfo.mTreeObserver;
} if (mFloatingTreeObserver == null) {
mFloatingTreeObserver = newViewTreeObserver(mContext);
} return mFloatingTreeObserver;
}
getViewTreeObserver() 用于返回当前 View 所在 View 树的观察者。
全局重绘其实覆盖了上述的两个场景:
同一 Activity 中 Fragment 的切换
手动调用 View.setVisibility(View.GONE)
被输入法覆盖
这两个场景都会发生 View 树的重绘。
捕获全局滚动时机
ScrollView, NestedScrollView 的滚动
ViewPager, ViewPager2 的滚动
RecyclerView 的滚动
上述三个时机的共同特点是“发生了滚动”。
每个可滚动的容器控件都提供了各自滚动的监听
// android.view.ScrollView.java publicinterfaceOnScrollChangeListener { voidonScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
}
functioncreateKeyToOldIdx(children, beginIdx, endIdx) { let i, key const map = {} for (i = beginIdx; i <= endIdx; ++i) {
key = children[i].key if (isDef(key)) map[key] = i
} return map
}
IM 架构中的 TCP 长连接接入层的 NET 连接一般会很多,比如单台服务器至少会有几十万,有的甚至会到百万连接;这个长连接的维持,也就代表中会有这么多客户端(用户)的接入。那么我们怎么去管理这些连接?当有数据需要下发的时候,怎么能够快速根据连接信息找到用户、或者根据用户快速定位到网络连接?这就需要我们能够有一个合适的数据结构去维护,并且我们需要考虑一些其他的点比如快速定位、机器内存大小等。
然后 Router Server 提供一个 HTTP 服务的 API 接口,用来返回所有节点中连接数最少的节点的一批 IP 列表(一般可以 3 个)给到客户端。为何不是返回一个呢?因为我们返回的节点,可能因为其他原因导致连接不上,或者连接不稳定,那么此时 客户端就可以有备选方案,选择返回的下一个节点建连。
公司内常规的防火墙策略,通过 iptable 设置 iptables 的防火墙策略。比如限制只能接收指定 IP 和 Port 的包,避免攻击者通过节点上其他端口的漏洞登录机器;比如只接收某些协议(TCP)的包。
SYN 攻击
SYN 攻击是一个典型的 DDOS 攻击,具体就是攻击客户端在短时间内伪造大量不存在的 IP 地址,然后向服务端发送 TCP 握手连接的 SYN 请求包,服务端收到 SYN 包后会回复 ACK 确认包,并等待客户端的 ACK 确认。但是,由于源 IP 地址不是真实有效的,因此服务端需要不断的重发直至 63s 超时后才会断开连接。这些伪造的 SYN 包将长时间占用未连接队列,引起网络堵塞甚至系统瘫痪,让正常的 TCP 握手连接请求不能处理。通过 netstat -n -p TCP | grep SYN_RECV 可以查看是否有大量 SYN_RECV 状态,如果有则可能存在 SYN 攻击。
Linux 在系统层面上,提供了三个选项来应对相关攻击:
• tcp_max_syn_backlog,增大 SYN 连接数
• tcp_synack_retries,减少重试次数
• tcp_abort_on_overflow,过载直接丢弃,拒绝连接
另外,还有一个 tcp_syncookies 参数可以缓解,当 SYN 队列满了后,TCP 会通过相关信息(源 IP、源 port)制造出一个 SYN Cookie 返回,如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie 发回来,然后服务端可以通过 SYN Cookie 建连接。
TCP 长连接层面上
黑名单机制
可以静态或者动态配置黑名单列表,处于黑名单中的 IP 列表则直接拒绝 accept 建连;服务端执行 accept 之后,首先先判断 remote IP 是否存在于黑名单中,如果是则直接 close 连接;如果不是则继续下一步。
限制建连速度
IM 系统为了防止恶意攻击,需要防止单个 IP 大量频繁建连,避免异常 socket 连接数爆满;因此需要限制每个 IP 每秒建立速度,如果单个 IP 在单位时间内建连的连接数超过一定阈值(如 100)该值,则将 IP 列入黑名单并且同时关闭此连接
举个实际的应用案例,针对 IM 系统的发送消息的这个场景,比如微信发送消息,那么当客户端发送的消息,服务端收到后,这个消息肯定要落地存储,这个发送的流程才能算完毕,但是,如果每条消息,服务端都真正存储到 DB 后再返回给客户端说已经正确收到,那么这个性能显然会很低,因为我们知道,写 DB 的性能是很低的,尤其是像微信这种每天有大量消息的 APP。那么这个流程就可以异步化,服务端收到消息后,先把消息写入消息队列,写入队列成功就返回给客户端,然后异步流程去从消息队列里面消费数据然后落地存储到 DB 里面,这样性能就非常高了,因为消息队列的性能会很高。而比较低性能的操作都是异步处理。
分布式数据库的基本思想是将原来集中式数据库中的数据分散存储到多个通过网络连接的数据存储节点上,以获取更大的存储容量和更高的并发访问量,从而提高我们的性能。现在传统的关系型数据库已经开始从集中式模型向分布式架构发展了。一般云服务厂商,都会提供分布式数据库的解决方案,比如腾讯云的 TDSQL MySQL 版,TDSQL for MySQL 是腾讯打造的一款分布式数据库产品,具备强一致高可用、全球部署架构、分布式水平扩展、高性能、企业级安全等特性,同时提供智能 DBA、自动化运营、监控告警等配套设施,为客户提供完整的分布式数据库解决方案。
资源使用层面,我们要合理的分配 CPU 和内存等相关资源,一般 CPU 的使用率不要超过 70%-80%,超过这个阈值后,我们服务的性能就会开始下降,因此一般我们在 70% 的时候就要开始执行扩容。如果是 K8s 容器部署的话,我们可以设置 CPU 使用率超过指定阈值后就自动扩容。当然,如果是物理机部署,或者其他方式,可以同样的进行监控和及时扩容。也就是说,要保证我们所需的各种资源(CPU、内存、磁盘、带宽)都在一个合理的范围。
SPL(Structured Process Language)是一个开源结构化数据计算引擎,本身提供了不依赖数据库的强大计算能力,SPL内置了很多高性能算法,尤其是对关联运算做了优化,对不同的关联场景采用不同的手段,可以大幅提升关联性能,从而不用宽表也能实时关联以满足多维分析时效性的需要。同时,SPL还提供了高性能存储,配合高效算法可以进一步发挥性能优势。
SEL ECT ct1.area,o.emp_id,sum(o.amount) somt FROM orders o JOIN customer c ON o.cus_id = c.cus_id JOIN city ct1 ON c.city_id = ct1.city_id JOIN employee e ON o.emp_id = e.emp_id JOIN city ct2 ON e.city_id = ct2.city_id WHERE ct2.area = 'east' AND year(o.order_date)= 2022 GRO UP BY ct1.area, o.emp_id
SEL ECT cus_id.city_id.area,emp_id,sum(amount) somt FROM orders WHERE emp_id.city_id.area == "east"ANDyear(order_date)== 2022 BY cus_id.city_id.area,emp_id
JVMTIAgent是一个利用JVMTI暴露出来的接口提供了代理启动时加载(Agent On Load)、代理通过Attach形式加载(Agent On Attach)和代理卸载(Agent On Unload)功能的动态库。而Instrument Agent可以理解为一类JVMTIAgent动态库,别名是JPLISAgent(Java Programming Language Instrumentation Services Agent),也就是专门为Java语言编写的插桩服务提供支持的代理。
2.2.3 启动时和运行时加载Instrument Agent过程
2.3 那些年JVM和HotSwap之间的“相爱相杀”
围绕着Method Body的HotSwap JVM一直在进行改进。从1.4版本开始,JPDA引入HotSwap机制(JPDA Enhancements),实现Debug时的Method Body的动态性。大家可参考文档:enhancements1.4 。 1.5版本开始通过JVMTI实现的java.lang.instrument(Java Platform SE 8)的Premain方式,实现Agent方式的动态性(JVM启动时指定Agent)。大家可参考文档:package-summary。
1.6版本又增加Agentmain方式,实现运行时动态性(通过The Attach API 绑定到具体VM)。大家可参考文档:package-summary 。基本实现是通过JVMTI的retransformClass/redefineClass进行method、body级的字节码更新,ASM、CGLib基本都是围绕这些在做动态性。但是针对Class的HotSwap一直没有动作(比如Class添加method、添加field、修改继承关系等等),为什么会这样呢?因为复杂度过高,且没有很高的回报。
User ClassLoader是框架自定义的ClassLoader统称,例如Jetty项目是WebAppclassLoader。其中Urlclasspath为当前项目的lib文件件下,例如Spring Boot项目也是从当前项目BOOT-INF/lib/路径中加载CLass等等,不同框架的自定义位置稍有不同。所以针对此类情况,Agent必须拿到用户的自定义Classloader,如果是常规方式启动的,比如普通Spring XML项目,借助Plus(美团内部服务发布平台)发布,此类没有自定义Classloader,是默认AppClassLoader,所以Agent在用户项目启动过程中,借助字节码增强的方式来获取到真正的用户Classloader。
booleanisPrime=number>0; // 计算number的平方根为k,可以减少一半的计算量 intk= (int) Math.sqrt(number); for (inti=2; i<=k; i++) { if (number%i==0) { isPrime=false; break; } } returnisPrime;
二、对称加密和非对称加密
假如 Alice 时而需要给北漂搬砖的 Bob 发一些信息,为了安全起见两个人相互协商了一个加密的方式。比如 Alice 发送了一个银行卡密码 142857 给 Bob,Alice 会按照与 Bob 的协商方式,把 142857 * 2 = 285714 的结果传递给 Bob,之后 Bob 再通过把信息除以2拿到结果。
定理 1 令 a 为整数, d 为正整数, 则存在唯一的整数 q 和 r, 满足 0⩽r<d, 使得 a=dq+r.
当 r=0 时, 我们称 d 整除 a, 记作 d∣a; 否则称 d 不整除 a, 记作 d∤a
整除有以下基本性质:
定理 2 令 a, b, c 为整数, 其中 a≠0a≠0. 则:
对任意整数 m,n,如果 a∣b 且 a∣c, 则 a∣(mb + nc)
如果 a∣b, 则对于所有整数 c 都有 a∣bc
如果 a∣b 且 b∣c, 则 a∣c
1.2 模算术
在数论中我们特别关心一个整数被一个正整数除时的余数. 我们用 a mod m = b表示整数 a 除以正整数 m 的余数是 b. 为了表示两个整数被一个正整数除时的余数相同, 人们又提出了同余式(congruence).
定义 1 如果 a 和 b 是整数而 m 是正整数, 则当 m 整除 a - b 时称 a 模 m 同余 b. 记作 a ≡ b(mod m)
a ≡ b(mod m) 和 a mod m= b 很相似. 事实上, 如果 a mod m = b, 则 a≡b(mod m). 但他们本质上是两个不同的概念. a mod m = b 表达的是一个函数, 而 a≡b(mod m) 表达的是两个整数之间的关系.
模算术有下列性质:
定理 3 如果 m 是正整数, a, b 是整数, 则有
(a+b)mod m=((a mod m)+(b mod m)) mod m
ab mod m=(a mod m)(b mod m) mod m
根据定理3, 可得以下推论
推论 1 设 m 是正整数, a, b, c 是整数; 如果 a ≡ b(mod m), 则 ac ≡ bc(mod m)
证明 ∵ a ≡ b(mod m), ∴ (a−b) mod m=0 . 那么
(ac−bc) mod m=c(a−b) mod m=(c mod m⋅(a−b) mod m) mod m=0
∴ ac ≡ bc(mod m)
需要注意的是, 推论1反之不成立. 来看推论2:
推论 2 设 m 是正整数, a, b 是整数, c 是不能被 m 整除的整数; 如果 ac ≡ bc(mod m) , 则 a ≡ b(mod m)
证明 ∵ ac ≡ bc(mod m) , 所以有
(ac−bc)mod m=c(a−b)mod m=(c mod m⋅(a−b)mod m) mod m=0
∵ c mod m≠0 ,
∴ (a−b) mod m=0,
∴a ≡ b(mod m) .
2. 最大公约数
如果一个整数 d 能够整除另一个整数 a, 则称 d 是 a 的一个约数(divisor); 如果 d 既能整除 a 又能整除 b, 则称 d 是 a 和 b 的一个公约数(common divisor). 能整除两个整数的最大整数称为这两个整数的最大公约数(greatest common divisor).
定义 2 令 a 和 b 是不全为零的两个整数, 能使 d∣ad∣a 和 d∣bd∣b 的最大整数 d 称为 a 和 b 的最大公约数. 记作 gcd(a,b)
定理 4贝祖定理 如果整数 a, b 不全为零, 则 gcd(a,b)是 a 和 b 的线性组合集 {ax+by∣x,y∈Z}中最小的元素. 这里的 x 和 y 被称为贝祖系数
证明 令 A={ax+by∣x,y∈Z}. 设存在 x0x0, y0y0 使 d0d0 是 A 中的最小正元素, d0=ax0+by0 现在用 d0去除 a, 这就得到唯一的整数 q(商) 和 r(余数) 满足
又 0⩽r<d0, d0 是 A 中最小正元素
∴ r=0 , d0∣a.
同理, 用 d0d0 去除 b, 可得 d0∣b. 所以说 d0 是 a 和 b 的公约数.
设 a 和 b 的最大公约数是 d, 那么 d∣(ax0+by0)即 d∣d0
∴∴ d0 是 a 和 b 的最大公约数.
我们可以对辗转相除法稍作修改, 让它在计算出最大公约数的同时计算出贝祖系数.
defgcd(a, b): ifb==0: returna, 1, 0 d, x, y = gcd(b, a% b) returnd, y, x- (a/b) *y
3. 线性同余方程
现在我们来讨论求解形如 ax≡b(modm) 的线性同余方程. 求解这样的线性同余方程是数论研究及其应用中的一项基本任务. 如何求解这样的方程呢? 我们要介绍的一个方法是通过求使得方程 ¯aa≡1(mod m) 成立的整数 ¯a. 我们称 ¯a 为 a 模 m 的逆. 下面的定理指出, 当 a 和 m 互素时, a 模 m 的逆必然存在.
定理 5 如果 a 和 m 为互素的整数且 m>1, 则 a 模 m 的逆存在, 并且是唯一的.
证明 由贝祖定理可知, ∵ gcd(a,m)=1 , ∴ 存在整数 x 和 y 使得 ax+my=1 这蕴含着 ax+my≡1(modm) ∵ my≡0(modm), 所以有 ax≡1(modm)
∴ x 为 a 模 m 的逆.
这样我们就可以调用辗转相除法 gcd(a, m) 求得 a 模 m 的逆.
a 模 m 的逆也被称为 a 在模m乘法群 Z∗m 中的逆元. 这里我并不想引入群论, 有兴趣的同学可参阅算法导论
求得了 a 模 m 的逆 ¯a 现在我们可以来解线性同余方程了. 具体的做法是这样的: 对于方程 ax≡b(modm)a , 我们在方程两边同时乘上 ¯a, 得 ¯aax≡¯ab(modm)
应用层是网络应用程序和网络协议存放的分层,因特网的应用层包括许多协议,例如我们学 web 离不开的 HTTP,电子邮件传送协议 SMTP、端系统文件上传协议 FTP、还有为我们进行域名解析的 DNS 协议。应用层协议分布在多个端系统上,一个端系统应用程序与另外一个端系统应用程序交换信息分组,我们把位于应用层的信息分组称为 报文(message)。
因特网的网络层负责将称为 数据报(datagram) 的网络分层从一台主机移动到另一台主机。网络层一个非常重要的协议是 IP 协议,所有具有网络层的因特网组件都必须运行 IP 协议,IP 协议是一种网际协议,除了 IP 协议外,网络层还包括一些其他网际协议和路由选择协议,一般把网络层就称为 IP 层,由此可知 IP 协议的重要性。
链路层
现在我们有应用程序通信的协议,有了给应用程序提供运输的协议,还有了用于约定发送位置的 IP 协议,那么如何才能真正的发送数据呢?为了将分组从一个节点(主机或路由器)运输到另一个节点,网络层必须依靠链路层提供服务。链路层的例子包括以太网、WiFi 和电缆接入的 DOCSIS 协议,因为数据从源目的地传送通常需要经过几条链路,一个数据包可能被沿途不同的链路层协议处理,我们把链路层的分组称为 帧(frame)
浏览器正式的名字叫做 Web Broser,顾名思义,就是检索、查看互联网上网页资源的应用程序,名字里的 Web,实际上指的就是 World Wide Web,也就是万维网。
我们在地址栏输入URL(即网址),浏览器会向DNS(域名服务器,后面会说)提供网址,由它来完成 URL 到 IP 地址的映射。然后将请求你的请求提交给具体的服务器,在由服务器返回我们要的结果(以HTML编码格式返回给浏览器),浏览器执行HTML编码,将结果显示在浏览器的正文。这就是一个浏览器发起请求和接受响应的过程。
Web 服务器
Web 服务器的正式名称叫做 Web Server,Web 服务器一般指的是网站服务器,上面说到浏览器是 HTTP 请求的发起方,那么 Web 服务器就是 HTTP 请求的应答方,Web 服务器可以向浏览器等 Web 客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache、 Nginx 、IIS。
IP 协议的全称是 Internet Protocol 的缩写,它主要解决的是通信双方寻址的问题。IP 协议使用 IP 地址 来标识互联网上的每一台计算机,可以把 IP 地址想象成为你手机的电话号码,你要与他人通话必须先要知道他人的手机号码,计算机网络中信息交换必须先要知道对方的 IP 地址。(关于 TCP 和 IP 更多的讨论我们会在后面详解)
DNS
你有没有想过为什么你可以通过键入 http://www.google.com 就能够获取你想要的网站?我们上面说到,计算机网络中的每个端系统都有一个 IP 地址存在,而把 IP 地址转换为便于人类记忆的协议就是 DNS 协议。
DNS 的全称是域名系统(Domain Name System,缩写:DNS),它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。
URI / URL
我们上面提到,你可以通过输入 http://www.google.com 地址来访问谷歌的官网,那么这个地址有什么规定吗?我怎么输都可以?AAA.BBB.CCC 是不是也行?当然不是的,你输入的地址格式必须要满足 URI 的规范。
GET 获取资源,GET 方法用来请求访问已被 URI 识别的资源。指定的资源经服务器端解析后返回响应内容。也就是说,如果请求的资源是文本,那就保持原样返回;
POST 传输实体,虽然 GET 方法也可以传输主体信息,但是便于区分,我们一般不用 GET 传输实体信息,反而使用 POST 传输实体信息,
PUT 传输文件,PUT 方法用来传输文件。就像 FTP 协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。
但是,鉴于 HTTP 的 PUT 方法自身不带验证机制,任何人都可以上传文件 , 存在安全性问题,因此一般的 W eb 网站不使用该方法。若配合 W eb 应用程序的验证机制,或架构设计采用REST(REpresentational State Transfer,表征状态转移)标准的同类 Web 网站,就可能会开放使用 PUT 方法。
HEAD 获得响应首部,HEAD 方法和 GET 方法一样,只是不返回报文主体部分。用于确认 URI 的有效性及资源更新的日期时间等。
DELETE 删除文件,DELETE 方法用来删除文件,是与 PUT 相反的方法。DELETE 方法按请求 URI 删除指定的资源。
OPTIONS 询问支持的方法,OPTIONS 方法用来查询针对请求 URI 指定的资源支持的方法。