MYSQL空间索引使用指南
背景
近期在开发一个需求的使用用到了 MYSQL 的空间索引,之前一般也用不上这个,这次第一次用倒是踩了不少的坑。
目前需求开发完成且稳定运行一段时间没有异常了,才来写这篇文章,主要就是介绍一下如何使用 MYSQL 的空间索引以及在使用中需要注意的一些坑。
问题引入
在 MYSQL 数据库中保存了上千万条记录,每条记录保存了一个地理坐标点。需求是传入一个坐标点的位置以及一个半径r,检索出该坐标点方圆r距离内的所有记录。
看起来有点小小的难度,上网检索了一下,MYSQL 中有个函数 ST_Distance_Sphere 能直接计算两个坐标点的距离。
那 easy 了,省略表中无关字段,表的 DDL 为:
12345create table `locations`( id bigint auto_increment primary key, coordinate point not null)
查询 sql 则为:
12345SELECT * FROM `locations`WHERE ST_Distance_Sphere(coordinate,ST_GeomF ...
用ebiten写一个炸弹人
ebiten 是啥
Ebiten 是一个用 Go 编程语言编写的开源游戏库,专门用于开发 2D 游戏。它简单易用,适合创建跨平台的游戏,支持 Windows、macOS、Linux、iOS 和 Android 等平台。Ebiten 提供了渲染、输入处理、音频播放等功能,帮助开发者快速构建和发布游戏。
主要特点
简单易用:提供了简洁的 API,开发者可以快速上手编写 2D 游戏,不需要深入了解复杂的图形编程。
跨平台支持:一个代码库可以编译和运行在多个平台上,包括桌面、移动设备和网页浏览器。
高效的渲染:Ebiten 利用底层的 OpenGL 或 Metal API 实现了高效的 2D 渲染,能够处理游戏中的大量图形操作。
集成输入处理:支持键盘、鼠标、触摸屏、手柄等多种输入方式,可以轻松实现用户交互。
游戏循环:提供了简单的游戏主循环,开发者只需专注于每一帧的游戏逻辑和渲染。
快速上手 ebiten
在 Ebiten 中,游戏的核心是一个实现了 ebiten.Game 接口的结构体。该接口的原型如下:
12345type Game interface { Updat ...
MYSQL数据库踩坑合集
数据库报错 ‘ERROR 1290’
最近在观察生产环境的运行日志时发现,日志中出现了一些 Error 1290: The MySQL server is running with the --read-only option so it cannot execute this statement 错误。询问了系统运维,得到的答复是数据库没有 down,也没有数据库升级或者迁移的动作。
遂询问 MYSQL 生产环境所用的架构以及服务商,得到以下答复:
服务商:阿里云云数据库RDS
架构:读写分离
问题排查
通过日志信息,找到出错的 SQL 语句,发现均为 SELECT 查询语句,且使用 FOR UPDATE 加了行级锁。
推测为加锁失败导致的报错。
查阅阿里云 RDS 文档,得到以下关键信息:读写分离架构的数据库,可单独设置每个实例的读写权重。
再次询问系统运维,得知项目所用数据库的读写权重为主实例只写,其他从实例均摊读请求。
推测错误原因为:读写分离架构,数据库代理将所有的 SELECT 请求发送到了从实例,但是部分 SELECT 请求使用了 FOR UPDATE,需要写数据库, ...
go&redis组合编写一个分布式队列
背景
最近开发的一个项目,需要使用任务队列来控制任务的发布和消费。一开始做技术选型的时候,选择的是 RabbitMQ,一来是在其他项目使用过,轻车熟路了,无学习成本,二是有现成的 RabbitMQ 服务器可用,无需运维成本和额外的服务器成本。但后来出现了需要获取任务详情以及任务当前排号的需求,单独使用 RabbitMQ 的话无法实现这些需求。
在经过考量后,RabbitMQ 搭配 redis 的 ZSET 结构能实现以上的需求。考虑到 redis 也能实现队列的功能,因此决定放弃 RabbitMQ,完全使用 redis 实现项目所需的任务队列。
实现流程
需求分析
任务队列功能(任务发布、任务队列订阅、任务拉取、任务响应)
获取任务的详细信息
获取任务的排队情况
获取任务是否存在
获取任务总数
删除任务
实现步骤
任务队列的结构体设计
任务队列的接口抽象
实现队列接口
处理并发问题
任务队列的结构体设计
首先,该队列是使用 redis 进行实现的,所以必须要有的是 redis 的客户端连接,使用的是 github.com/go-redis/redis/v8 包:
1redisC ...
golang中的反射
什么是反射
反射是 go 语言提供的一种在运行时动态获取变量类型和值的手段。
有时候我们可能需要编写一个函数,来处理当时尚不清楚类型的参数,可能是该类型当时尚不存在,也可能是其没有明确的表达式。
比如说,我要编写一个函数,接收一个 any 类型的参数,打印出该参数的实际类型以及其方法列表。该需求通过正常方案是没办法实现的,必须使用反射,来得到其类型和其方法列表。
反射的使用
所有反射的功能,均由 reflect 包提供。该包中包含了反射功能最核心的两个类型,一是 reflect.Type ,该类型用来描述一个变量的具体类型;二是 reflect.Value ,该类型用来描述一个变量的具体的值。
reflect.TypeOf
函数 reflect.TypeOf() 接收任意的类型,并以 reflect.Type 返回其具体类型。
123t := reflect.TypeOf(3) // a reflect.Typefmt.Println(t.String()) // "int"fmt.Println(t) // "int"
这里 ...
Nginx 快速入门
前言
在当今互联网飞速发展的时代,网站性能和稳定性对于用户体验至关重要。无论是个人开发者还是大型企业,都需要一个高效、可靠的 Web 服务器来支撑其在线业务。而 Nginx,作为一个高性能的 HTTP 和反向代理服务器,凭借其卓越的性能、丰富的功能和灵活的配置,已经成为全球最受欢迎的Web服务器之一。
本文将详细讲解如何入门 Nginx,帮助每个后端开发者了解 Nginx 的用途和用法。
简介
Nginx(Engine X) 是由俄罗斯工程师 Igor Sysoev 于 2004 年开发的用于解决 C10k 问题(即在一台服务器上同时处理 10000 个并发连接的挑战)的服务器。自发布以来,Nginx 迅速获得了广泛的应用,尤其是在高并发、大流量的互联网服务中。
选择使用 Nginx 的理由有很多,以下是 Nignx 的一些特点:
高并发处理能力:Nginx 采用异步、非阻塞的事件驱动模型,能够高效地处理大量并发连接(单机支持 10w 以上的并发连接);
低资源消耗:Nginx 通过事件驱动机制大幅降低了CPU和内存的消耗,即使在高负载下也能保持较低的资源占用(一般情况下,10000 ...
golang常用轮子
前言
在使用 go 语言进行开发时,经常会遇到一些常见的编程任务和问题。为了提高开发效率和代码质量,造轮子是很常见的行为,使用轮子能提高我们的开发效率和代码复用率。
这篇文章主要汇总一下我在开发过程中自己写的一些轮子,供大家参考使用。
JWT
JWT(JSON Web Token, Json Web 令牌) 是一个开放标准,定义了一种紧凑的、自包含的方式,用于在各方之间以 Json 对象安全地传输信息。此信息可以验证和信任,因为它是数字签名过的。常在 WEB 应用中被用于身份认证。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061package jwtimport ( "fmt" "github.com/dgrijalva/jwt-go" "time")type SessionClaims struct { *jwt. ...
golang 单元测试
什么是单元测试
单元测试是对一组封装良好、实现有限特定功能的代码进行正确性检验的工作。对于面向过程编程来说,一个单元可以是一个函数;对于面向对象编程来说,一个单元就是类的方法;在 Go 中,一个 package(下称包) 就是一个单元。
为什么需要单元测试
相比没有单元测试的代码,有单元测试的代码具有以下优点:
最直接的当然是提高代码的正确率和可靠性;
尽早发现问题。问题越早发现,解决的难度和成本就越低;
提高团队各成员之间的沟通效率。新代码未经过测试就发布到测试环境,可能会带有明显的 bug,这会制造非常多繁琐的协作流程:测试人员发现 Bug → 新建 Bug 卡 → 开发人员收到 Bug 卡后开始排查并修复 → 提交代码 → 运行 CI 流水线 → 再次发布 → 开发人员修改 Bug 卡状态 → 测试人员验证;
保证重构的正确性。随着功能的增加,重构(修改老代码)几乎是无法避免的,很多时候我们没有信心做代码重构,就是因为担心重构会导致引入新的 Bug。有了单元测试,只要在改完代码后运行一下单元测试就知道改动对整个系统的影响了;
优化代码设计。编写单元测试需要开发人员让自己的代码通 ...
go web 服务常用的项目结构
前言
Go 语言已经广泛被应用于服务端开发,成为了构建高效、可靠服务端应用程序的首选语言。因此,精通如何搭建一个 Go 服务端项目,是每一位 Go 开发者必备的技能。
一个良好的服务端项目,其核心在于其项目架构的设计。一个优秀的项目架构能够帮助我们有序地组织代码,极大地提升代码的可维护性和可读性,同时也能有效地提高开发效率。
在接下来的文章中,我将简单探讨一下 Go 语言在 Web 服务端开发中常用的一种项目架构。
go-web 服务项目结构
为什么要进行项目分层
项目代码分层是一种常见的软件开发实践,主要有以下几个理由:
可维护性:当代码分层清晰时,维护工作相对容易进行。每个层次都有明确的职责,使得定位和修复问题更为简单。此外,如果需要修改某个功能或行为,只需要在相应的层进行修改,而不会影响到其他层。
复用性:代码分层可以提高代码的复用性。例如,数据访问层的代码通常可以在多个场景中重复使用,无论是在不同的业务逻辑中,还是在不同的项目中。
可测试性:代码分层有助于单元测试和集成测试。每一层都可以独立地进行测试,这使得测试工作更为简单和可控。
解耦:分层设计有助于降低各部分代码之间的耦 ...
golang 内存逃逸
前言
在编程领域中,理解和管理内存是提高代码性能和稳定性的关键。尤其在 Go 语言中,一个强大的垃圾收集器和内存模型使得内存管理变得相对直观,但这并不意味着我们可以完全忽视内存的使用。其中,内存逃逸是一个值得我们深入理解的概念,因为它直接影响到变量的生命周期和垃圾收集的效率。
在这篇文章中,我将详细地探讨 Go 语言中的内存逃逸,以及内存逃逸将造成什么影响,如何分析并优化内存逃逸现象。
概念
在 C/C++ 开发中,需要开发者手动分配内存(malloc/new),使用完后的内存需要手动回收(delete)。这样做的好处是能够细致掌握内存的分配,但因此也会降低开发者的开发效率,而且若是忘记回收内存,就会造成内存泄露。因此,大多数的高级语言都实现了垃圾回收机制(GC),通过编译器来管理内存分配。
go 语言中,在函数中创建一个局部变量,编译器在编译的时候就会根据一定的规则,指定该变量的内存是分配到栈还是分配到堆。而对于分配到堆上的内存,就称之为内存逃逸。
内存分配规则
一般情况下,在函数中创建的变量都应该分配到栈上,以下情况才会分配到堆上,即内存逃逸:
创建的局部变量通过返回值返回了其指 ...