killercoda CKA:Services & Networking

killercoda CKA:Services & Networking

D瓜哥
1. Services & Networking - Services Services & Networking - Services You have an existing Nginx pod named nginx-pod. Perform the following steps: Expose the nginx-pod internally within the cluster using a Service named nginx-service . Use port forwarding to service to access the Welcome content of nginx-pod using the curl command. # @author D瓜哥 · https://www.diguage.com $ kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx-pod 1/1 Running 0 8m48s app=nginx $ cat svc.yaml apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80 $ kubectl apply -f svc.yaml service/nginx-service created $ kubectl port-forward service/nginx-service 8081:80 Forwarding from 127.0.0.1:8081 -> 80 Forwarding from [::1]:8081 -> 80 Handling connection for 8081 # 打开另外一个终端 $ curl localhost:8081 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
killercoda CKA:Architecture, Installation & Maintenance

killercoda CKA:Architecture, Installation & Maintenance

D瓜哥
1. Architecture, Installation & Maintenance - Create Pod Architecture, Installation & Maintenance - Create Pod Create a pod called sleep-pod using the nginx image and also sleep (using command ) for give any value for seconds. # @author D瓜哥 · https://www.diguage.com $ cat nginx.yaml apiVersion: v1 kind: Pod metadata: name: sleep-pod spec: containers: - name: nginx image: nginx command: - sleep - "3600" $ kubectl apply -f nginx.yaml pod/sleep-pod created $ kubectl get pod NAME READY STATUS RESTARTS AGE sleep-pod 1/1 Running 0 5s
理解数据库分片

理解数据库分片

D瓜哥
最近在 DigitalOcean 社区看到一篇文章,讲解数据库分片架构的,感觉非常不错,图文并茂,翻译过来,分享给需要的朋友。 介绍 任何应用程序或网站,如果出现大幅增长,最终都需要进行扩展,以适应流量的增加。对于数据驱动型应用程序和网站来说,在进行扩展时必须确保数据的安全性和完整性。很难预测一个网站或应用程序会变得多受欢迎,或者它的受欢迎程度会维持多久,这就是为什么一些组织会选择一种允许他们动态扩展数据库的数据库架构。 在这篇概念性文章中,我们将讨论这样一种数据库架构:分片数据库。近年来,分片数据库受到了广泛关注,但很多人并不清楚什么是分片数据库,也不知道在哪些情况下分片数据库才有意义。我们将介绍什么是分片、分片的一些主要优点和缺点,以及几种常见的分片方法。 什么是分片? 分片是一种与水平分区相关的数据库架构模式,即把一个表的行分成多个不同的表,称为分区。每个分区都有相同的模式和列,但也有完全不同的行。同样,每个分区中的数据都是唯一的,与其他分区中的数据无关。 从水平分区与垂直分区的关系角度来思考水平分区可能会有所帮助。在垂直分区表中,整个列都被分离出来并放入新的、不同的表中。一个垂直分区中的数据独立于所有其他分区中的数据,每个分区都有不同的行和列。下图说明了如何对表格进行水平和垂直分区: 图 1. 水平分区与垂直分区 分片是指将数据分割成两个或多个较小的块,称为逻辑分片。然后,逻辑分片分布在不同的数据库节点上,称为物理分片,物理分片可容纳多个逻辑分片。尽管如此,所有分片中保存的数据共同代表了一个完整的逻辑数据集。 数据库分片是无共享架构的典范。这意味着分片是独立的,它们不共享任何相同的数据或计算资源。不过,在某些情况下,将某些表复制到每个分片中作为参考表是有意义的。例如,假设有一个应用程序的数据库依赖于重量测量的固定转换率。通过将包含必要转换率数据的表复制到每个分片中,有助于确保每个分片中都包含查询所需的所有数据。 通常,分片是在应用程序级实现的,这意味着应用程序包含定义向哪个分片传输读写的代码。不过,有些数据库管理系统内置了分片功能,允许你直接在数据库级实施分片。 鉴于以上对分片的概述,让我们来看看这种数据库架构的一些优点和缺点。 分片的优点 对数据库进行分片的主要吸引力在于,它有助于促进水平扩展,也称为向外扩展,横向扩展。水平扩展是指在现有堆栈中添加更多机器,以分散负载,允许更多流量和更快处理。这通常与垂直扩展(也称向上扩展)形成对比,后者涉及升级现有服务器的硬件,通常是增加更多内存或 CPU。 在一台机器上运行一个关系数据库,并根据需要通过升级其计算资源来扩大其规模相对简单。但归根结底,任何非分布式数据库在存储和计算能力方面都是有限的,因此可以自由横向扩展,会让你的设置更加灵活。 一些人选择分片数据库架构的另一个原因是为了加快查询响应速度。在未分片的数据库上提交查询时,数据库可能需要搜索查询表中的每一行,然后才能找到所需的结果集。对于使用大型单体数据库的应用程序来说,查询速度会慢得令人望而却步。不过,通过将一个表分片成多个表后,查询需要处理的行数就会减少,返回结果集的速度也会快得多。 分片还可以减轻中断造成的影响,从而提高应用程序的可靠性。如果您的应用程序或网站依赖的是未分片的数据库,中断有可能导致整个应用程序不可用。 而使用分片数据库时,故障可能只影响单个分片。尽管这可能会导致部分用户无法使用应用程序或网站的某些部分,但总体影响仍小于整个数据库崩溃的影响。 分片的缺点 虽然分片可以使数据库的扩展更容易并提高性能,但它也会带来一些限制。在此,我们将讨论其中的一些限制,以及为什么要避免使用分片。 人们在使用分片时遇到的第一个困难是正确实施分片数据库架构的复杂性。如果操作不当,分片过程很有可能导致数据丢失或表损坏。即使操作正确,分片也可能对团队的工作流程产生重大影响。用户必须跨多个分片位置管理数据,而不是从一个入口点访问和管理数据,这可能会对某些团队造成干扰。 用户在对数据库进行分片后有时会遇到一个问题,那就是分片最终会变得不平衡。举例来说,假设你的数据库有两个独立的分片,一个用于存储姓氏以字母 A 至 M 开头的客户,另一个用于存储姓氏以字母 N 至 Z 开头的客户。然而,你的应用程序为大量姓氏以字母 G 开头的人提供服务。 A-M 分区已成为所谓的数据库热点。在这种情况下,分片给数据库带来的任何好处都会被速度变慢和崩溃所抵消。数据库很可能需要修复和重新分片,以使数据分布更均匀。 另一个主要缺点是,一旦数据库被分片,就很难将其恢复到未分片的架构。数据库分片前的任何备份都不包括分片后写入的数据。 因此,要重建未分片的原始架构,就需要将新的分片数据与旧的备份合并,或者将分片后的数据库变回单一数据库,这两种方法都会耗费大量成本和时间。 最后一个需要考虑的缺点是,并非每个数据库引擎都支持分片。例如,PostgreSQL 不包括自动分片功能,但可以手动分片 PostgreSQL 数据库。 有一些 Postgres 变种确实包含自动分片功能,但它们往往落后于最新的 PostgreSQL 版本,而且缺乏某些其他功能。一些专门的数据库技术(如 MySQL Cluster 或某些数据库即服务产品(如 MongoDB Atlas))确实包含自动分片功能,但这些数据库管理系统的普通版本并不包含。因此,分片通常需要“自己开发”。这意味着通常很难找到分片文档或故障排除技巧。 当然,这些只是分片前需要考虑的一些一般性问题。根据其用例,对数据库进行分片可能会有更多潜在的缺点。 现在,我们已经介绍了分片的一些缺点和优点,下面将介绍几种不同的分片数据库架构。 分片架构 一旦决定对数据库进行分片,接下来需要考虑的就是如何分片。在运行查询或将输入数据分发到分片表或数据库时,将数据分发到正确的分片至关重要。否则,可能会导致数据丢失或查询缓慢。在本节中,我们将介绍几种常见的分片架构,每种架构都使用略有不同的流程在分片间分发数据。 基于键的分片 基于密钥的分片,也称为基于散列的分片,涉及使用从新写入的数据中提取的值,例如客户的 ID 编号、客户端应用程序的 IP 地址、邮政编码等并将其输入散列函数,以确定数据应进入哪个分片。散列函数是一种输入数据(如客户电子邮件)并输出离散值(即散列值)的函数。在分片的情况下,散列值是一个分片 ID,用于确定输入的数据将存储在哪个分片上。整个过程如下: 图 2. 基于键的分片 为确保条目以一致的方式放置于正确的分片,输入散列函数的值都应来自同一列。此列被称为分片键。简单来说,分片键与主键类似,都是用于为单个行建立唯一标识符的列。从广义上讲,分片键应该是静态的,也就是说,它不应该包含可能会随时间变化的值。否则,会增加更新操作的工作量,并可能降低性能。
基于 Docker 搭建开发环境(三):链路追踪

基于 Docker 搭建开发环境(三):链路追踪

D瓜哥
基于 Docker 搭建开发环境系列: 基于 Docker 搭建开发环境(一):数据库+监控 基于 Docker 搭建开发环境(二):EFK 日志套件 基于 Docker 搭建开发环境(三):链路追踪 在上一篇文章 基于 Docker 搭建开发环境(一):数据库+监控 和 基于 Docker 搭建开发环境(二):EFK 日志套件 两篇文章中,分别介绍了“数据库+监控”和“EFK 日志套件”。这篇文章给大家分享一下如何在本地搭建起一套简单的分布式链路追踪。 在 AI 的帮助下,如同砍瓜切菜一样,非常迅速地就完成了 基于 Docker 搭建开发环境(二):EFK 日志套件 的搭建。原以为搞这个也会分分钟的问题,结果应用的追踪数据一致无法正常发送到 Jaeger 中,各种改端口号都不行。后来,无意间看了 OpenTelemetry 的配置文档,增加了一个协议配置,全部流程竟然通了,非常神奇! 站在更高的视角去看,链路追踪其实是可观测性的一部分,包括上篇文章的日志,也是可观测性的一部分。日志、追踪、度量,三者是相辅相成的。 图 1. 可观测性 在 OpenTelemetry 出现之前,日志、追踪、度量是分离的,三者各各自为战。而 OpenTelemetry 的出现,则是试图将三者统一。目前 OpenTelemetry 是云原生架构中,最炙手可热的分布式链路追踪解决方案,它提供了一套相关标准,各个厂商可以在这套标准之上进行各种各样的组件开发,大家可以根据自己的需要,选择不同的组件,进行可插拔式的安装。 图 2. OpenTelemetry 的野心 在这篇文章中,链路追踪的解决方案选择的是 OpenTelemetry + OpenTelemetry Collector + Jaeger。 OpenTelemetry OpenTelemetry 并不需要在 Docker 中启动或者配置什么。在目前的架构中,Jaeger 是作为 OpenTelemetry 的一个实现来出现的。 OpenTelemetry 需要做的就是下载一个 Java Agent,执行 docker/config/opentelemetry/download-opentelemetry-agent.sh 脚本即可下载最新版的 Java Agent。在业务应用启动时,增加如下 JVM 参数:
基于 Docker 搭建开发环境(二):EFK 日志套件

基于 Docker 搭建开发环境(二):EFK 日志套件

D瓜哥
基于 Docker 搭建开发环境系列: 基于 Docker 搭建开发环境(一):数据库+监控 基于 Docker 搭建开发环境(二):EFK 日志套件 基于 Docker 搭建开发环境(三):链路追踪 在上一篇文章 基于 Docker 搭建开发环境(一):数据库+监控 中,介绍了一下如何使用 Docker 搭建起 MySQL + NACOS + Prometheus + Grafana 集成数据库、注册中心+配置管理、监控的开发环境。这篇文章来介绍一下如何在原来的基础上接入 Elasticsearch + Fluentd + Kibana 套件,并且将 NACOS 的日志接入到 Elasticsearch 里。 Elasticsearch 由于 Elasticsearch 8+ 的版本修改了安全策略,不允许 Kibana 使用超级管理员 elastic 连接 Elasticsearch,这里选用 7.x 版本做演示。 还有一点需要提醒,在设置 Elasticsearch 的超级管理员 elastic 的账户密码时,如果密码是全部的阿拉伯数字,那么需要用双引号或者单引号括起来。 在测试中,还遇到一个磁盘过载导致的只读问题。解决方式如下: curl -X GET "localhost:9200/_cat/allocation?v&pretty" 查看磁盘使用情况 解除只读状态 $ curl -X PUT "localhost:9200/test/_settings" -H 'Content-Type: application/json' -d' { "index.blocks.read_only_allow_delete": null } '
基于 Docker 搭建开发环境(一):数据库+监控

基于 Docker 搭建开发环境(一):数据库+监控

D瓜哥
基于 Docker 搭建开发环境系列: 基于 Docker 搭建开发环境(一):数据库+监控 基于 Docker 搭建开发环境(二):EFK 日志套件 基于 Docker 搭建开发环境(三):链路追踪 去年,很多同事要换 Mac 本,所以,写了 新 Mac 安装软件脚本,方便大家一键换机。最近想玩一下 Spring Cloud 以及相关周边的部署、监控等开源解决方案。由于组件众多及为了便于迁移和共享,计划基于 Docker 及 Docker Compose 搭建一套相关的开发环境。记录一下,方便有相同需求的朋友借鉴。 最新版的 Docker 在下载镜像时,会先访问一下 Docker 的官方站点。由于国内众所周知的网络情况,访问 Docker 官方站点总失败。所以,即使配置了国内 Docker 镜像站点也会失败。只需要将 Docker 软件回滚到 4.30.0 即可。(Mac 下验证有效,其他操作系统待进一步验证。) MySQL 开发中,最常用的应该就是数据库了。所以,先来搞 MySQL 数据库。 创建如下目录结构,并添加相关相关文件: $ tree . ├── README.adoc ├── clean.sh ├── data │ └── mysql │ └── .gitkeep ├── docker │ ├── config │ │ └── mysql │ │ └── init.sql │ ├── env │ │ └── mysql.env │ └── images │ └── mysql.dockerfile └── docker-compose.yml
再谈 DDD 是银弹吗?

再谈 DDD 是银弹吗?

D瓜哥
在 DDD 是银弹吗? 中,D瓜哥分享了关于领域驱动设计的三个问题。最近在读一本书 《架构设计2.0:大型分布式系统架构方法论与实践》。(这本书还不错,推荐)这本书中,花了两个章节的篇幅,重点谈论了领域驱动设计。引用书中的观点,结合个人开发经验,再来谈一谈 DDD 是否是银弹? 软件建模的困难 首先,必须面对的一个事实是:软件建模,困难重重;尤其是对于复杂业务的建模,更是难上加难。 对于复杂业务的软件开发,其生命周期大概分为如下五个阶段: 确定业务目标和业务价值。 比如某消费信贷业务。 目标被拆解成一系列核心功能点。 比如消费信贷下的授信、交易、账务等。 围绕这些功能点定义业务流程、业务规则,以及整个过程设计什么样的业务数据或业务对象。 比如账单分期金额必须大于 100 元。 领域建模。 比如对账务系统进行建模。 基于领域模型做技术架构的设计。 比如是否要做读写分离?是否要做分库分表等? 软件建模的本质是找出现实世界中的“不变形”。但是,现实世界中,唯一不变的就是这个世界在不断变化!所以,建模的过程也是一个反复的过程。如下图: 图 1. 复杂业务软件开发的生命周期 几乎不存在稳定的领域模型 我们追求一个稳定的领域模型,但是,现实却给了我们重重一击:稳定的模型几乎不可能做到。原因如下: 意识问题。 在消费、业务及产品等关注的是业务流程。唯独开发人员要将业务流程转化成业务模型。 现实世界的复杂性。 现实业务是复杂的,建模只是抽取了一个现实业务某一时刻的业务形态。但是,业务形态会有变化的,比如取现前期不可分期,后期业务迭代可能就会运行进行分期。 迭代速度。 互联网公司要求“小步快跑,快速迭代”。这与模型的稳定其实是矛盾的。为了业务的迭代速度,只能牺牲模型的稳定性,为了赶工期,只能在模型上不断打补丁。 火候的掌握。 开发人员的设计能力无法一蹴而就。既需要思考,又需要反复练习。在快速的业务迭代和人员流动下,开发人员根本没有时间锤炼自己的设计能力。那么,对于设计火候的掌握,也就很难达到理想中的水平。 领域驱动设计的困难 书中总结了实施领域驱动设计的五个困难,D瓜哥逐一谈谈自己的看法: 领域驱动设计本身只是一套思维方法,而不是要严格执行的标准,所以其本身弹性很大。 这个问题,D瓜哥在上一篇文章中已经讨论过了。弹性太大,就有太多值得商榷的地方,也许初次开发,还可以按照某个人的想法一以贯之。但是,随着参与维护的人员增多,每个人都会不由自主地会带入个人的一些想法,各种想法的碰撞,必然就会引入代码结构的混乱。 思维方式的转换很难。 绝大多数面向业务的开发人员,尤其是 Java 开发人员,对三层架构已经有根深蒂固的认识。思维方式已经被打上深深的烙印,想要改变,坦白讲,极其困难。尤其是,没有一个统一的标准和广泛认可的实现范例,完全靠摸着石头过河,必然会“一千个读者,就有一千个哈姆雷特。” 领域驱动设计的实施需要强大的技术基础实施来保证。 D瓜哥私以为这个倒不是什么问题。针对技术问题,尤其是一些共性问题,都有成熟的解决方案。只要能合理搭积木,就可以解决相应的问题。 大量存量的老系统,重构成本大于收益,没有重构动力。 编程第一准则:代码能跑就不要动。重构引入的问题谁来解决?重构带来的事故谁来负责?这个时候必须祭出这张图了: 图 2. 代码能跑就不要动 当然,私以为不是程序员反感重构代码,更多是因为下面这个因素。 在互联网的快速开发迭代面前,很少有人可以静下心来在软件方法论层面去精雕细琢,更多的是快速堆砌功能,完成业务需求开发。 业务的快速迭代,导致根本没有时间让开发人员去优化代码。可口的饭菜需要恰当的火候和足够的时间,优雅的软件建模也需要恰当的火候和足够的时间。精心地软件建模需要三个月,业务让你一个月上线,而且还是加班加点才能干完。结合实际来看,绝大多数情况都会想业务妥协吧?! 领域驱动设计的出路 书中的观点是做个折中:在宏观层面,遵循领域驱动设计的方法论;在微观层面,不严格遵循领域驱动设计的方法论。 D瓜哥是这样理解的:可以利用领域驱动设计里面的限界上下文的思想,把领域做个分割,划分成业务更聚合的子域。在子域内部,提炼出统一语言,来规范业务、产品和开发沟通的业务术语。在子域交互的接口层面,进行精心设计,精雕细琢。至于子域及接口的内部实现,就交给开发团队自己决策,只要满足对应的技术指标(比如每秒要支撑多大的访问量)即可。 在部门内部讨论时,D瓜哥还给出了一个更具操作性和落地性的方案:现实面临的问题是代码冗余,技术欠债,不容易维护。先放下关于领域驱动设计的无谓讨论,利用每一次开发的机会,把冗余代码删除,把代码重构和优化,一步一步地精炼代码,即使不谈领域驱动设计,相信在逐步重构和优化下,技术欠债会逐渐弥补,可维护性也会逐步提高。
DDD 是银弹吗?

DDD 是银弹吗?

D瓜哥
史前时期最骇人的景象,莫过于一群巨兽在焦油坑里做垂死前的挣扎。不妨闭上眼睛想像一下,你看到了一群恐龙、长毛象、剑齿虎正在奋力挣脱焦油的束缚,但越挣扎,焦油就缠得越紧,就算他再强壮、再厉害,最后,都难逃灭顶的命运。过去十年间,大型系统的软件开发工作就像是掉进了焦油坑里…… — 佛瑞德·布鲁克斯(Frederick P. Brooks) 《人月神话》 应该早在 2019 年,在 左耳朵耗子哥 的推荐下阅读了 《领域驱动设计》,并将读书摘要整理成几篇文章: 《领域驱动设计》读书笔记(一):运用领域模型 《领域驱动设计》读书笔记(二):模型驱动设计的构造块 《领域驱动设计》读书笔记(三):通过重构来加深理解 《领域驱动设计》读书笔记(四):战略设计 部门要搞 DDD 和体系化建设,正好有一个核心项目要做重构,领导让实践一下领域驱动设计,苦于没有范例可以参考,感觉无处下手,所以又读了 《中台架构与实现·基于DDD和微服务》(最早读的是极客时间专栏,后专栏编撰成该书)。 后来,又陆陆续续看了好多领域驱动设计的相关文章。对于领域驱动设计,即了解过,也实践过。所以,结合自身的经历和体会,谈一谈我的感受。不吹不黑,重点谈三个问题。 1. 如何快速上手? 上面介绍了一下D瓜哥的个人经历,是付出了一点的时间和精力的,由此引出了第一个问题:如何快速上手?对于一个工作多年,经验丰富,也算勤奋好学的高级码农,上手还如此困难重重,那么对于一个刚刚参加工作的职场新人,上手是否会更加困难?又该如何克服这个困难? 任何一家公司,尤其是大型技术公司,都是由初中高级工程师组成的,而且成员人数也是由多到少,参与实际开发工作,大概率也会由多到少,初级开发工程师干了大量的实际编码工作。如果无法吸引大多数的初级工程师参与进来,只有个别的高级工程师去落地,那么,所谓的领域驱动设计,只能成为空中楼阁,海市蜃楼。华而不实,无法落地。 但是,由于经验少,这对于初级工程师来说,也许是一个优势。毕竟,一张白纸,可以画出各种美丽的画卷。中高级工程师已经习惯于传统的开发模式,思维已经定格。但是,初级工程师,反倒是嗷嗷待哺,更容易塑性。可惜的是,现在没有好的示例可以学习。 2. 哪里有可以参考的示例? 快速上手的最好办法,就是给一个完整的示例,拿来直接抄作业。对于入门的程序员,学东西上手最快的办法就是抄代码。把示例代码,拿过来改吧改吧就能跑起来,无形中就学会怎么写代码了。对于传统的三层架构,有太多的示例可以来学习了,比如 SpringSide。 从 《Domain-Driven Design》 这本书在 2003 年出版到现在,已经有 21 年了。到现在为止,也没有见到一个开源的、能运行起来的基于领域驱动设计的项目。也可能是鄙人孤陋寡闻,坐井观天,没有发现。如果谁发现了,欢迎向我反馈。 作为对比,我们来看一下 Spring 的发展过程。Spring 的思想最早是在 《J2EE Development without EJB》 这本书里出现的,这本书是在 2004 年 6 月出版的。这本书出版后,开源社区根据这本书里面的思想及代码片段,开发出了 Spring 框架。在两年后,Spring 之父 Rod Johnson 接着出版了 《Professional Java Development with the Spring Framework》,系统介绍了一下 Spring 框架的各种使用案例。到 2008 年我上大学的时候,在国内的培训行业,已经开始重点讲解 Spring 了。 其实,D瓜哥想拿传统的三层架构的发展来做对比,可惜没有找到更确切的时间线。 期待一个完整的、基于领域驱动设计的、能正常运行起来的开源项目尽早出现!
关于高中求学的一些问答及提醒

关于高中求学的一些问答及提醒

D瓜哥
家里一个亲戚今年参加中招考高中,由于成绩不是很理想,所以,就面临一个问题:选择哪所高中去求学?由此引发的一系列思考和讨论,D瓜哥觉得非常有共性,分享出来,希望给需要的家长一个参考。 1. 去重点高中怕跟不上,选择去上私立高中 一些家长可能会有这样的想法:孩子中考成绩不理想,如果去重点高中,担心孩子跟不上课程,所以,选择去上私立高中。 关于这个问题,是一个伪命题。高中最重要的考核就是三年以后的高考。高考对所有参加的考生都是一视同仁的,不会因为私立高中和公立高中而有什么差别。(同一个省的高考生是一样的,跨省则不一定。这里不予讨论。)所以,只要上高中,就必须努力跟上,尽力向前冲!否则,就会掉队,考不上大学,考不上大学,就失去了上高中的主要意义。所以,根本无需考虑能不能跟上的问题。这个问题只有一个选择:只要求学,就只能加油往前冲! 2. 选择高中的关注点 由于孩子成绩不理想,那么可能无法进入理想的中学。接下来的一个问题就是:如何选择高中? 对于这个问题,私以为对于高中的的考察标准只有一条:就是高考录取率,各个层次本科的录取率。但是在选择高中时,有一些值得关注的点,下面一一说明。 2.1. 生源质量 聪明的学生在任何高中都有好的成绩。脑瓜子不灵的学生,即使送到人大附中这样全国最好的高中也难有好的成绩。 另外,如果身边有一些成绩好的同学,那么当自己学习有问题时,可以更方便地找同学帮忙解答。如果身边事一群瓜娃子,出现学习问题,也无法及时解决,日积月累,成绩自然难以提高! 2.2. 学校的历史成绩 成绩好的学校大概率会一如既往地好下去。而差的学校想变好,却需要付出非常巨大的努力和相当长的时间来改善。它还需要时间,逐步向社会来证实它的实力,以求获取更好的生源。对于学校来说,这个时间是可以耗得起的。但是,作为学生,上学的时间段时是卡死的,耗不起,也等不起。 2.3. 老师资历 好的老师有更好的教学方法,对学生学习更有帮助。 但是,好的师资也需要好的学生来衬托。老师和学生是相互成就的。只有伯乐,没有千里马,伯乐只能悲叹“英雄无用武之地”! 2.4. 学习氛围 大多数人都从众。所以,学习氛围好的地方,大部分人会被带动起来学习。但是,如果学习氛围一般,大多数人就会随波逐流,逐步落伍。 2.5. 私立高中的困境 目前,国内大多数人更愿意相信公立高中。认为公立高中有政府托底,更有保障。而对私立高中,大多数人缺乏足够的信任。 当然,还有一个原因是私立高中普遍学费高昂,这对于很多家长来说,也是一个不小的负担。 2.6. 小结 所以,综合上述情况,导致的结果是,大多数情况下私立高中的生源质量普遍一般,甚至不好。由于生源质量问题,导致无论是学校的历史成绩,还是学校氛围,可能都会差强人意。所以,如果家长希望通过上私立高中来提高孩子成绩。综合来看,个人觉得很难实现,甚至基本不可能(可能比买彩票中大奖的概率要高一点)。最后的结果,可能钱也花了,时间也耽误了,孩子也没有太大的起色,最后高考成绩也不理想。 还有一个种情况,从小就一直上私立学校的情况,这种大多数是双语教学,面向的也是国外的大学,大部分是不把高考作为第一选项的。这种情况,不在此讨论范围。 3. 转学 如果一个学校不行,在条件允许的情况下,尽快转学,转到更好的学校。这个时候,由于入学晚的原因,可能不容易合群,家长要多鼓励和开导,提供足够的情绪价值,帮助孩子早日完成过渡。 另外,学生也不要太在意,一般情况下,等到上高二会进行二次分班,大家又都从新开始了。 4. 培优班 如果一个学生没有考进更好的中学,去了一所一般的高中,而且还进培优班了。这里有三点需要注意: 如果不是托关系进培优班,那么只能说明这个高中生源质量确实一般。 成绩一般的学生在培优班里,有可能每次考试都是班里垫底。这就要多去关注一下学生在整个高中的整体成绩排名。好的情况是,在班级垫底,但在年级总体排名靠前,这种情况家长要多鼓励学生,培养学生有一颗强大的心脏。 另外一种情况是,由于可能长时间在班级成绩排名垫底,这对学生来说,无形中会带来很大的压力,导致有些学生可能会自暴自弃。所以,家长要做好安慰和支持,多发现学生的优点和长处,多鼓励孩子。 5. 相比私立高中的更优解 如果有能力支付私立高中的钱,相对来说,另外一条路可操作性更大一些:尽力去层次更好的公立高中,把省下来的学费给孩子请一对一的私教辅导。 6. 私教辅导 学生有各种各样的性格,老师也有跟种各样的教法,所以,孔子提出要“因材施教”。如果学生和私教老师不是很契合,那么请私教老师不一定就能提高成绩。如果已经请私教的情况下,家长一定要多关注学生的反馈,了解学生的学习情况,判断是否合拍,如果不合适,要尽早更换私教老师。 7. 高中成绩可以突飞猛进 无需太过担心孩子的高中入学成绩排名。以D瓜哥的上学经历来看,在高一,学生的成绩排名会有剧烈的波动,有人入学成绩很差,后来迎头赶上的;也有人入学成绩很好,但后来却跌落谷底。所以,只要学生初中不掉队,上了高中肯下功夫学习,成绩就会逐步提高。(掉队的学生可能就不会想着去上高中了) 8. 不要选择职高或“3+2”大专 还有一个选项:选择职高或者是“3+2”的大专。私以为,这个选项可以直接忽略,除非迫不得已。 大多数成绩还可以的学生都去上高中了,所以,能选择去上职高或者大专的,大部分成绩都一般,甚至很差。结果,大部分人可能就会不学无术,聚众打架斗殴。最后,孩子不仅可能没学好,甚至沾染了一堆坏毛病。 另外,现在学历贬值严重,满大街都是本科生,大专生更没出路(可以看看现在公务员招聘都要求什么学历)。上了大专,如果想有出路,还要考专升本,相当于一次高考,那为何不直接上高中呢? 当然,在职高或者大专里面,也不乏一些学有所成的人才,但这样的概率太低了。这个问题,不再争论,争论就是你对。 总结 综合上述的讨论,对于孩子上学,最优解就是上尽可能好的高中。如果上不了最好的高中,那就选次一点的公立高中。如果家庭条件允许,可以给孩子请一些私教辅导,来帮助孩子提高成绩。 最后,送给正在求学的学子们一句话:你充满了潜能,但你的努力还远远不够!祝福每一个学子学有所成!
单调栈实践(二):应用

单调栈实践(二):应用

D瓜哥
在 单调栈实践(一):入门 中对单调栈做了一个初步介绍,同时使用一个类似单调栈的题目做了入门的尝试。在本文中,将分析正式单调栈的使用案例。 实践: LeetCode 503. 下一个更大元素 II 单调栈主要就是为了解决选择下一个更大或者更小元素的相关问题。来看一下 LeetCode 503. 下一个更大元素 II。 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的下一个更大元素。 数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。 如果熟悉单调栈,这道题的解法就一目了然:将数组从后向前遍历,如果单调栈栈顶元素比当前元素小,就将栈顶元素弹出;重复上述操作,直到栈顶元素大于当前元素,或者栈为空。如果栈不为空,则栈顶元素就是当前元素的后继更大元素。代码如下: /** * LeetCode 503. 下一个更大元素 II * * @author D瓜哥 · https://www.diguage.com * @since 2024-07-05 23:08:39 */ public int[] nextGreaterElements(int[] nums) { if (nums == null || nums.length == 0) { return nums; } int[] result = new int[nums.length]; Deque<Integer> stack = new LinkedList<>(); // 只需要将数组“拼接”,遍历两遍数组,就可以解决所有元素后继更大元素的问题 // 从后向前遍历,再加上单调递增栈,就是时间复杂度为 O(n) 的解决方案 for (int i = 2 * nums.length - 1; i >= 0; i--) { // 取余即可获取当前需要处理的元素 int index = i % nums.length; // 在单调栈不为空的情况下,将栈中小于等于当前元素的值都弹出 while (!stack.isEmpty() && stack.peek() <= nums[index]) { stack.pop(); } // 剩下元素既是比当前元素大的后继元素。为空则是没有更大元素 // 这里还有一个隐含变量: // 由于栈是从后向前添加,则栈顶元素距离当前元素更近。 // 如果栈不为空,则栈顶元素就是符合条件的元素。 result[index] = stack.isEmpty() ? -1 : stack.peek(); stack.push(nums[index]); } return result; } 使用单调栈,一个关键点是确定使用的是单调递增栈,还是单调递减栈。 这里给大家留一个思考题:本文提供的答案是从后向前遍历数组。尝试一下从前向后遍历数组的解决方案。 实践: LeetCode 42. 接雨水 下面再来看一下: LeetCode 42. 接雨水。 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。