2025-05-12 22:40:45
在macOS中,若因VPN或其他软件导致默认nameserver
(DNS服务器)地址被强制修改,可通过以下方法手动强制替换DNS服务器地址,确保域名解析正常:
打开网络设置
点击左上角苹果图标 > 系统偏好设置 > 网络。
选择当前活跃的网络接口(如Wi-Fi、Ethernet或VPN虚拟接口)。
修改DNS服务器
点击右下角 高级 > 切换到 DNS 标签页。
在 DNS服务器 列表左侧,点击 + 添加新的DNS地址(如8.8.8.8
、114.114.114.114
)。
拖动新添加的DNS地址到列表顶部,确保优先级最高。
点击 OK > 应用 保存配置。
清除DNS缓存
终端执行:
killall -HUP mDNSResponder
若VPN或软件锁定了图形化设置,可直接通过终端覆盖DNS配置:
执行命令获取活跃接口名(如Wi-Fi
、Ethernet
或VPN连接名
):
networksetup -listallnetworkservices
替换[接口名]
为实际名称(如Wi-Fi
),并指定DNS地址(以8.8.8.8
和1.1.1.1
为例):
networksetup -setdnsservers "[接口名]" 8.8.8.8 1.1.1.1
示例:
networksetup -setdnsservers "Wi-Fi" 8.8.8.8 1.1.1.1
# 查看当前DNS服务器 networksetup -getdnsservers "[接口名]" # 测试域名解析 dig example.com nslookup example.com
killall -HUP mDNSResponder # 刷新缓存 dscacheutil -flushcache # 辅助清理
若DNS被VPN虚拟接口(如utun0
)强制覆盖,需直接修改VPN接口的DNS设置:
# 查找VPN虚拟接口名(通常为utun0、utun1等) ifconfig | grep utun # 手动设置DNS(以utun0为例) sudo networksetup -setdnsservers "utun0" 8.8.8.8 1.1.1.1
在aTrust VPN客户端设置中,取消勾选 使用VPN的DNS服务器 或类似选项。
若客户端无此选项,需联系VPN管理员调整策略。
若上述方法无效,可手动修改/etc/resolv.conf
(需关闭SIP保护):
临时禁用SIP(需重启)
重启Mac,按住 Command + R
进入恢复模式。
打开终端执行:
csrutil disable reboot
修改DNS配置文件
编辑/etc/resolv.conf
(文件可能为只读链接,需先删除后重建):
sudo rm /etc/resolv.conf sudo tee /etc/resolv.conf <<EOF nameserver 8.8.8.8 nameserver 1.1.1.1 EOF
重新启用SIP
再次进入恢复模式执行:
csrutil enable reboot
检查当前使用的DNS服务器
scutil --dns | grep "nameserver
测试域名解析延迟
time dig example.co
捕获DNS请求流量
tcpdump -i en0 port 53 -vvn # 替换en0为实际接口
优先级问题
macOS默认遵循以下优先级:
手动设置DNS > VPN接口DNS > 系统默认DNS。若VPN强制锁定DNS,需联系管理员调整策略。
持久性配置
通过networksetup
修改的DNS在重启后仍有效,但某些VPN重连后可能覆盖配置,需结合脚本或自动化工具固化设置。
防火墙与代理干扰
确保本地防火墙(如Little Snitch)或代理工具未拦截DNS请求(默认端口UDP 53
)。
通过上述方法,可强制替换macOS的nameserver地址,解决因DNS配置异常导致的域名解析问题。
2025-05-12 05:32:06
在使用lvm前先了解下 LVM介绍及架构,直接开撸。
LVM卷使用
假设有一块1T的盘(/dev/sdb),创建三个分区,使用LVM配置逻辑卷并管理,常见操作步骤如下:
1. 使用fdisk创建LVM类型的分区 → 2. 创建物理卷 → 3. 创建卷组 → 4. 创建逻辑卷 → 5. 格式化并挂载逻辑卷 → 6. 更新fstab
使用fdisk创建分区:fdisk /dev/sdb
按 n
创建新分区,选择主分区 (p
),分区号1,起始扇区默认,结束扇区设置为 +300G
。
按 t
更改分区类型,选择 8e
(Linux LVM)。
重复上述步骤创建分区2和3,分配剩余空间(确保类型均为8e)。
按 w
保存并退出。
LVM配置逻辑卷
1. 创建物理卷(PV): pvcreate /dev/sdb1 /dev/sdb2 /dev/sdb3 2. 创建卷组(VG): vgcreate vg_sealer /dev/sdb1 /dev/sdb2 /dev/sdb3 3. 创建逻辑卷(LV): lvcreate -n lv_sealer -L 300G vg_sealer
格式化并挂载逻辑卷
1. 格式化逻辑卷:根据需求选择 ext4、xfs 或其他类型,格式化命令需匹配 mkfs.ext4 /dev/vg_sealer/lv_sealer 2. 创建挂载目录: mkdir -p /var/lib/sealer 3. 获取逻辑卷的UUID: blkid /dev/vg_sealer/lv_sealer 4. 编辑/etc/fstab文件: vim /etc/fstab 添加以下行, # 设备标识(建议使用UUID,避免设备名变化导致问题),第1个0为dump 备份标志(0=不备份,1=备份),第2个0为 fsck 检查顺序(0=不检查,根分区设为1,其他数据分区可设为0或2) UUID=你的UUID /var/lib/sealer ext4 defaults 0 0 或者直接挂LVM逻辑卷 /dev/vg_sealer/lv_sealer /var/lib/sealer ext4 defaults 0 0 5. 挂载逻辑卷: mount -a
实际挂载的是LVM逻辑卷(如/dev/vg_sealer/lv_sealer
),而非直接挂载/dev/sdb1
。LVM允许更灵活的存储管理,建议通过逻辑卷进行操作。
LVM逻辑卷扩容
现在300G的卷不够用了,需要将逻辑卷 lv_sealer
从 300G 扩展到 400G,操作步骤如下:
1. 检察卷组(VG)的剩余空间 → 2. 扩容逻辑卷(LV)大小 → 3. 扩展文件系统 → 4. 验证扩展结果
1. 首先确认卷组 vg_sealer 是否有足够的剩余空间: vgdisplay vg_sealer # 查看 Free PE / Size 字段,确保剩余空间 ≥ 100G(若不足需先扩展卷组) Free PE / Size 25599 / 700G # 表示剩余 100G 空间 2. 扩展逻辑卷(LV)大小:将逻辑卷从 300G 扩展到 400G(新增 100G) lvextend -L +100G /dev/vg_sealer/lv_sealer lvextend -L 400G /dev/vg_sealer/lv_sealer # 或直接指定目标大小:-L 400G # 此命令会将卷组中 所有剩余空间 添加到 lv_sealer。 lvextend -l +100%FREE /dev/vg_sealer/lv_sealer # 将剩余空间全部分配给逻辑卷(LV) 3. 扩展文件系统:调整文件系统以使用新增的空间(假设文件系统为 ext4) resize2fs /dev/vg_sealer/lv_sealer #(如果是 xfs 文件系统,用 xfs_growfs /var/lib/sealer) 4. 验证扩展结果:确认逻辑卷和文件系统的新大小 lvdisplay /dev/vg_sealer/lv_sealer # 检查 LV 大小 df -h /var/lib/sealer # 检查文件系统大小
完成后,逻辑卷和文件系统将扩容至 400G, /var/lib/sealer
的挂载点会自动使用新空间。且 ext4
/xfs
支持在线调整(ext4支持在线扩缩容、xfs只支持扩容,不支持缩容),无需卸载文件系统。操作前建议备份重要数据(虽然风险极低)。
创建逻辑卷并占用全部剩余空间
现在突然有个需求,需要创建一个etcd的逻辑卷,并把卷组剩余的空间都分给它使用,此时可以使用 lvcreate
命令,通过 -l 100%FREE
参数直接分配所有剩余空间:
lvcreate -n lv_etcd -l 100%FREE vg_sealer
参数解释:
-n lv_etcd
:指定逻辑卷名称为 lv_etcd
。
-l 100%FREE
:占用卷组中 全部剩余空间。
vg_sealer
:目标卷组名称(根据实际情况替换)。
[zkqw]
LVM扩展现有的卷组空间
由于创建了一个新的逻辑卷lv_etcd,占用了卷组的所有剩余空间。现在需要将已有的PV添加盘扩容,操作步骤如下:
1. 添加新磁盘或扩展现有磁盘的分区 → 2. 创建或调整物理卷 → 3. 将新的物理卷添加到卷组 → 4. 扩展逻辑卷并使用新增的空间 → 5. 调整文件系统大小
情况一:已有物理卷(如 /dev/sdb1
)所在的磁盘空间被扩大(例如虚拟机磁盘扩容),需要扩展物理卷。
情况二:新增一块磁盘(如 /dev/sdc
),需将其初始化为物理卷并添加到卷组中。
查看卷组、物理卷、逻辑卷的当前状态:
pvs # 查看物理卷信息,显示物理卷(PV)信息(所属 VG、容量等) vgs # 查看卷组剩余空间,显示卷组(VG)的总容量、剩余空间 lvs # 查看逻辑卷信息,显示逻辑卷(LV)名称、大小、所属 VG lsblk # 查看磁盘、分区、LVM 设备的树状层级关系 # 查看卷组(VG)包含的物理卷(PV) pvs --segments -o+pv_name,vg_name # 列出所有PV及其所属VG # 针对特定卷组(例如 vg_sealer): pvdisplay -S vgname=vg_sealer # 显示该VG下的所有PV详细信息 # 查看卷组(VG)的详细空间分配 vgdisplay vg_sealer # 替换为实际VG名称
快速查看 LVM 逻辑卷(LV)、卷组(VG)、物理卷(PV)及底层磁盘的层级关系,可以通过组合命令一步实现。
echo "===== Physical Volumes (PVs) =====" && pvs && \ echo "\n===== Volume Groups (VGs) =====" && vgs && \ echo "\n===== Logical Volumes (LVs) =====" && lvs && \ echo "\n===== Block Devices Hierarchy =====" && mount -a && lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
输出示例:
===== Physical Volumes (PVs) ===== PV VG Fmt Attr PSize PFree /dev/sda2 vg_root lvm2 a-- <99.00g 0 /dev/sdb1 vg_data lvm2 a-- 500.00g 200.00g /dev/sdc1 vg_data lvm2 a-- 500.00g 500.00g ===== Volume Groups (VGs) ===== VG #PV #LV #SN Attr VSize VFree vg_root 1 2 0 wz--n- <99.00g 0 vg_data 2 1 0 wz--n- 1000.00g 700.00g ===== Logical Volumes (LVs) ===== LV VG Attr LSize Pool Origin Data% Meta% root vg_root -wi-ao---- <95.00g swap vg_root -wi-ao---- 4.00g lv_data vg_data -wi-ao---- 300.00g ===== Block Devices Hierarchy ===== NAME SIZE TYPE FSTYPE MOUNTPOINT sda 100G disk ├─sda1 1G part vfat /boot/efi └─sda2 99G part LVM2_member ├─vg_root-root 95G lvm ext4 / └─vg_root-swap 4G lvm swap [SWAP] sdb 500G disk └─sdb1 500G part LVM2_member └─vg_data-lv_data 300G lvm xfs /data sdc 500G disk └─sdc1 500G part LVM2_member
物理卷(PV):
/dev/sdb1
和 /dev/sdc1
属于卷组 vg_data
,总容量 1000G,剩余 700G。
/dev/sda2
属于 vg_root
,已完全分配。
卷组(VG):
vg_data
包含 2 个 PV(sdb1
和 sdc1
),总空间 1000G。
vg_root
用于系统和交换分区。
逻辑卷(LV):
lv_data
大小 300G,挂载到 /data
,使用 xfs
文件系统。
vg_root
中的 root
和 swap
逻辑卷分别挂载到 /
和作为交换分区。
磁盘层级(lsblk):
sdb1
和 sdc1
是 LVM 物理卷(LVM2_member
)。
逻辑卷路径为 /dev/mapper/vg_data-lv_data
(对应 dm
设备)。
情况一:扩展现有物理卷(如磁盘分区已扩容)
假设原有物理卷 /dev/sdb1
所在的磁盘已从 300G 扩容到 500G,需调整物理卷大小。
使用 fdisk
或 parted
调整分区大小(需删除并重建分区,注意备份数据)。
或者使用在线工具如 growpart
(适用于无需重建分区):
growpart /dev/sdb 1 # 调整 /dev/sdb 的第1个分区
pvresize /dev/sdb1
pvdisplay /dev/sdb1 # 查看物理卷新容量
lvextend -l +100%FREE /dev/vg_sealer/lv_sealer # 占用全部剩余空间 resize2fs /dev/vg_sealer/lv_sealer # 调整文件系统(ext4) # 若为xfs文件系统:xfs_growfs /var/lib/sealer
情况二:添加新磁盘到卷组
假设新增磁盘 /dev/sdc
,需将其初始化为物理卷并加入卷组。
若需分区(推荐使用完整磁盘):
fdisk /dev/sdc
按 n
创建新分区,设置类型为 8e
(Linux LVM),保存退出。
# 使用整块磁盘 pvcreate /dev/sdc # 或指定分区(如 /dev/sdc1) pvcreate /dev/sdc1
# 将新物理卷添加到卷组 vgextend vg_sealer /dev/sdc
lvextend -l +100%FREE /dev/vg_sealer/lv_sealer # 分配全部剩余空间 resize2fs /dev/vg_sealer/lv_sealer # 调整文件系统(ext4) # 若为xfs文件系统:xfs_growfs /var/lib/sealer
验证结果
# 查看卷组扩容后的总空间 vgdisplay vg_sealer # 检查逻辑卷大小 lvdisplay /dev/vg_sealer/lv_sealer # 确认文件系统已扩容 df -h /var/lib/sealer
注意事项
数据备份:操作前备份重要数据,尤其是调整分区时。
分区对齐:使用 parted
或 fdisk
时注意分区对齐,避免性能问题。
在线扩容:ext4
和 xfs
文件系统支持在线调整,无需卸载。
虚拟机环境:若为虚拟机磁盘扩容,需先扩展虚拟磁盘,再在操作系统中操作。
LVM(PV/VG/LV)缩容
对LVM(PV/VG/LV)进行缩容是一项高风险操作,需谨慎执行。以下是分步指南及注意事项:
场景一:缩小逻辑卷(LV)
1. 卸载文件系统(可选但推荐) umount /var/lib/sealer # 替换为实际挂载点 2. 检查文件系统完整性 e2fsck -f /dev/vg_sealer/lv_sealer # ext4专用 3. 缩小文件系统(以ext4为例) resize2fs /dev/vg_sealer/lv_sealer 300G # 目标大小(如300G) 4. 缩小逻辑卷(LV) lvreduce -L 300G /dev/vg_sealer/lv_sealer # 与文件系统大小一致 5. 重新挂载文件系统 mount /dev/vg_sealer/lv_sealer /var/lib/sealer
场景二:从卷组(VG)中移除物理卷(PV)
1. 迁移数据到其他PV pvmove /dev/sdb1 # 将数据从/dev/sdb1迁移到其他PV 2. 从卷组中移除PV vgreduce vg_sealer /dev/sdb1 3. 删除PV pvremove /dev/sdb1
场景三:缩小物理卷(PV)
1. 缩小PV(需先缩小所属VG/LV) pvresize --setphysicalvolumesize 200G /dev/sdb1 # 调整PV大小 2. 调整分区大小(使用parted或fdisk) parted /dev/sdb resizepart 1 200G # 调整分区大小
验证操作
lvdisplay /dev/vg_sealer/lv_sealer # 检查LV大小 vgdisplay vg_sealer # 检查VG剩余空间 pvdisplay /dev/sdb1 # 检查PV大小 df -h /var/lib/sealer # 检查文件系统大小
注意事项
xfs文件系统不可缩容:若使用xfs,只能备份数据→删除LV→重建更小的LV→恢复数据。
顺序不可逆:必须先缩小文件系统,再缩小LV,否则数据丢失。
虚拟机/物理机差异:物理机需确保硬件支持磁盘缩容(如RAID/LVM配置)。
数据丢失:操作失误可能导致数据不可恢复。
性能影响:频繁调整可能导致文件系统碎片化。
依赖工具:
resize2fs
:ext2/3/4文件系统调整工具。
parted
:替代fdisk的更友好分区工具。
[/zkqw]
2025-05-09 17:45:52
踩了个研发建表没有设置主键的坑,mark一下。数据库实例是 tdsql mysql 5.7,服务建表的时候直接报错:ERROR 1173 (42000):This table type requires a primary key,最后乖乖加上主键解决。
tdsql中设置建表必须需要显式主键的参数为 reject_table_no_pk
至于为什么建表必须创建主键应该是主要有两个原因,一个是mysql规范,一个是怕影响性能埋坑。
TDSQL 内核使用 row 格式的 binlog 复制。根据目前 MariaDB/MySQL 的实现方式,如果一个 update/delete 语句更新或者删除了很多行,那么到了备机上面,更新或者删除每个行时候,需要使用索引扫描或者全表扫描来找到这个行,导致备机复制变得非常慢,这是非常严重的问题。 在 TDSQL 的告警平台上面就有用户出现过主备延迟因此变得非常大的告警。为了避免这些致命问题的出现,所以才有“自动增加主键”和“禁止 create table/alter table 语句产生无主键的表”
1.通过 ALTER TABLE 语句为表添加主键 ALTER TABLE 表名 ADD PRIMARY KEY (列名); 2.或者修改建表语句,添加主键 CREATE TABLE IF NOT EXISTS `zone_xxx_job` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `dispatch_job_id` bigint(20) NULL, PRIMARY KEY (`id`) ) ENGINE = InnoDB CHARSET = utf8mb4; 3.验证主键是否生效 SHOW CREATE TABLE 表名;
注意事项:
列要求:主键列必须满足以下条件:
值唯一且非空。
数据类型适合作为索引(推荐整数类型如 INT
、BIGINT
)。
数据冲突:若表中已有数据,需确保主键列无重复值,否则会报错 Duplicate entry
。
2025-05-06 09:39:45
sql_mode
是 MySQL 中一个关键的系统变量,用于控制 SQL 语法解析、数据校验和存储行为的严格程度。合理配置 sql_mode
可以确保数据一致性、兼容性和安全性。以下是详细的配置说明及操作指南:
sql_mode
的核心作用语法校验:控制 SQL 语句的语法规则(如是否允许省略 GROUP BY
中的非聚合字段)。
数据校验:严格检查数据的合法性(如日期格式、除零操作)。
兼容性:调整 MySQL 行为以兼容其他数据库(如 Oracle 或 SQL Server)。
安全性与性能:通过严格模式避免脏数据写入,提升数据质量。
sql_mode
模式模式名称 | 说明 |
---|---|
STRICT_ALL_TABLES |
对所有表的写入操作启用严格模式,非法数据会触发错误。 |
STRICT_TRANS_TABLES |
对事务型存储引擎(如 InnoDB)启用严格模式,非事务引擎可能宽松处理。 |
ONLY_FULL_GROUP_BY |
要求 GROUP BY 子句包含所有非聚合字段,避免查询结果不确定性。 |
NO_ZERO_IN_DATE |
禁止日期中的月份或日为 0 (如 '2023-00-01' )。 |
NO_ZERO_DATE |
禁止插入 '0000-00-00' 这样的零日期。 |
ERROR_FOR_DIVISION_BY_ZERO |
除零操作触发错误(否则返回 NULL 并警告)。 |
NO_AUTO_CREATE_USER |
禁止 GRANT 语句自动创建用户(需先显式创建用户)。 |
NO_ENGINE_SUBSTITUTION |
阻止存储引擎自动替换(如表指定引擎不可用时直接报错)。 |
ANSI |
启用 ANSI SQL 兼容模式,包含多种严格规则。 |
TRADITIONAL |
启用传统严格模式(类似 STRICT_TRANS_TABLES + 其他严格规则)。 |
sql_mode
sql_mode
SHOW VARIABLES LIKE 'sql_mode';
示例输出:
sql_mode = ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
-- 设置当前会话的 sql_mode SET SESSION sql_mode = '模式1,模式2,...'; -- 示例:启用严格模式和 ONLY_FULL_GROUP_BY SET SESSION sql_mode = 'STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY';
1.编辑 MySQL 配置文件(如 my.cnf
或 my.ini
):
[mysqld] sql_mode = "STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
2.重启 MySQL 服务:
systemctl restart mysql # Linux # 或通过服务管理器重启 Windows 上的 MySQL 服务
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
作用:阻止非法数据写入,确保数据合法性。
sql_mode = ""
作用:禁用所有严格模式,允许宽松的数据处理(需谨慎使用)。
sql_mode = "ANSI"
作用:启用 ANSI 标准兼容模式,适用于跨数据库迁移场景。
版本差异:
MySQL 5.7:默认包含 ONLY_FULL_GROUP_BY
、STRICT_TRANS_TABLES
等模式。
MySQL 8.0:默认启用更严格的模式,且弃用 NO_AUTO_CREATE_USER
。
严格模式的影响:
写入失败:非法数据(如字符串插入整数字段)会直接报错,而非截断或警告。
业务兼容性:确保应用程序能正确处理严格模式触发的错误。
配置回滚:
修改 sql_mode
前备份配置文件。
测试环境验证后再应用到生产环境。
动态修改限制:
部分模式(如 NO_AUTO_CREATE_USER
)需重启 MySQL 才能生效。
GROUP BY
查询报错报错信息:Expression #1 of SELECT list is not in GROUP BY clause
原因:启用了 ONLY_FULL_GROUP_BY
模式。
解决:
修改 sql_mode
移除 ONLY_FULL_GROUP_BY
。
或调整 SQL 语句,确保 GROUP BY
包含所有非聚合字段。
0000-00-00
插入失败报错信息:Incorrect date value: '0000-00-00'
原因:启用了 NO_ZERO_DATE
模式。
解决:
移除 NO_ZERO_DATE
和 NO_ZERO_IN_DATE
。
或修改应用程序,避免插入零日期。
NULL
而非报错原因:未启用 ERROR_FOR_DIVISION_BY_ZERO
或严格模式。
解决:
SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
2025-05-03 14:36:20
首先,我们要知道,为什么会有枯燥的知识?一般来说,枯燥的东西通常是你不感兴趣的东西,而你不感兴趣的东西,可能是你并不知道有什么用的东西。这样的知识通常是比较底层或是抽象度比较高的知识,比如:线性代数,或者一些操作系统内部的原理……越理论的东西就越让人觉得枯燥。
我还记得,当初上大学学习《计算机网络》时,直接学习那个七层协议,以及那些报文,让我感觉枯燥得不行。那个时候,完全不知道这些东西有什么用,因为我连网络是什么都没有见过。直到有一天,我在老师的公司里看到了网卡、网线和 Hub,然后了解了 Windows NT 的域和 IP 地址,然后用 Power Builder 连上了 SQL Server,用 SQL 写入并读取了数据,我才真正明白网络原来有这么好玩。
我开始学习《TCP/IP 详解》,又感到一阵枯燥。然后,有一个同事给我递来了《Unix 网络编程》,我照着其中的例子,写了一个聊天服务器,前端用 Delphi 写了一个 QQ 的样子,那种兴奋劲就别提了。再后来,因为要处理网络问题,调优网络性能,我才发现,以前随便学了点的《TCP/IP 详解》对我在排查网络问题上有很大的帮助。这个时候,我才认真地看了这本书,也正是这个时候,才算是真正读进去了。
后来,我让我团队的一个人学《TCP/IP 详解》这本书,他发现有点难啃就买了一本《图解 TCP/IP》。我找来一看,发现这种图文并茂的书真是增加了很不错的阅读体验,一下子就觉得不是很枯燥了。这让我回想起来那本《从一到无穷大》的相对论科普书,简单、一点也不枯燥。然而,能把这么复杂的问题用这么简单的语言讲清楚的一定是这个领域的大牛了。
我列举我的这个学习过程,就是想说,如果你发现有些知识太过于枯燥,那么可以通过下面的方法解决。
这个知识对于你来说来太高级了,你可能不知道能用在什么地方。
人的认知是从感性认识向理性认识转化的,所以,你可能要先去找一下应用场景,学点更实用的,再回来学理论。
学习需要有反馈,有成就感,带着相关问题去学习会更好。
当然,找到牛人来给你讲解,也是一个很不错的手段。
看过《程序员练级攻略》的朋友们,一定会有这样的疑问,东西太多了,怎么学。我给你的建议是,一点一点学,一口一口吃。你可以使用我前面说过的那些方法,注重基础,画知识图,多问为什么,多动手,然后坚持住,哪怕你每周就学一个知识点,你一年也可以学到 50 个知识点。只要你在进步,总有一天可以把这些知识学到手的。
当然,你的目的不是学完这些知识,因为学无止境,你永远也学不完,所以你在学习时,一定不要学在表面上,一定要学到本质,学到原理上,那些东西是不容易变的,也是经得住时间考验的。把学习当成投资,这是这个世界上回报最好的投资。
带着问题去学习,带着要解决的东西去学习,带着挑战去学习,于是每当你解决了一个问题,做了一个功能,完成了一个挑战,你就会感到兴奋和有成就感。这样,你也就找到了源源不断的学习驱动力。
把你学习的心得、过程、笔记、代码分享出来,找到和你一同学习的人,因为一个人长跑很辛苦,有人同行就会好很多,就算没有人同行,你的读者,你的观众也会为你鼓掌加油,这些也是让你持续前行的动力。
人的一生是要永远学习的。加油!
我发现很多技术问题都是出在技术人员不认真读技术手册上,我自己也一样。在我的成长生涯中,我发现很多答案或其实都在文档中,而我却没有仔细地去读一下。可能是,我们都不想投入太多的时间吧。
在这里,我想说,用户手册(User Manual)一定要好好地读一读,很多很多提示都在里面了,这是让你可以少掉很多坑的法宝。比如:Unix 和 Linux 的 man,Docker 和 Kubernetes 的官方文档,Git 的操作文档……你的很多很多问题的答案都在这些文档中。
举个例子,很多年前,我掉了一个坑,我把这个问题记录在了文章《 C/C++ 返回内部静态成员的陷阱 》中。 其中提到了一个函数 char *inet_ntoa(struct in_addr in);
,我还批评了一下这个函数。然而,只要你 man 一下这个函数,就可以看到:“The string is returned in a statically allocated buffer, which subsequent calls will overwrite”。
还有,很多中国的文档都会教人把 tcp_tw_recycle 和 tcp_tw_resue 这两个参数打开。然而,只要你 man 一下 TCP(7) ,就可以看到这样的描述:
你就可以看到这两个参数都是不建议被打开的。
认真阅读用户手册不但可以让你少掉很多坑,同时,还能让你学习到很多。
用不同的方式来学习同一个东西。比如:通过看书,听课,创建脑图,写博客,讲课,解决实际问题,等等。
不要被打断。被打断简直就是学习的天敌,所以,你在学习的时候,最好把手机设置成勿扰模式放在一边,然后把电脑上的所有通知也关掉,最好到一个别人找不到你的地方。
总结压缩信息。当你获得太多的信息时,你需要有一个“压缩算法”。我常用的压缩算法是只关心关键点,所以,你需要使用表格、图示、笔记或者脑图来帮助你压缩信息。
把未知关联到已知。把你新学的知识点关联到已知的事物上来。比如,你在学习 Go 语言,你就把一些知识关联到自己已经学过的语言上比如 C 和 Java。通过类比,你会学得更扎实,也会思考得更多。
用教的方式来学习。你想想,如果你过几天要在公开场合对很多人讲一个技术,那么这个压力会让你学得更好。因为要教给别人,所以,这么高的标准需要你不但要把自己已掌握的东西学好,还要把周边的也一并学了,才可能做到百问不倒。你才敢去教别人,不是么?(试试教 6 岁的孩子编程,如果你掌握了这种技能,那么你一定是把知识吃得非常透彻了。)
学以致用。把学到的东西用起来,没有什么比用起来能让你的知识更巩固的了。在实践中,你才会有更为真实的体会,你才会遇到非常细节和非常具体的问题,这些都会让你重新思考,或深化学习。
不要记忆。聪明的人不会记忆知识的,他们会找方法,那些可以推导出知识或答案的方法。这也是为什么外国人特别喜欢方法论。
多犯错误。犯错会让你学得到更多,通过错误总结教训,你会比没有犯过错的人体会得更深。但是千万不要犯低级错误,也不要同一个错误犯两次。
如果你有更好的一些技巧,欢迎你分享出来。
总结一下今天的内容。首先,我先分析了为什么会有枯燥的知识。我认为,枯燥的知识通常是你不感兴趣的知识,也有可能是你不知道有什么用的东西。然后,结合自己的经历给出了面对枯燥的知识时该怎样做。此外,我们身处在信息爆炸时代,如何面对如此量大的知识,也是我们面临的一个挑战。我建议,一定不要学在表面上,一定要学到本质上、原理上,一定要学那些不容易改变,能经得住时间考验的东西。
随后,我分享了认真阅读文档的重要性,不仅可以让你少掉很多坑,还可以让你学习到很多知识。最后,我分享了好几条实用的学习技巧,这些也是我在工作中慢慢收集和总结起来的。希望对你有帮助。
来源:《左耳听风专栏:高效学习》