自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(208)
  • 收藏
  • 关注

原创 从零实现RPC框架:Go语言版

良好的接口设计是可扩展性的基础。// Codec 编解码接口// Transport 传输层接口// Registry 服务注册接口// LoadBalancer 负载均衡接口通过从零实现一个RPC框架,我们深入理解了分布式系统通信的核心原理和实现细节。这个过程不仅仅是技术学习,更是对系统设计思维的锻炼。

2025-08-07 15:00:00 991 1

原创 Go语言中的gRPC:原理与实战

接下来,我们定义一个用户服务的接口。这就像画建筑图纸,定义了服务的"外观"和"功能"。// 用户信息// 用户ID// 用户名// 邮箱// 年龄// 标签列表// 获取用户请求// 获取用户响应// 创建用户请求// 用户列表流响应// 用户服务定义// 一元调用:获取单个用户// 一元调用:创建用户// 服务端流:获取用户列表// 客户端流:批量创建用户// 双向流:实时用户聊天。

2025-08-07 14:00:00 508

原创 构建实时应用:WebSocket+Go实战

经过这一路的技术探索,我们从基础的WebSocket概念开始,构建了一个完整的生产级实时聊天应用,并深入探讨了分布式架构、安全加固和性能优化等高级话题。让我来总结一下核心要点和未来的发展趋势。Goroutine管理:忘记正确清理资源导致的内存泄漏消息顺序性:并发处理导致的业务逻辑错误网络配置:Nginx代理和防火墙设置的各种陷阱代码review中特别关注资源清理设计阶段就考虑并发安全部署时使用标准化的配置模板。

2025-08-06 15:00:00 586

原创 HTTP/2在Go中的实现与优化技术指南

经过这篇文章的深入探讨,我们全面了解了HTTP/2在Go中的实现与优化。从基础概念到生产实践,从性能调优到问题解决,HTTP/2已经从一个新兴技术成为了现代Web应用的基础设施。核心收获总结技术层面的提升:HTTP/2的多路复用、头部压缩、服务端推送等特性为我们提供了全新的性能优化思路。相比HTTP/1.1,我们看到了20-40%的性能提升,特别是在高并发和多资源加载场景下效果更加明显。Go语言的优势:Go标准库对HTTP/2的原生支持让我们能够以最小的改动获得最大的收益。

2025-08-06 14:00:00 545

原创 Go语言WebSocket编程详解:从入门到生产实践

经过这一路的探索,我们从WebSocket的基础概念出发,深入到Go语言的具体实现,再到生产环境的优化实践,最后通过一个完整的聊天室项目将所有知识点串联起来。这个过程就像是从学习驾驶理论,到实际上路练习,再到成为熟练司机的成长历程。WebSocket技术虽然概念简单,但要做好却不容易。就像学习一门乐器,掌握基础技巧只是开始,真正的艺术在于如何将这些技巧组合起来,创造出美妙的音乐。在我多年的开发经验中,最大的感悟是:技术永远在变化,但解决问题的思路是相通的。

2025-08-05 15:00:00 1002

原创 RESTful API开发:Go语言最佳实践

经过这一系列的深入探讨,我们从项目架构设计到生产环境部署,全面梳理了Go语言RESTful API开发的最佳实践。让我们来回顾一下核心要点,并展望Go生态的未来发展趋势。

2025-08-05 14:00:00 766

原创 从零到精通:GoFrame 框架文件下载功能深度解析与实践指南

在深入文件下载之前,我们先来了解一下 GoFrame 的“庐山真面目”。如果你已经对 GF 很熟悉,可以直接跳到下一节;如果它是你的“新朋友”,那就跟我一起揭开它的神秘面纱吧。简单来说,GoFrame 是一个模块化、高性能的企业级 Go 开发框架。它由国内团队开发,目标是为开发者提供一个“开箱即用”的工具箱。相比其他轻量级框架(如 Gin 或 Echo),GF 的野心更大——它不仅提供了基本的 HTTP 服务,还内置了 ORM、配置管理、日志系统甚至命令行工具,几乎涵盖了企业开发的全流程。

2025-08-04 15:00:00 1727

原创 构建高性能HTTP服务器:Go标准库深度解析

HTTP Transport是HTTP客户端的核心组件,虽然我们主要讨论服务器,但了解客户端的优化同样重要,因为微服务架构中服务器往往也是其他服务的客户端。经过这次深入的技术探索,我们从Go标准库的设计哲学出发,一路走到了高性能优化和生产实践,就像攀登一座技术高峰,每个阶段都有不同的风景和收获。从简单开始:不要一开始就追求复杂的优化,先让功能跑起来,再逐步优化。重视测试:标准库给了你更多的灵活性,但也意味着更多的责任,完善的测试是必须的。关注社区:Go社区有很多优秀的实践和工具,要保持学习和交流。性能监控。

2025-08-04 14:00:00 1316

原创 Go HTTP中间件设计模式与实践:从入门到精通

想象一下工厂的流水线:原材料进入后,要经过多道工序才能变成最终产品。HTTP中间件就像是这条流水线上的各个工作站,每个中间件负责处理请求的某个特定方面,然后将处理后的请求传递给下一个环节。功能类型具体作用常见场景预处理在业务逻辑前执行参数验证、权限检查后处理在响应返回前执行响应格式化、缓存设置横切关注点与业务逻辑正交的功能日志记录、性能监控错误处理统一的异常处理机制Panic恢复、错误格式化每个中间件都有机会在请求到达业务处理器之前和响应返回客户端之前进行处理。

2025-08-03 15:00:00 943

原创 HTTP客户端实现:深入理解Go的net/http包

通过这篇深度解析,我们从Gonet/http包的基础架构出发,逐步深入到高级特性、实际应用和常见陷阱。

2025-08-01 15:00:00 666

原创 Socket编程进阶:Go中的Unix Domain Socket实战指南

在现代软件架构中,进程间通信(IPC)一直是系统设计的核心挑战之一。传统的TCP Socket虽然功能强大,但在本地通信场景下往往显得"大材小用"——就像用高速公路来连接同一栋楼的两个房间,虽然能达到目的,但显然不是最优选择。Unix Domain Socket(UDS)就像是为同一台机器上的进程量身定制的"专线通道"。它绕过了网络协议栈的复杂处理,直接在内核空间完成数据传输,既保证了高性能,又提供了强大的安全控制能力。在微服务架构盛行的今天,当服务被容器化部署在同一节点时,UDS往往能带来意想不到的性能提

2025-07-30 15:00:00 1451

原创 实现可靠的UDP协议:Go语言版本 - 从理论到实践的完整指南

在网络编程的世界里,TCP和UDP就像是两位性格迥异的朋友。TCP严谨可靠,每个数据包都要确认收到才安心;UDP则追求速度,“发出去就不管了”。对于大多数应用来说,这两种选择似乎已经足够。但随着实时游戏、视频直播、IoT设备等对低延迟高要求应用的兴起,我们发现自己陷入了一个有趣的困境:我们既需要UDP的高性能,又离不开TCP的可靠性。想象一下,你正在开发一款竞技游戏,玩家的每个操作都需要在几十毫秒内同步到服务器。如果使用TCP,虽然数据不会丢失,但是握手、确认、重传等机制会带来额外的延迟;如果使用UDP,速

2025-07-25 15:00:00 1003 1

原创 Go语言实现DNS解析与域名服务:从基础到生产实践

miekg/dnsimport ("fmt""time""context""sync"// DNSClient 自定义DNS客户端结构// NewDNSClient 创建新的DNS客户端Net: "udp", // 默认使用UDP协议},// QueryWithFallback 带故障转移的DNS查询// 构造DNS查询消息// 遍历所有DNS服务器进行查询// 执行DNS查询cancel()// 如果是网络错误,尝试切换到TCP// 指数退避重试。

2025-07-23 17:00:00 895

原创 Go中的UDP编程:实战指南与使用场景

在当今快节奏的数字时代,网络通信的效率往往决定着应用的成败。想象一下,在激烈的电竞比赛中,一个多毫秒的网络延迟就可能让胜利擦肩而过;在物联网设备密集的智能工厂里,每一个传感器数据的及时传输都关乎着生产安全。这些场景的背后,都有一个共同的技术支撑——UDP协议。UDP(User Datagram Protocol)用户数据报协议,虽然不如TCP那样"可靠",但它的"快速"和"灵活"特性却在特定场景下发挥着不可替代的作用。无论是实时音视频通话、在线游戏、DNS查询,还是物联网数据采集,UDP都是首选的传输协议。

2025-07-21 11:13:08 941

原创 TCP连接池设计与实现:提升Go应用网络性能

在高并发的Go应用开发中,网络通信往往是性能瓶颈的"重灾区"。想象一下,如果每次数据库查询都要重新建立TCP连接,就像每次上楼都要重新搭建楼梯一样,不仅耗时耗力,还会严重影响整体效率。每次建立TCP连接都需要经历完整的三次握手过程,这个过程涉及:在我之前负责的一个电商系统中,发现单个数据库查询的平均响应时间竟然达到了50ms,其中连接建立就占用了30ms!这种现象在高并发场景下尤为突出。案例背景:某微服务架构的订单系统,峰值QPS达到5000,每次请求平均需要查询数据库3次。问题现象:根因分析:通过性能分析

2025-07-20 15:00:00 608 1

原创 从零到百万并发:Go语言高性能TCP服务器实现指南

在当今互联网快速发展的时代,TCP服务器就像是互联网世界的"神经网络",承载着无数的连接和数据传输。无论是游戏服务器需要处理玩家的实时交互,还是消息推送系统要同时服务数百万用户,高性能的TCP服务器都是支撑这些应用的核心基础设施。Go语言自诞生以来,就以其独特的协程模型和优秀的并发处理能力在服务器开发领域崭露头角。相比传统的线程模型,Go的协程就像是轻盈的"绿色线程",以仅仅2KB的初始栈空间,让我们能够轻松创建成千上万的并发处理单元。再加上Go强大的标准库支持和垃圾回收机制,开发高性能TCP服务器变得前所

2025-07-18 15:00:00 638

原创 Go语言中的TCP编程:基础实现与最佳实践

经过这一路的探索,我们从TCP编程的基础概念出发,深入到了生产环境的复杂应用场景。就像学习驾驶一样,我们不仅掌握了基本操作,还学会了在各种复杂路况下安全行驶的技巧。技术层面的核心原则:连接管理是基础:合理的连接池设计和生命周期管理是高性能TCP服务的根基并发控制是关键:利用Go的goroutine优势,但要防止资源泄露和过度并发协议设计是灵魂:清晰的消息格式和错误处理机制决定了系统的可靠性监控观测是保障:完善的指标收集和日志记录让问题无处遁形实践层面的重要经验:渐进式优化。

2025-07-16 15:00:00 901 1

原创 深入理解Go的网络I/O模型:从理论到实践的完整指南

在当今互联网时代,高并发Web服务已经成为每个开发者必须面对的技术挑战。想象一下,当你的应用需要同时处理成千上万个用户请求时,传统的"一个连接一个线程"模型就像是在高速公路上用马车运输——不仅效率低下,还会造成严重的资源浪费。这正是Go语言诞生时要解决的核心问题之一。Go通过其独特的网络I/O模型,让开发者能够以近乎线性的方式编写高并发代码,而无需深入了解复杂的事件循环或回调函数。这种"看起来同步,实际异步"的编程体验,让无数开发者为之着迷。本文将带领有1-2年Go开发经验的你,深入探索Go网络I/O模型的

2025-07-13 15:00:00 753

原创 Go网络编程基础:网络模型与协议栈概述 - 从理论到实践的完整指南

在当今的互联网时代,网络编程已经成为后端开发的核心技能。Go语言以其出色的并发性能和简洁的语法,在网络编程领域展现出了强大的优势。从Docker、Kubernetes到众多微服务框架,Go已经成为构建高性能网络应用的首选语言之一。你是否在开发网络应用时遇到过这样的困惑:为什么同样的代码在高并发下表现差异巨大?如何选择TCP还是UDP?什么时候使用HTTP/2,什么时候选择gRPC?这些问题的答案都藏在对网络模型和协议栈的深入理解中。理解网络模型对Go开发者的重要性不言而喻。 它就像是盖房子的地基,只有打牢了

2025-07-11 15:00:00 1295

原创 Go内存优化案例分析:从实践中学习

/ 大型响应对象// 其他字段...// 自定义JSON序列化// 使用对象池获取一个buffer// 手动构建JSON,避免反射if i > 0 {// 复制结果(因为buf会被回收)经过前面案例的分析,我们可以总结出一套内存优化的最佳实践。这些实践就像是一位园丁照料花园的技巧,让你的程序在资源有限的环境中也能茁壮成长。内存优化是一场永无止境的旅程。就像城市规划需要不断适应人口增长和生活方式变化,软件系统也需要持续优化以应对不断变化的需求和环境。Go语言的内存管理正在不断演进。

2025-07-09 15:00:00 1876 1

原创 Go内存压力测试:模拟与应对高负载

内存压力测试是一种特殊的性能测试,专注于评估应用在高内存负载下的行为表现。就像我们测试水管能承受多大的水压一样,内存压力测试可以帮助我们了解应用在极端内存条件下的极限。内存压力测试不是一次性工作,而是系统稳定性和性能优化的长期伙伴。通过本文的学习,我们了解了Go内存压力测试的理论基础、工具使用、测试方案设计,以及问题分析与优化策略。在实际项目中,内存优化常常能带来意想不到的性能提升,因为它直接影响GC行为,间接影响整个系统的响应时间和吞吐量。

2025-07-07 15:00:00 1686

原创 从C/C++迁移到Go:内存管理思维转变

自动内存管理不等于无需关注内存:理解GC的工作方式和限制从手动控制到合理设计:设计合理的数据结构和算法更重要从所有权模型到引用跟踪:理解对象生命周期从精细控制到适度放手:信任语言运行时,专注业务逻辑从C/C++迁移到Go的过程中,内存管理思维的转变可能是最大的挑战,但也带来了巨大的回报。通过拥抱Go的设计理念,我们可以编写出更简洁、更可靠、更易维护的代码,同时保持接近C/C++的性能水平。希望本文能帮助你平稳完成这一思维转变,充分发挥Go语言的潜力!

2025-07-06 15:00:00 617

原创 Go容器化环境中的内存限制与调优:实战指南

经过上述章节的讨论,我们已经深入了解了Go容器化环境中的内存限制与调优技术。最后,让我们展望未来并总结关键经验。明确告知Go运行时内存限制使用GOMEMLIMIT设置软内存限制将限制设置为容器限制的70%-80%代码层面的优化预分配内存,减少动态扩容使用对象池减少GC压力注意长连接和goroutine泄漏监控与分析建立完善的监控系统,包括内存使用、GC频率和延迟定期进行pprof分析,发现潜在问题容器配置最佳实践设置合理的内存请求和限制比例禁用或限制swap使用。

2025-07-06 14:00:00 761

原创 Go程序内存使用基准测试与比较:从理论到实践

掌握合适的工具是进行有效内存基准测试的前提,就像木匠需要合适的工具才能打造精美家具一样。通过这次深入探讨Go程序内存基准测试与优化,我们不仅学习了理论知识,还通过实战案例获得了宝贵的实践经验。

2025-07-05 15:00:00 917 1

原创 Go反射使用的内存成本与优化方法 - 从理论到实践的全面指南

纵观Go反射的内存优化之旅,我们从理论基础出发,探索了各种优化策略和实战案例,积累了宝贵的经验教训。现在,让我们归纳出反射使用的决策框架,并展望Go未来版本中反射系统可能的改进方向。反射就像魔法一样强大,但正如所有魔法一样,它也需要谨慎使用。通过理解反射的内存成本并应用本文介绍的优化策略,你可以享受反射带来的灵活性,同时避免其性能陷阱。记住,最好的反射代码往往是最少的反射代码。适当地使用缓存、池化和预编译技术,可以在保持代码灵活性的同时,显著降低内存开销和提高执行效率。

2025-07-05 14:00:00 544

原创 Go中interface的内存开销与优化:从理论到实践

在这篇文章中,我们深入探讨了Go中interface的内存开销与优化技巧。了解内部机制:interface在内存中由类型信息和数据指针组成,装箱操作会产生内存分配。辨别适用场景✅ 适合用于模块边界、插件系统和测试❌ 不适合用于热点路径和性能关键型操作优化策略减少不必要的类型转换使用具体类型的快速路径合理设计小而精确的接口考虑泛型作为替代方案使用对象池减少分配平衡艺术:软件设计是灵活性和性能的平衡艺术,好的架构应该在适当的地方使用适当的工具。

2025-07-04 15:00:00 1332

原创 Go高并发场景下的内存管理最佳实践

/ 一个简单的固定大小对象池实现select {return bufdefault:// 池为空,创建新的bufferbuf.Reset() // 重置buffer状态select {// 放回池中成功default:// 池已满,丢弃预分配固定数量的对象,避免峰值创建实现带过期时间的对象回收添加使用统计和监控功能在这篇文章中,我们深入探讨了Go高并发场景下的内存管理最佳实践。从基础概念到实战案例,系统地梳理了提升Go程序内存效率的关键策略。

2025-07-04 14:00:00 632

原创 Go缓存设计:权衡内存使用与性能

平衡内存与性能:缓存容量并非越大越好,而是要找到最佳平衡点分层设计:多级缓存可以兼顾性能与容量数据一致性:务必谨慎处理缓存与源数据的同步策略防御设计:必须考虑缓存穿透、击穿和雪崩等异常情况监控优先:完善的监控和告警是保障缓存系统稳定的基础。

2025-07-03 15:00:00 822

原创 Go结构体内存布局优化与字段排序技巧 - 提升程序性能的隐藏技巧

高性能系统开发:当性能是关键指标时内存密集型应用:处理大量数据的系统嵌入式或资源受限环境:内存本身就很宝贵优化热点代码路径:在性能分析后发现的瓶颈区域。

2025-07-03 14:00:00 1372

原创 Go GC停顿时间优化:实现毫秒级响应

白色:潜在的垃圾,尚未被检查或已经确认为垃圾的对象灰色:已检查但还需进一步处理的对象(就像分拣中的物品)黑色:确认存活且已完成检查的对象这个过程就像从你的"根物品"(如全局变量、栈上变量)开始整理,逐步确认什么是需要保留的,什么可以丢弃。GC停顿是指垃圾回收期间,程序必须暂停正常执行的时间段。GC开始时:准备工作,设置写屏障标记终止阶段:确保所有对象都被正确标记这就像整理房间时,有些时刻你必须停下来思考:“这个物品到底应该放哪儿?”,不可能100%的时间都在动手整理。

2025-07-02 15:00:00 760 1

原创 Go微服务架构下的内存优化策略:从原理到实践

/ 针对特定大小的buffer池,避免sync.Pool的GC清理问题size int // buffer的初始容量max int // 池的最大容量max: max,return buf// 防止池无限增长在我们的API网关项目中,将请求处理中的临时buffer改为使用对象池后,每秒节省了约20万次内存分配,GC频率降低了70%,服务延迟从P99的120ms降至45ms。经过多个微服务项目的实战经验,我们总结了一系列最佳实践和常见陷阱。

2025-07-02 14:00:00 1447

原创 GoFrame Session 模块实战:从入门到生产实践

在微服务架构大行其道的今天,Session(会话管理)依然是 Web 开发绕不开的话题。无论是用户登录状态的保持,还是购物车数据的暂存,Session 都扮演着“幕后英雄”的角色。作为 Go 语言生态中一颗冉冉升起的全栈框架,GoFrame(简称 GF)凭借其优雅的设计和强大的功能,在国内开发者圈子里圈粉无数。而其中的gsession 模块,更是为开发者提供了一个开箱即用的会话管理利器。想让 Session 在每次访问时自动延期?if err!= nil {// 每次访问重置 TTLif value!

2025-07-01 15:00:00 2147

原创 Go内存分析工具链:从开发到生产环境

pprof是Go语言内置的性能分析利器,堪比瑞士军刀般多功能。它不仅能分析CPU使用情况,还能深入检查内存分配。基于Prometheus可以设置告警规则,当内存使用超过阈值时发送通知。groups:rules:for: 5mlabels:summary: "高内存使用率"description: "应用 {{ $labels.instance }} 内存使用率超过85%已持续5分钟"for: 2mlabels:summary: "内存快速增长"

2025-07-01 14:00:00 771

原创 Go中string与[]byte的内存处理与转换优化

理解底层原理:掌握string不可变而[]byte可变的特性减少不必要的转换:合理选择数据类型,避免频繁转换高效构建工具:使用strings.Builder和bytes.Buffer复用内存:采用预分配和对象池技术减少内存分配安全使用unsafe:在适当场景下谨慎使用零拷贝技术。

2025-06-29 15:00:00 843

原创 Go GOGC环境变量调优与实战案例

GOGC环境变量控制着Go垃圾回收器的积极程度,它决定了下一次GC触发前,堆内存可以增长的比例。// GOGC的工作原理可以用以下伪代码表示触发下一次GC的阈值 = 上次GC后的活跃内存 * (1 + GOGC/100)默认情况下,GOGC=100,这意味着当堆内存增长到上次GC完成后的两倍(100%增长)时,将触发新一轮GC。❗ 注意:理解GOGC不是直接控制内存使用上限,而是控制GC触发的频率。了解应用特性:不同类型的应用需要不同的GC策略高吞吐量服务器通常受益于较高的GOGC值(200-300)

2025-06-27 15:00:00 566 1

原创 Go sync.Pool最佳实践:复用对象降低GC压力

理论知识已经详细介绍,接下来分享一些来自真实项目的经验和教训,这些案例展示了sync.Pool在不同场景下的应用效果。经过深入探讨,我们已经全面了解了sync.Pool的工作原理、使用方法、最佳实践和实战经验。让我们总结核心要点,并展望未来发展趋势。虽然sync.Pool功能强大,但并非所有场景都适合使用它。选择sync.Pool的情况选择自定义对象池的情况对象需要被GC管理需要严格控制池大小短暂使用后即可释放对象需要长期持有对象状态容易重置对象有复杂的状态管理简单的Get/Put模式足够。

2025-06-25 15:00:00 868 1

原创 Go中值类型与指针类型选择:内存分配优化实战指南

在一个处理每秒上万请求的 API 网关项目中,我们面临 GC 压力过大导致的延迟波动问题。分析发现,主要原因是路由匹配过程中大量临时对象的创建。优化方案使用对象池:为频繁创建的请求上下文对象建立对象池预分配:为可预期大小的切片预分配容量,避免扩容减少接口转换:减少类型的使用,避免装箱操作字符串处理优化:使用替代连接符优化效果每秒内存分配减少了约 60%P99 延迟从 15ms 降至 5msGC 暂停次数减少约 70%适度优化:先剖析性能瓶颈,再有针对性地优化遵循规则小对象优先值类型。

2025-06-22 15:00:00 817 1

原创 Go程序内存占用分析与监控方法

通过本文的学习,我们已经掌握了Go程序内存分析与监控的基本方法和实践技巧。这些知识和技能将帮助你构建更加高效和稳定的Go应用。

2025-06-20 15:00:00 939

原创 Go GC触发条件与调优参数详解

GOMEMLIMIT# 设置应用最大内存使用上限为8GB export GOMEMLIMIT = 8GiB当应用接近这个限制时,GC会更频繁地运行,以避免OOM。这个特性在Kubernetes等资源受限环境中特别有用。应用类型GOGC推荐值GOMEMLIMIT推荐其他建议API服务100-150内存限制的80%使用对象池减少临时对象数据处理150-250内存限制的90%批量处理减少内存波动CLI工具200-off可不设置短生命周期应用可考虑禁用GC低延迟服务150-200。

2025-06-18 15:00:00 677

原创 Go大对象与小对象分配策略优化 - 从理论到实践

理解分配机制:小对象和大对象走不同分配路径,需要针对性优化复用优于重建:高频使用的对象应使用对象池技术复用预分配优于增长:合理预估并预分配容量,避免运行时扩容分批替代整块:处理大数据时采用分批策略,控制内存峰值监控指导优化:使用pprof等工具监控内存使用,有的放矢进行优化。

2025-06-15 15:00:00 949

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除