大部分情况下,我们希望在一个功能的灰度放量过程中,某个特定用户一旦进入了灰度放量组,在灰度比例不减少的情况下,总是进入灰度组。不希望用户因为刷新页面、重新打开APP、请求被分配到另一个服务端实例等原因,一会看到新功能,一会看不到新功能,从而感到迷惑。要达到用户稳定进入灰度组,只需要在上述代码第三步创建 User 时指定stableRollout 即可,具体使用详情见:docs.featureprobe.io/zh-CN/tutor…
segment是lucene的概念,也是实现搜索的关键。名称 扩展名 简要描述
Term Dictionary .tim term词典,存储term信息
Term Index .tip 指向term词典的索引
Frequencies .doc 包含了有term的频率的文档列表
Positions .pos 存储了每个出现在索引中的term的位置信息
Payloads .pay 存储了额外的每一个位置的元数据信息如一个字符偏移和用户的负载
Field Index .fdx 包含field data的指针
Field Data .fdt 存储docs里的field表1 segment文件
Donald Knuth(高德纳)是一位计算机科学界的著名学者和计算机程序设计的先驱之一。他被誉为计算机科学的“圣经”《计算机程序设计艺术》的作者,提出了著名的“大O符号”来描述算法的时间复杂度和空间复杂度,开发了TeX系统用于排版科技文献,获得过图灵奖、冯·诺伊曼奖、美国国家科学奖章等多项荣誉。今天要说的就是他所提出的一条软件设计重要原则 Premature optimization is the root of all evil过早优化是万恶之源。
IBM OS/360操作系统:在20世纪60年代,IBM公司开发了OS/360操作系统,这是当时最大的软件工程项目之一。在开发过程中,IBM公司过于关注代码的性能问题,导致代码的复杂性增加,开发时间延误,最终导致项目的失败。我知晓这个项目还是在我最近在阅读的一本软件工程经典书籍《人月神话》中,也推荐大家阅读下,这个项目虽然最终失败了,但也给整个软件工程领域留下了宝贵的经验。
Windows Vista操作系统:在21世纪初,微软公司开发了Windows Vista操作系统,这是当时最大的软件工程项目之一。在开发过程中,微软公司过于关注代码的性能问题,导致代码的复杂性增加,开发时间延误,最终导致操作系统的用户体验不佳,市场反响不佳。话说这个操作系统我还用过呢,用户界面还是很漂亮的,很多UI设计也被沿用到了Window7中。
果不其然,发布后的第二天凌晨1点多,又出现了大量的 RetriableCommitFailedException,只是这次换了个 Topic,并且异常的原因又多出了其它Caused by 。
org.apache.kafka.clients.consumer.RetriableCommitFailedException: Offset commit failed with a retriable exception. You should retry committing the latest consumed offsets.
Caused by: org.apache.kafka.common.errors.DisconnectException
...
...
E16:23:31.640 RuntimeException org.apache.kafka.clients.consumer.RetriableCommitFailedException ERROR
...
...
org.apache.kafka.clients.consumer.RetriableCommitFailedException: Offset commit failed with a retriable exception. You should retry committing the latest consumed offsets.
Caused by: org.apache.kafka.common.errors.TimeoutException: The request timed out.
可以直接打开 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)