September 19, 2020
Golang开发中中使用GitHub私有仓库
"\u003cp\u003e私有仓库地址为\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egithub.com/cfanbo/websocket\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"一设置私有环境变量-goprivate\"\u003e一、设置私有环境变量 GOPRIVATE\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ go env -w GOPRIVATE=github.com/cfanbo/websocket\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e对于为什么需要设置 GOPRIMARY 变量,可以参考 \u003ca href=\"https://gocn.vip/topics/9904\"\u003e这里\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e对于GOPRIVATE值级别分为仓库级别和账号级别。\u003c/p\u003e\n\u003cp\u003e如果只有一个仓库,直接设置为仓库地址即可。如果有多个私有仓库的话,使用”,”分开,都在这个账号下,也可以将值设置为账号级别,这样账号下的所有私有仓库都可以正常访问。如 \u003ca href=\"http://github.com/cfanbo\"\u003ehttp://github.com/cfanbo\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如果不想每次都重新设置,我们也可以利用通配符,例如:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ go env -w GOPRIVATE=\u0026#34;*.example.com\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样子设置的话,所有模块路径为 example.com 的子域名(例如:git.example.com)都将不经过 Go module proxy 和 Go checksum database,需要注意的是不包括 example.com 本身。\u003c/p\u003e\n\u003cp\u003e国内用户访问仓库建议设置 GORPOXY …\u003c/p\u003e"
July 21, 2020
MySQL DBA利器innodb_ruby
"\u003ch2 id=\"innodb_ruby简介\"\u003einnodb_ruby简介\u003c/h2\u003e\n\u003cp\u003einnodb_ruby是一款用ruby写的用来分析 innodb 物理文件的专业DBA工具,可以通过这款工具来窥探innodb内部的一些结构。\n注意不要在生产环境中使用此工具,以避对线上服务造成影响。官方网址 \u003ca href=\"https://rubygems.org/gems/innodb_ruby\"\u003ehttps://rubygems.org/gems/innodb_ruby\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e注意如果(Linux)平台安装中遇到错误一般情况是由于缺少依赖库造成的,可以先安装 sudo apt-get install libxslt1-dev libxml2-dev 相关库。\u003c/p\u003e\n\u003ch2 id=\"命令语法\"\u003e命令语法\u003c/h2\u003e\n\u003cp\u003e在执行以下命令时,建议切换到MySQL 的 datadir 目录里。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esxf@ubuntu:~$ innodb_space --help\n\nUsage: innodb_space \u0026lt;options\u0026gt; \u0026lt;mode\u0026gt;\ninnodb_space \u0026lt;选项\u0026gt; \u0026lt;模式\u0026gt;\n命令主要分 options 和 mode 两大部分。\n\nInvocation examples:\n\n innodb_space -s ibdata1 [-T tname [-I …\u003c/code\u003e\u003c/pre\u003e"
June 6, 2020
利用jenkins+github实现应用的自动部署及回滚
"\u003cp\u003e对于jenkins的介绍这里不再详细写了,此教程只是为了让大家对部署和回滚原理有所了解。\u003c/p\u003e\n\u003ch2 id=\"一创建项目\"\u003e一、创建项目\u003c/h2\u003e\n\u003cp\u003e点击左侧的“New Item”,输入项目名称,如 rollback-demo。\u003c/p\u003e\n\u003cp\u003e选中 ” 丢弃旧的构建(Discard old builds)”项,在“策略(Strategy” 选择”\u003cem\u003eLog Rotation\u003c/em\u003e“, 并输入保留的最大构建个数。\u003c/p\u003e\n\u003ch2 id=\"二常规配置-05a2833329fee18776c5682a1068d288\"\u003e二、常规配置 \u003cimg src=\"https://blogstatic.haohtml.com/uploads/2020/06/16e3bc0afb4cf3f179f02fc598c220cd.png\" alt=\"05a2833329fee18776c5682a1068d288\"\u003e\u003c/h2\u003e\n\u003cp\u003e设置参数,点击”\u003cem\u003eAdd Parameter\u003c/em\u003e“,依次选择 “\u003cem\u003eChoice Parameter\u003c/em\u003e” 和 “\u003cem\u003eString Parameter\u003c/em\u003e“这两,填写如下\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2020/06/3193669cca6c1da1bdde929ec1666ff2.png\" alt=\"ac7d45c20f8b6777ab153ce75439dafb\"\u003e\u003c/p\u003e\n\u003cp\u003e这里的Name 项为参数名称,用户在操作的时候,会在deploy 和 rollback 两个值中选择一项。\u003c/p\u003e\n\u003ch2 id=\"三源码管理\"\u003e三、源码管理\u003c/h2\u003e\n\u003cp\u003e我们这里选择Git.并填写github.com上的项目地址,记得设置认证 Credentials。构建分支直接使用默认的 */master 即可以了。查看代码浏览器选择 githubweb,并填写项目的github地址。\u003c/p\u003e\n\u003ch2 id=\"四构建触发事件\"\u003e四、构建触发事件\u003c/h2\u003e\n\u003cp\u003e选择 “GitHub hook trigger for GITScm polling”,表示使用github webhook来 …\u003c/p\u003e"
May 27, 2020
golang中几种对goroutine的控制方法
"\u003cp\u003e我们先看一段代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc listen() {\n\tticker := time.NewTicker(time.Second)\n\tfor {\n\t\tselect {\n\t\tcase \u0026lt;-ticker.C:\n\t\t\tfmt.Println(time.Now())\n\t\t}\n\t}\n}\nfunc main() {\n\tgo listen()\n\ttime.Sleep(time.Second * 5)\n\tfmt.Println(\u0026#34;main exit\u0026#34;)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e非常简单的一个goroutine用法,想必每个gopher都看过的。\u003c/p\u003e\n\u003cp\u003e不过在实际生产中,我们几乎看不到这种用法的的身影,原因很简单,我们无法实现对goroutine的控制,而一般业务中我们需要根据不同情况对goroutine进行各种操作。\u003c/p\u003e\n\u003cp\u003e要实现对goroutine的控制,一般有以下两种。\u003c/p\u003e\n\u003ch2 id=\"一手动发送goroutine控制信号\"\u003e一、手动发送goroutine控制信号\u003c/h2\u003e\n\u003cp\u003e这里我们发送一个退出goroutine的信号。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// listen 利用只读chan控制goroutine的退出\nfunc listen(ch \u0026lt;-chan bool) {\n\tticker := …\u003c/code\u003e\u003c/pre\u003e"
May 3, 2020
Golang遍历切片删除元素引起恐慌问题
"\u003cp\u003e删除一个切片的部分元素, 告知切片操作:\u003ca href=\"http://cn.voidcc.com/question/p-mkbvfagj-hy.html\"\u003eGolang遍历切片恐慌时删除元素\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"问题描述\"\u003e问题描述\u003c/h2\u003e\n\u003cp\u003e代码( \u003ca href=\"https://go.dev/play/p/Kyvo7YQuw1m\"\u003e演示代码\u003c/a\u003e):\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\tslice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}\n\tfor i, value := range slice {\n\t\tif value%3 == 0 { // remove 3, 6, 9\n\t\t\tslice = append(slice[:i], slice[i+1:]...)\n\t\t}\n\t}\n\tfmt.Printf(\u0026#34;%v\u0026#34;, slice)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行结果\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epanic: runtime error: slice bounds out of range [8:6]\n\ngoroutine 1 [running]:\nmain.main()\n\t/tmp/sandbox2635969259/prog.go:11 +0x212\n\nProgram exited.\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"解决办法\"\u003e\u003cstrong\u003e解决办法:\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e以下是网友想到的几种办法\u003c/p\u003e\n\u003cp\u003e1、使用\u003ccode\u003egoto\u003c/code\u003e和标签\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc …\u003c/code\u003e\u003c/pre\u003e"
April 30, 2020
Golang中select用法导致CPU占用100%的问题分析
"\u003cp\u003e上一节( \u003ca href=\"https://blog.haohtml.com/archives/19670\"\u003egolang中有关select的几个知识点\u003c/a\u003e)中介绍了一些对于select{}的一些用法,今天介绍一下有关select在 \u003ccode\u003efor语句\u003c/code\u003e 中由于使用不当引起的CPU占用100% 的案例。\u003c/p\u003e\n\u003cp\u003e先看代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\nfunc main() {\n\tch := make(chan int, 10)\n\t// 读取chan\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase i := \u0026lt;-ch:\n\t\t\t\t// 只读取15次chan\n\t\t\t\tfmt.Println(i)\n\t\t\tdefault:\n\t\t\t\t// 读取15次chan以后的操作一直在这个空语句无任何IO操作的default条件里死循环,无法出让P,以保证一个GPM关系。\n\t\t\t\t// 而如果无default条件的话,则系统当读取完15次chan后,当前goroutine会发生 chan IO 阻塞, Go调度器根据GPM的调度关系,会将当前执行关系中的G切换出去,再从LRQ队列中取一个新的G,重新组成一 …\u003c/code\u003e\u003c/pre\u003e"
April 21, 2020
基于 GitHub Actions 实现 Golang 项目的自动构建部署
"\u003cp\u003e前几天 GitHub官网宣布 GitHub 的所有核心功能对所有人都免费开放,不得不说自从微软收购了GitHub后,确实带来了一些很大的改变。\u003c/p\u003e\n\u003cp\u003e以前有些项目考虑到协作关系的原因,虽然放在github上面,但对于一些项目的持续构建和部署一般是通过自行抢建Travis CI、jenkins等系统来实现。虽然去年推出了Actions用来代替它类三方系统,但感觉着还是不方便,必须有些核心功能无法使用,此消息的发布很有可能将这种格局打破。\u003c/p\u003e\n\u003cp\u003e本篇教程将介绍使用github的系列产品来实现项目的发布,构建,测试和部署,当然这仅仅是一个非常小的示例,有些地方后期可能会有更好的瞿恩方案。\u003c/p\u003e\n\u003cp\u003eGitHub Actions 是一款持续集成工具,包括clone代码,代码构建,程序测试和项目发布等一系列操作。更多内容参考:\u003c/p\u003e\n\u003cp\u003e如果你对CI/CD不了解的话,建议先找些文档看看。\u003c/p\u003e\n\u003cp\u003e项目源文件见\u003c/p\u003e\n\u003ch2 id=\"github-actions-术语\"\u003eGitHub Actions 术语\u003c/h2\u003e\n\u003cp\u003eGitHub Actions 相关的术语。\u003c/p\u003e\n\u003cp\u003e(1)workflow (工作流程):持续集成一次运行的过程,就是一个 workflow。\u003c/p\u003e\n\u003cp\u003e(2)job (任务):一个 workflow 由一个或 …\u003c/p\u003e"
March 28, 2020
k8s中的Service与Ingress
"\u003cp\u003e集群中的服务要想向外提供服务,就不得不提到Service和Ingress。 下面我们就介绍一下两者的区别和关系。\u003c/p\u003e\n\u003ch1 id=\"service\"\u003eService\u003c/h1\u003e\n\u003cp\u003e必须了解的一点是对 Service 的访问只有在 Kubernetes 集群内有效,而在集群之外是无效的。\u003c/p\u003e\n\u003cp\u003eService可以看作是一组提供相同服务的Pod对外的访问接口。借助Service,应用可以方便地实现服务发现和负载均衡。对于Service 的工作原理请参考\u003c/p\u003e\n\u003cp\u003e当需要从集群外部访问k8s里的服务的时候,方式有四种:\u003ccode\u003eClusterIP\u003c/code\u003e(默认)、\u003ccode\u003eNodePort\u003c/code\u003e、\u003ccode\u003eLoadBalancer\u003c/code\u003e、\u003ccode\u003eExternalName\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e下面我们介绍一下这几种方式的区别\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"一clusterip\"\u003e\u003cstrong\u003e一、ClusterIP\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e该方式是指通过集群的内部 IP 暴露服务,但此服务只能够在集群内部可以访问,这种方式也是默认的 ServiceType。\u003c/p\u003e\n\u003cp\u003e我们先看一下最简单的Service定义\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eapiVersion: v1\nkind: Service\nmetadata:\n name: hostnames\nspec:\n selector:\n app: hostnames\n ports:\n - name: …\u003c/code\u003e\u003c/pre\u003e"
March 28, 2020
mac下利用minikube安装Kubernetes环境
"\u003cp\u003e本机为mac环境,安装有brew工具,所以为了方便这里直接使用brew来安装minikube工具。同时本机已经安装过VirtualBox虚拟机软件。\u003c/p\u003e\n\u003cp\u003eminikube是一款专门用来创建k8s 集群的工具。\u003c/p\u003e\n\u003ch2 id=\"一安装minikube\"\u003e一、安装minikube\u003c/h2\u003e\n\u003cp\u003e参考 , 在安装minkube之前建议先了解一下minikube需要的环境。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e先安装一个虚拟化管理系统,如果还未安装,则在 HyperKit、VirtualBox 或 VMware Fusion 三个中任选一个即可,这里我选择了VirtualBox。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如果你想使用hyperkit的话,可以直接执行 \u003cstrong\u003ebrew install hyperkit\u003c/strong\u003e 即可。\u003c/p\u003e\n\u003cp\u003e对于支持的driver_name有效值参考, 目前\u003cstrong\u003edocker\u003c/strong\u003e尚处于实现阶段。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install minikube\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e查看版本号\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ minikube version\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eminikube version: v1.8.2\ncommit: eb13446e786c9ef70cb0a9f85a633194e62396a1\u003c/p\u003e\n\u003cp\u003e安装kubectl命令行工具\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install kubectl\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"二启动minikube-创建集群\"\u003e二、启 …\u003c/h2\u003e"
March 27, 2020
Golang中的限速器 time/rate
"\u003cp\u003e在高并发的系统中,限流已作为必不可少的功能,而常见的限流算法有:计数器、滑动窗口、令牌桶、漏斗(漏桶)。其中滑动窗口算法、令牌桶和漏斗算法应用最为广泛。\u003c/p\u003e\n\u003ch2 id=\"常见限流算法\"\u003e常见限流算法\u003c/h2\u003e\n\u003cp\u003e这里不再对 \u003ccode\u003e计数器算法\u003c/code\u003e 和 \u003ccode\u003e滑动窗口\u003c/code\u003e 算法一一介绍,有兴趣的同学可以参考其它相关文章。\u003c/p\u003e\n\u003ch3 id=\"漏斗算法\"\u003e漏斗算法\u003c/h3\u003e\n\u003cp\u003e漏斗算法很容易理解,它就像有一个漏斗容器一样,漏斗上面一直往容器里倒水(请求),漏斗下方以\u003cstrong\u003e固定速率\u003c/strong\u003e一直流出(消费)。如果漏斗容器满的情况下,再倒入的水就会溢出,此时表示新的请求将被丢弃。可以看到这种算法在应对大的突发流量时,会造成部分请求弃用丢失。\u003c/p\u003e\n\u003cp\u003e可以看出漏斗算法能强行限制数据的传输速率。\u003cimg src=\"https://blog.haohtml.com/wp-content/uploads/2020/03/rate-limit.png\" alt=\"\"\u003e漏斗算法\u003c/p\u003e\n\u003ch3 id=\"令牌桶算法\"\u003e令牌桶算法\u003c/h3\u003e\n\u003cp\u003e从某种意义上来说,令牌算法是对漏斗算法的一种改进。对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发情况。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。\u003c/p\u003e\n\u003cp\u003e令牌桶算法是指一个固定大小的桶,可以存放的令牌的最大个数也是固定的。此算法以一种\u003cstrong\u003e固定速率\u003c/strong\u003e不断的往桶中存放令牌,而每次请求调用前必须先从桶中获取令牌才可以。否则进行拒绝或等待,直到获取到有效令牌为止。如果桶内的令牌数量已达到桶的最 …\u003c/p\u003e"
March 19, 2020
Golang中的两个定时器 ticker 和 timer
"\u003cp\u003eGolang中time包有两个定时器,分别为 \u003ccode\u003eticker\u003c/code\u003e 和 \u003ccode\u003etimer\u003c/code\u003e。两者都可以实现定时功能,但各自都有自己的使用场景。\u003c/p\u003e\n\u003ch2 id=\"ticker定时器\"\u003eTicker定时器\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\nfunc main() {\n // Ticker 包含一个通道字段C,每隔时间段 d 就向该通道发送当时系统时间。\n // 它会调整时间间隔或者丢弃 tick 信息以适应反应慢的接收者。\n // 如果d \u0026lt;= 0会触发panic。关闭该 Ticker 可以释放相关资源。\n\n\tticker1 := time.NewTicker(5 * time.Second)\n\t// 一定要调用Stop(),回收资源\n\tdefer ticker1.Stop()\n\tgo func(t *time.Ticker) {\n\t\tfor {\n\t\t\t// 每5秒中从chan t.C 中读取一次\n\t\t\t\u0026lt;-t.C\n\t\t\tfmt.Println(\u0026#34;Ticker:\u0026#34;, …\u003c/code\u003e\u003c/pre\u003e"
March 4, 2020
认识虚拟内存
"\u003ch2 id=\"什么是虚拟内存\"\u003e什么是虚拟内存\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98/101812\"\u003e虚拟内存\u003c/a\u003e是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。\u003c/p\u003e\n\u003ch2 id=\"为什么需要虚拟内存\"\u003e为什么需要虚拟内存\u003c/h2\u003e\n\u003cp\u003e我们知道程序执行指令的时候,程序计数器是顺序地一条一条指令执行下去,这一条条指令就需要连续地存储在一起,所以就需要这块内存是连续的。物理内存是有限的,如果多个程序同时运行的话,访问同一个物理地址的话,就有可能内存地址冲突,怎么办呢?\u003c/p\u003e\n\u003cp\u003e这时就需要虚拟内存发挥的作用了,程序里有指令和各种内存地址,系统从物理内存申请一段地址,与这个程序指令里用到的内存地址建立映射关系,这样实际程序指令执行的时候,会通过虚拟内存地址,找到对应的物理内存地址执行。对于任何一个程序来说,它看到的都是同样的内存地址。我们只需要维护一个虚拟内存到物理内存的映射表即可。\u003c/p\u003e\n\u003cp\u003e这种从物理内存申请一段地址建立映射的方法,我们称其为\u003cstrong\u003e内存分段\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e看似解决了上面的问题,但这里又引起了新的问 …\u003c/p\u003e"
January 18, 2020
Golang中的变量逃逸问题 变量去哪了?
"\u003cp\u003e参考阅读 \u003ca href=\"https://mp.weixin.qq.com/s/ashgWyb-w4fT47xX60yNFA\"\u003ehttps://mp.weixin.qq.com/s/ashgWyb-w4fT47xX60yNFA\u003c/a\u003e\u003c/p\u003e"
January 18, 2020
Golang中关于defer语句理解的一道题
"\u003ch2 id=\"示例\"\u003e示例\u003c/h2\u003e\n\u003cp\u003e我们先看一下源代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc f(n int) (r int) {\n\tdefer func() {\n\t\tr += n\n\t\trecover()\n\t}()\n\n\tvar fc func()\n\tdefer fc()\n\tfc = func() {\n\t\tr += 2\n\t}\n\n\treturn n + 1\n}\n\nfunc main() {\n\tfmt.Println(f(3))\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e大家感觉着打印的值是多少呢?5、9还是7?执行完以后发现是7。好像与多数理解的有些出入,为什么是7,而不是9呢。下面我们来分析一下。\u003c/p\u003e\n\u003ch2 id=\"问题分析\"\u003e问题分析\u003c/h2\u003e\n\u003cp\u003e对于defer执行的顺序是FIFO这一点都很清楚,我们只需要看搞懂f()函数的执行顺序就行了。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e执行顺序为:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e注册第1个defer 函数, 这里为匿名函数,函数体为 “func() { r += n recover() }()”,内部对应一个函数指针。这里延时函数所有相关的操作一步完成。\u003c/li\u003e\n\u003cli\u003e注册第2个defer函数,函数名为fc(),无函数体, 函数指针为\u003cstrong\u003enil\u003c/strong\u003e(也有可能指针不会空,但指针指向的内容非函数体 …\u003c/li\u003e\u003c/ol\u003e"
January 15, 2020
开发者必知redis知识点
"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e剖析Redis常用数据类型对应的数据结构 \u003ca href=\"https://time.geekbang.org/column/article/79159\"\u003ehttps://time.geekbang.org/column/article/79159\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis中的COW(Copy-On-Write) \u003ca href=\"https://www.jianshu.com/p/b2fb2ee5e3a0\"\u003ehttps://www.jianshu.com/p/b2fb2ee5e3a0\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis常用有哪些数据类型及每种数据类型的使用场景有哪些 \u003ca href=\"https://www.cnblogs.com/tqlin/p/10478459.html\"\u003ehttps://www.cnblogs.com/tqlin/p/10478459.html\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果存储一个JSON数据时,选择hash还是string 存储数据? \u003ca href=\"https://segmentfault.com/a/1190000019552836\"\u003ehttps://segmentfault.com/a/1190000019552836\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis与memcache的区别 \u003ca href=\"https://www.cnblogs.com/JavaBlackHole/p/7726195.html\"\u003ehttps://www.cnblogs.com/JavaBlackHole/p/7726195.html\u003c/a\u003e \u003ca href=\"https://blog.csdn.net/qq_34126805/article/details/81748107\"\u003ehttps://blog.csdn.net/qq_34126805/article/details/81748107\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis支持多CPU吗?如何发挥多cpu? …\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"