2022-03-31-Redis 使用场景

2022-03-31-Redis 使用场景 database Redis Redis 使用场景 Redis 是一个基于内存的单线程的缓存中间件,利用它可以实现很多场景的需求。 数据缓存:string、hash 分布式数据共享:string、hash 分布式锁:setnx 分布式生成全局ID:incrby key number,利用原子性 计数器:incr key。文章的阅读量、微博点赞数、允许一定的延迟 限流:incr key。访问者的ip和其他信息作为key,访问一次增加一次计数,超过次数则返回false 位统计:set key value;setbit key bitPos 0/1。用来做大数据量的统计 临时购物车:string、hash 用户消息时间线:list 消息队列:list 抽奖:spop set 点赞、签到、打卡:set。对于这类场景每个人都是独立的。 商品标签:set 商品筛选:set;sdiff差集/sinter交集/sunion并集 用户关注:set 排行榜:zset

January 16, 2026

2022-03-31-MySQL索引类型

2022-03-31-MySQL索引类型 database MySQL [转载]MySQL 索引类型 转载信息 作者:白菜1031 发布时间:2020-11-01 原始链接:MySQL索引有哪些分类,你真的清楚吗? MySQL索引都有哪些分类? 按数据结构分类可分为:B+tree 索引、Hash 索引、Full-text 索引。 按物理存储分类可分为:聚簇索引、二级索引(辅助索引)。 按字段特性分类可分为:主键索引、唯一索引、普通索引、前缀索引。 按字段个数分类可分为:单列索引、联合索引(复合索引、组合索引)。 数据结构分类 MySQL索引按数据结构分类可分为:B+tree索引、Hash索引、Full-text索引。 - InnoDB MyISAM Memory B+tree索引 √ √ √ Hash索引 × × √ Full-text索引 √(MySQL5.6+) √ × 注:InnoDB 实际上也支持 Hash 索引,但是 InnoDB 中 Hash 索引的创建由存储引擎引擎自动优化创建,不能人为干预是否为表创建 Hash 索引 B+tree 是MySQL中被存储引擎采用最多的索引类型。B+tree 中的 B 代表平衡(balance),而不是二叉(binary),因为 B+tree 是从最早的平衡二叉树演化而来的。下面展示B+tree数据结构与其他数据结构的对比。 1. B+tree与B-tree的对比 B-tree 中的每个节点根据实际情况可以包含多条数据信息和子节点,如下图所示为一个 3 阶的 B-tree: (图片来源于网络) 相对于 B-tree,B+tree 有以下两点不同: B+tree 非叶子节点只存储键值信息, 数据记录都存放在叶子节点中。而 B-tree 的非叶子节点也存储数据。所以 B+tree 单个节点的数据量更小,在相同的磁盘 I/O 次数下,能查询更多的节点。 B+tree 所有叶子节点之间都采用单链表连接。适合 MySQL 中常见的基于范围的顺序检索场景,而 B-tree 无法做到这一点。 ...

January 16, 2026

2022-03-31-Golang 程序实现热更新

2022-03-31-Golang 程序实现热更新 Go Golang 程序实现热更新 热更新的定义就是在客户无感知的情况下进行程序的升级。 常用的方案有两种: 程序上面有代理层,例如:NGINX、k8s-proxy 程序自身实现热更新,例如:tableflip、endless 对于第一种方案来说,会消耗更多的资源,但是实现起来很简单,也不容易出错,从工程的角度来说是好的方案。 对于第二种方案来说,架构设计上更简单(毕竟少了一层转发代理),但是实现起来需要考虑的点很多,容易出现预期外的问题,工程上不建议使用,但在实现的过程中可以深入的理解:一个程序到底是如何运行的。 endless 已经很久没有更新了,除了简单的 Web 应用外,其他应用不建议继续使用,可以选择更新且更新频率更高的 tableflip。 对于第二个方案,简单的理解就是:程序先运行起来,在热更新的时候,自启动(fork)一个新的进程,同时将一些关键资源进行拷贝,在确保新的进程可以开始工作后原先的进程就退出。 可以参考 graceful-upgrades-in-go 里提到的设计。 重点: 利用 SO_REUSEPORT 实现套接字复用 参考 tableflip endess graceful-upgrades-in-go

January 16, 2026

2022-03-31-分钱问题

2022-03-31-分钱问题 Algorithm 分钱问题 x 元分给 y 个人,每个人可以分到的金额为 m 到 n 元,且 m < x/y < n。 思路很多,但都有缺陷。对于上述问题,除了实现明面上的分配问题,还需要考虑: 是否实时性分配、而不是预分配 是否需要符合某种分布方案 伯努利分布 二项式分布 几何分布 负二项式分布 超几何分布 泊松分布 均匀分布 正态分布 伽马分布 指数分布 这里面牵扯到不少概率论的问题,想清楚算法再去想实现。 方案一:快速预分配 使用预分配的方案,在初次分配后随即给随机用户分钱,只要用户可持有的金额没超过最大值即成立,否则这次划转失效。 package main import ( "fmt" "math/rand" "time" ) var ( totalMoney = 100.00 person = 10 min = 9.5 max = 10.5 ) func main() { // 假设精确到分,即不使用浮点数 var resultOut [10]float64 var result [10]int totalMoneyInt := int(totalMoney * 100) minInt := int(min * 100) maxInt := int(max * 100) // 预分配 9.5 元,实现第一个条件 for index := range result { result[index] = minInt } remainMoney := totalMoneyInt - minInt*person rand.Seed(time.Now().Unix()) oneAlloct := 0 randomUser := 0 cycleCount := 0 for { // 每次循环获得一个随机值,然后随机分配给一个用户 cycleCount++ if remainMoney == 0 { break } else if remainMoney < maxInt-minInt { oneAlloct = remainMoney } else { oneAlloct = rand.Intn(maxInt - minInt) } randomUser = rand.Intn(person) if result[randomUser]+oneAlloct > maxInt { continue } result[randomUser] = result[randomUser] + oneAlloct remainMoney = remainMoney - oneAlloct } for index := range result { resultOut[index] = float64(result[index]) / 100 } fmt.Printf("总共循环了:%d次\n每个人可以分配的金额为:%v", cycleCount, resultOut) } 方案二:即时分配 参考微信发送红包机制:每个人可以抢到的金额为 [0.01, 平均值*2]。 ...

January 16, 2026

2022-02-28-一文详解微服务架构

2022-02-28-一文详解微服务架构 [[Microservices]] [转载]一文详解微服务架构 转载信息 作者:古霜卡比 原始链接:一文详解微服务架构 标签:微服务, 架构, 服务治理, 链路跟踪, 服务发现, 流量控制, Service Mesh 正文 本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件。本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节。 要理解微服务,首先要先理解不是微服务的那些。通常跟微服务相对的是单体应用,即将所有功能都打包成在一个独立单元的应用程序。从单体应用到微服务并不是一蹴而就的,这是一个逐渐演变的过程。本文将以一个网上超市应用为例来说明这一过程。 最初的需求 几年前,小明和小皮一起创业做网上超市。小明负责程序开发,小皮负责其他事宜。当时互联网还不发达,网上超市还是蓝海。只要功能实现了就能随便赚钱。所以他们的需求很简单,只需要一个网站挂在公网,用户能够在这个网站上浏览商品、购买商品;另外还需一个管理后台,可以管理商品、用户、以及订单数据。 我们整理一下功能清单: 网站 用户注册、登录功能 商品展示 下单 管理后台 用户管理 商品管理 订单管理 由于需求简单,小明左手右手一个慢动作,网站就做好了。管理后台出于安全考虑,不和网站做在一起,小明右手左手慢动作重播,管理网站也做好了。总体架构图如下: 小明挥一挥手,找了家云服务部署上去,网站就上线了。上线后好评如潮,深受各类肥宅喜爱。小明小皮美滋滋地开始躺着收钱。 随着业务发展…… 好景不长,没过几天,各类网上超市紧跟着拔地而起,对小明小皮造成了强烈的冲击。 在竞争的压力下,小明小皮决定开展一些营销手段: 开展促销活动。比如元旦全场打折,春节买二送一,情人节狗粮优惠券等等。 拓展渠道,新增移动端营销。除了网站外,还需要开发移动端APP,微信小程序等。 精准营销。利用历史数据对用户进行分析,提供个性化服务。 …… 这些活动都需要程序开发的支持。小明拉了同学小红加入团队。小红负责数据分析以及移动端相关开发。小明负责促销活动相关功能的开发。 因为开发任务比较紧迫,小明小红没有好好规划整个系统的架构,随便拍了拍脑袋,决定把促销管理和数据分析放在管理后台里,微信和移动端APP另外搭建。通宵了几天后,新功能和新应用基本完工。这时架构图如下: 这一阶段存在很多不合理的地方: 网站和移动端应用有很多相同业务逻辑的重复代码。 数据有时候通过数据库共享,有时候通过接口调用传输。接口调用关系杂乱。 单个应用为了给其他应用提供接口,渐渐地越改越大,包含了很多本来就不属于它的逻辑。应用边界模糊,功能归属混乱。 管理后台在一开始的设计中保障级别较低。加入数据分析和促销管理相关功能后出现性能瓶颈,影响了其他应用。 数据库表结构被多个应用依赖,无法重构和优化。 所有应用都在一个数据库上操作,数据库出现性能瓶颈。特别是数据分析跑起来的时候,数据库性能急剧下降。 开发、测试、部署、维护愈发困难。即使只改动一个小功能,也需要整个应用一起发布。有时候发布会不小心带上了一些未经测试的代码,或者修改了一个功能后,另一个意想不到的地方出错了。为了减轻发布可能产生的问题的影响和线上业务停顿的影响,所有应用都要在凌晨三四点执行发布。发布后为了验证应用正常运行,还得盯到第二天白天的用户高峰期…… 团队出现推诿扯皮现象。关于一些公用的功能应该建设在哪个应用上的问题常常要争论很久,最后要么干脆各做各的,或者随便放个地方但是都不维护。 尽管有着诸多问题,但也不能否认这一阶段的成果:快速地根据业务变化建设了系统。不过紧迫且繁重的任务容易使人陷入局部、短浅的思维方式,从而做出妥协式的决策。在这种架构中,每个人都只关注在自己的一亩三分地,缺乏全局的、长远的设计。长此以往,系统建设将会越来越困难,甚至陷入不断推翻、重建的循环。 是时候做出改变了 幸好小明和小红是有追求有理想的好青年。意识到问题后,小明和小红从琐碎的业务需求中腾出了一部分精力,开始梳理整体架构,针对问题准备着手改造。 要做改造,首先你需要有足够的精力和资源。如果你的需求方(业务人员、项目经理、上司等)很强势地一心追求需求进度,以致于你无法挪出额外的精力和资源的话,那么你可能无法做任何事…… 在编程的世界中,最重要的便是抽象能力。微服务改造的过程实际上也是个抽象的过程。小明和小红整理了网上超市的业务逻辑,抽象出公用的业务能力,做成几个公共服务: 用户服务 商品服务 促销服务 订单服务 数据分析服务 各个应用后台只需从这些服务获取所需的数据,从而删去了大量冗余的代码,就剩个轻薄的控制层和前端。这一阶段的架构如下: 这个阶段只是将服务分开了,数据库依然是共用的,所以一些烟囱式系统的缺点仍然存在: 数据库成为性能瓶颈,并且有单点故障的风险。 数据管理趋向混乱。即使一开始有良好的模块化设计,随着时间推移,总会有一个服务直接从数据库取另一个服务的数据的现象。 数据库表结构可能被多个服务依赖,牵一发而动全身,很难调整。 如果一直保持共用数据库的模式,则整个架构会越来越僵化,失去了微服务架构的意义。因此小明和小红一鼓作气,把数据库也拆分了。所有持久化层相互隔离,由各个服务自己负责。另外,为了提高系统的实时性,加入了消息队列机制。架构如下: 完全拆分后各个服务可以采用异构的技术。比如数据分析服务可以使用数据仓库作为持久化层,以便于高效地做一些统计计算;商品服务和促销服务访问频率比较大,因此加入了缓存机制等。 还有一种抽象出公共逻辑的方法是把这些公共逻辑做成公共的框架库。这种方法可以减少服务调用的性能损耗。但是这种方法的管理成本非常高昂,很难保证所有应用版本的一致性。 ...

January 16, 2026

2022-02-28-图床 chevereto 安装及使用

2022-02-28-图床 chevereto 安装及使用 Internet 图床 chevereto 安装及使用 图床服务就是一个图片存储服务,图片直接存放到图床上,需要使用时直接通过一个链接进行调用。这意味着自制图床需要两个先决条件: 一台有存储空间的服务器 一个可以访问的 ip 地址 至于公有云上的图床,可能存在以下一些问题: 图片资源违规直接丢失 收费(容易超出预算) 一台 NAS 即可满足上述两个条件,在下面两篇文章中也提到了如何在 NAS 上配置图床: 群晖搭建 chevereto 图床 在群晖中使用Chevereto搭建图床 但是出于对 NAS 的隐私性,公网访问不稳定性,性能三方面的考虑,决定不使用 NAS,而直接用服务器搭建,它本质上就是一个网络服务。 正好在良心云上有台低配的服务器,话不多少,直接折腾 chevereto-free。 它的安装还是比较麻烦的,需要配置数据库、http 服务、PHP 服务,这些配置都可以查看 Server Installation。 我直接使用容器的方式进行安装,按照 chevereto container compose 描述的进行操作。 安装完成后,默认使用的是宿主机的 8810 端口,这需要去良心云的后台的主机防火墙配置中增加一个 allow 的选项,否则公网页无法访问,配置完成后,打开 public-ip:8810,填入基本信息就可以使用。 最简单的使用方法就是点击 Upload,然后上传本地图片或者通过 url 获取图片资源,理论上会有 api 上传的方案,这里暂且不表。 下面这张图就是该图床存的第一张图。 需要使用图片时,就点开图片详情页,在 Embed codes 会给出不同场合下该如何使用该图片的代码,例如:

January 16, 2026

2022-02-09-Linux查看指定进程资源占用

2022-02-09-Linux查看指定进程资源占用 Linux查看指定进程资源占用 # 保持循环,一直输出 while true; do # 两段命令结合 # 命令1: ps命令 管道 结合head命令 输出头部的数据类型 # 命令2: ps命令 管道 结合grep命令 输出指定的crawl chapter命令的进程 命令可以为其他任何命令 # 命令2: grep -v grep 不输出grep进程 msg=$(ps aux|head -1;ps aux|grep 'crawl chapter'|grep -v grep) # 如果是echo $msg 则没有格式 echo "$msg" 加上换行输出 echo "$msg" echo '' echo '' # 输出当前时间 echo `date "+%Y-%m-%d %H:%M:%S"` # 休眠3s sleep 3s # 清除屏幕的数据打印 clear done Linux

January 16, 2026

2022-02-09-git 拉取所有分支内容

2022-02-09-git 拉取所有分支内容 git Git 拉取所有分支内容 cd repo/ # if remote name is origin git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done git fetch --all git pull --all

January 16, 2026

2021-08-13-IO多路复用

2021-08-13-IO多路复用 Linux [# select、poll、epoll之间的区别(搜狗面试)](https://www.cnblogs.com/aspirant/p/9166944.html) # 彻底理解 IO 多路复用实现机制

January 16, 2026

2021-08-11-Linux 内核态和用户态

2021-08-11-Linux 内核态和用户态 Linux Linux 内核态和用户态 先解释下这两者到底是什么区别。 假设程序需要从磁盘读取数据,数据并不是从磁盘直接加载到程序所持有的内存中,而是: 先将数据从磁盘复制到内核 Buffer 再将数据从内核 Buffer 复制到用户 Buffer 我们来分析下上面两步: 数据从磁盘(硬件)复制到内核 Buffer(内核内存),这是一次 IO 过程 数据从内核 Buffer 复制到用户 Buffer(用户内存) 所以:内核态和用户态本质上只是持有资源的不同,内核态下的指令可以访问到所有资源,而用户态下的指令只能访问到特定资源(CPU、内存)。 用户态、内核态的指令都是 CPU 都在执行,所以我们可以换个说法,实际上这个态代表的是当前 CPU 的状态。那既然这些指令最终都由 CPU 执行,那对其区分的理由是什么呢? 那是因为,CPU 指令根据其重要的程度,也分为不同的权限。有一些指令执行失败了无关痛痒,而有一些指令失败了会导致整个操作系统崩溃,甚至需要重启系统。如果将这些指令随意开放给应用程序的话,整个系统崩溃的概率将会大大的增加。 在 Linux 系统中,由于只有 Ring0 和 Ring3 级别的指令,所以我们可以对用户态、内核态给一个更细节的区别描述:运行 Ring0 级别指令的叫内核态,运行 Ring3 级别指令的叫用户态。 了解了指令集权限的概念,我们就可以再更正一下上面的描述:什么态实际上代表的是当前 CPU 正在执行什么级别的指令 高情商 ring 0被叫做内核态,完全在操作系统内核中运行 ring 3被叫做用户态,在应用程序中运行 低情商 执行内核空间的代码,具有ring 0保护级别,有对硬件的所有操作权限,可以执行所有C P U 指令集,访问任意地址的内存,在内核模式下的任何异常都是灾难性的,将会导致整台机器停机 在用户模式下,具有ring 3保护级别,代码没有对硬件的直接控制权限,也不能直接访问地址的内存,程序是通过调用系统接口(System Call APIs)来达到访问硬件和内存,在这种保护模式下,即时程序发生崩溃也是可以恢复的,在电脑上大部分程序都是在,用户模式下运行的 用户态与内核态 用户态与内核态的概念就是 CPU 指令集权限的区别,进程中要读写 IO,必然会用到 ring 0 级别的 CPU 指令集,而此时 CPU 的指令集操作权限只有 ring 3,为了可以操作ring 0 级别的 CPU 指令集, CPU 切换指令集操作权限级别为 ring 0,CPU 再执行相应的 ring 0 级别的 CPU 指令集(内核代码),执行的内核代码会使用当前进程的内核栈。 ...

January 16, 2026