在使用 docker-compose down
命令停止容器后,再使用 docker-compose up
命令启动容器时,默认情况下不会重新编译镜像。
docker-compose down
命令会停止并移除由 docker-compose up
启动的容器,但不会删除镜像。当您使用 docker-compose up
命令重新启动容器时,它会尝试使用已经存在的镜像来创建和启动容器。
如果在重新启动容器时想要确保使用最新的镜像,可以使用 --build
选项来强制重新构建镜像。例如:
1 |
|
这将重新构建所有在 docker-compose.yml
文件中定义的服务的镜像,并使用新构建的镜像来创建和启动容器。
请注意,重新构建镜像可能需要一些时间,特别是在镜像的构建过程中涉及到较大的依赖项下载或编译时。如果您只想重新启动容器而不重新构建镜像,可以省略 --build
选项。
另外,如果需要同时停止并移除容器,并重新构建镜像,可以使用以下命令:
1 |
|
上述命令会停止并移除容器,同时删除关联的卷和所有镜像,然后重新构建镜像并启动容器。
]]>当你的 MySQL 数据库中的表变得越来越大时,你可能需要考虑拆分表以提高性能。在本文中,我们将讨论如何拆分 MySQL 表。
以下是一些拆分表的方法:
垂直拆分是将一个大表拆分成多个小表的过程,每个小表包含原始表的一部分列。这种方法通常用于将大型、稀疏的表拆分成多个小型、密集的表。例如,可以将一个包含用户基本信息和订单信息的表拆分成两个表,一个包含用户基本信息,另一个包含订单信息。
水平拆分是将一个大表拆分成多个小表的过程,每个小表包含原始表的一部分行。这种方法通常用于将大规模的表拆分成多个小型、易于管理的表。例如,可以将一个包含所有用户订单的表拆分成多个包含每个用户订单的表。
分区是将一个大表分成多个小型表的过程,每个小表包含原始表的一部分行。这种方法通常用于处理大型、高并发的表。例如,可以将一个包含所有用户订单的表分成每个月的订单表。
可以将垂直和水平拆分结合起来,以更好地管理和分配表的数据。例如,可以将一个包含用户基本信息和订单信息的表拆分成多个小型的表,每个表包含某个用户的基本信息和订单信息。
在拆分表之前,需要考虑以下事项:
表之间的关系:在拆分表之前,需要考虑表之间的关系。如果表之间有外键约束,需要确保在拆分表之后这些约束仍然能够被满足。
数据一致性:在拆分表之后,需要确保数据的一致性。如果表之间有关联,需要确保在拆分表之后这些关联仍然能够被满足。
查询优化:在拆分表之后,需要优化查询以确保查询性能不受影响。
垂直拆分是将一个大表拆分成多个小表的过程,每个小表包含原始表的一部分列。这种方法通常用于将大型、稀疏的表拆分成多个小型、密集的表。例如,可以将一个包含用户基本信息和订单信息的表拆分成两个表,一个包含用户基本信息,另一个包含订单信息。
水平拆分是将一个大表拆分成多个小表的过程,每个小表包含原始表的一部分行。这种方法通常用于将大规模的表拆分成多个小型、易于管理的表。例如,可以将一个包含所有用户订单的表拆分成多个包含每个用户订单的表。
分区是将一个大表分成多个小型表的过程,每个小表包含原始表的一部分行。这种方法通常用于处理大型、高并发的表。例如,可以将一个包含所有用户订单的表分成每个月的订单表。
可以将垂直和水平拆分结合起来,以更好地管理和分配表的数据。例如,可以将一个包含用户基本信息和订单信息的表拆分成多个小型的表,每个表包含某个用户的基本信息和订单信息。
总体来说,选择何种拆分表的方式需要根据具体的情况来决定。可以根据表的大小、查询需求、数据冗余度等因素来选择最适合的拆分方式。拆分表的过程需要慎重考虑,以确保数据的一致性和查询性能的提高。
]]>当我们需要在消息传递系统中实现延迟队列时,RabbitMQ 是一个常用的解决方案。在本文中,我们将讨论如何使用 RabbitMQ 来实现延迟队列,并提供支持 Hexo 的 Markdown 格式。
在消息传递系统中,延迟队列(Delayed Queue)是指一种消息队列,它可以在一定时间后自动将消息发送到消费者。这种队列通常用于处理需要一定时间才能被处理的任务,例如定时任务、延迟通知等。
RabbitMQ 是一个流行的开源消息代理,它支持消息传递的多种模式,包括发布/订阅、点对点、RPC 等。它还支持多种语言的客户端库,例如 Java、Python、.NET 等。
在 RabbitMQ 中,我们可以使用 x-delayed-message
插件来实现延迟队列的功能。该插件基于 Exchange 类型实现,并提供了一个自定义的 Exchange 类型 x-delayed-message
,它可以根据消息的延迟时间将消息路由到相应的队列。
下面是使用 RabbitMQ 实现延迟队列的步骤:
x-delayed-message
插件首先,我们需要安装 x-delayed-message
插件。该插件可以在 RabbitMQ 的官方 GitHub 仓库中找到。下载后,将其放置在 RabbitMQ 的 plugins
目录下,并使用 rabbitmq-plugins enable
命令启用该插件。
x-delayed-message
类型的 Exchange在 RabbitMQ 中,我们需要创建一个 Exchange,该 Exchange 的类型为 x-delayed-message
。这可以通过在 RabbitMQ 的管理控制台中定义 Exchange 来完成。
在 RabbitMQ 中,我们可以使用消息的 Headers 属性来设置消息的延迟时间。具体来说,我们可以在消息的 Headers 属性中添加一个名为 x-delay
的字段,并将其设置为延迟的毫秒数。例如,如果我们想要将消息延迟 5 秒钟,我们可以将 x-delay
字段设置为 5000。
在 RabbitMQ 中,我们可以创建一个队列,并将其绑定到 x-delayed-message
Exchange 上,以便在消息到达时自动消费该消息。
在消费者端,我们可以使用 RabbitMQ 的客户端库来从队列中获取消息。在获取消息时,我们需要设置 noAck
参数为 false
,以确保消息在成功处理后被确认。
下面是一个使用 RabbitMQ 实现延迟队列的示例代码,使用 Python 语言编写:
1 |
|
RabbitMQ的基本概念包括以下几个方面:
消息是应用程序之间传递的信息单元,可以包含任意类型的数据。在RabbitMQ中,消息由生产者发送到交换机,并通过队列传递给消费者。
生产者是消息发送方,它将消息发送到交换机,交换机根据指定的路由规则将消息路由到队列中。
消费者是消息接收方,它从队列中获取消息并进行处理。
队列是消息的存储和传递载体。生产者将消息发送到队列中,消费者从队列中获取消息进行处理。
交换机是消息路由的核心,它接收生产者发送的消息,并根据指定的路由规则将消息路由到相应的队列中。
绑定是将交换机和队列关联起来的过程。通过绑定,交换机可以将消息路由到相应的队列中。
路由键是交换机根据指定的路由规则将消息路由到相应队列的关键字。队列和交换机之间可以绑定多个路由键,消息发送方在发送消息时,需要指定消息的路由键。
RabbitMQ可以用于多种场景,包括但不限于以下几个方面:
异步任务处理是RabbitMQ的一个典型使用场景。生产者可以将任务消息发送到队列中,消费者从队列中获取消息并进行处理。通过异步任务处理,可以提高任务处理效率和系统的可靠性。
RabbitMQ可以用于分布式系统之间的数据交换和通信。不同的系统可以通过RabbitMQ进行消息传递,实现解耦和系统之间的松耦合。
RabbitMQ可以用于日志收集和分发。生产者将日志消息发送到队列中,消费者从队列中获取消息并进行处理,将日志消息写入到日志文件或者发送到其他系统中。
RabbitMQ的架构包括以下几个核心组件:
Broker是RabbitMQ的核心组件,它接收生产者发送的消息,并根据指定的路由规则将消息路由到相应的队列中。Broker还负责管理队列和交换机之间的绑定关系,并确保消息传递的可靠性和高效性。
Virtual Host是RabbitMQ的逻辑隔离单元,它可以将不同的应用程序和业务逻辑分离开来,确保消息传递的隔离性和安全性。
Exchange是消息路由的核心,它接收生产者发送的消息,并根据指定的路由规则将消息路由到相应的队列中。Exchange可以根据不同的路由规则将消息路由到多个队列中。
Queue是消息的存储和传递载体,生产者将消息发送到队列中,消费者从队列中获取消息进行处理。
Connection是RabbitMQ的连接单元,它实现了生产者和消费者与Broker之间的连接和通信。Connection可以进行安全认证和加密传输,确保消息传递的安全性和可靠性。
Channel是Connection中的逻辑通道,它可以进行多路复用和流控等操作,提高消息传递的效率和可靠性。
使用RabbitMQ进行消息传递需要以下几个步骤:
安装RabbitMQ并启动Broker。
创建Virtual Host、Exchange和Queue,并进行绑定操作。
编写生产者和消费者程序,连接到Broker,并进行消息的发送和接收。
在实际使用中,可以根据具体的场景和需求进行配置和优化,以提高消息传递的效率和可靠性。
总的来说,RabbitMQ是一个功能强大的开源消息队列系统,可以用于多种场景和应用程序之间的数据交换和通信。熟练掌握RabbitMQ的基本概念、使用场景和架构,可以帮助开发者更好地进行消息传递和系统集成。
]]>composer 提供的 autoload 机制使得我们组织代码和引入新类库非常方便,但是也使项目的性能下降了不少 。
composer autoload 慢的主要原因在于来自对 PSR-0 和 PSR-4 的支持,加载器得到一个类名时需要到文件系统里查找对应的类文件位置,这导致了很大的性能损耗,当然这在我们开发时还是有用的,这样我们添加的新的类文件就能即时生效。 但是在生产模式下,我们想要最快的找到这些类文件,并加载他们。
因此 composer 提供了几种优化策略,下面说明下这些优化策略。
-o 等同于 –optimize
composer dump-autoload -o
原理:
这个命令的本质是将 PSR-4/PSR-0 的规则转化为了 classmap 的规则, 因为 classmap 中包含了所有类名与类文件路径的对应关系,所以加载器不再需要到文件系统中查找文件了。可以从 classmap 中直接找到类文件的路径。
注意事项
建议开启 opcache , 这样会极大的加速类的加载。
php5.5 以后的版本中默认自带了 opcache 。
这个命令并没有考虑到当在 classmap 中找不到目标类时的情况,当加载器找不到目标类时,仍旧会根据PSR-4/PSR-0 的规则去文件系统中查找
第二层级(Level-2/A)优化:权威的(Authoritative)classmap
-a 等同于 –classmap-authoritative
composer dump-autoload -a
原理
执行这个命令隐含的也执行了 Level-1 的命令, 即同样也是生成了 classmap,区别在于当加载器在 classmap 中找不到目标类时,不会再去文件系统中查找(即隐含的认为 classmap 中就是所有合法的类,不会有其他的类了,除非法调用)
注意事项
如果你的项目在运行时会生成类,使用这个优化策略会找不到这些新生成的类。
composer dump-autoload --apc
原理:
使用这个策略需要安装 apcu 扩展。
apcu 可以理解为一块内存,并且可以在多进程中共享。
这种策略是为了在 Level-1 中 classmap 中找不到目标类时,将在文件系统中找到的结果存储到共享内存中, 当下次再查找时就可以从内存中直接返回,不用再去文件系统中再次查找。
在生产环境下,这个策略一般也会与 Level-1 一起使用, 执行composer dump-autoload -o –apcu, 这样,即使生产环境下生成了新的类,只需要文件系统中查找一次即可被缓存 , 弥补了Level-2/A 的缺陷。
要根据自己项目的实际情况来选择策略,如果你的项目在运行时不会生成类文件并且需要 composer 的 autoload 去加载,那么使用 Level-2/A 即可,否则使用 Level-1 及 Level-2/B是比较好的选择。
几个提示
将其放入**/lib/systemd/system**列文件夹中。
1 |
|
1 |
|
PS: 注意上面的ExecStart/ExecReload/ExecStop 必须 以自己的为主
所对应的key说明如下
1 |
|
注意:[Service]的启动、重启、停止命令全部要求使用绝对路径
[Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3
1 |
|
要使用,你需要手动开启:
1 |
|
要将 SQL 输出到屏幕,你可以使用:
1 |
|
最近的查询语句将位于数组的底部。
类似下面这样:
1 |
|
对于 laravel 5.5.X
如果你希望接收应用程序执行的每个 SQL 查询,可以使用 listen 方法。 此方法对于记录查询或调试很有用。 你可以在服务提供者中注册你的查询侦听器:
1 |
|
你可以使用 toSql() 方法做以下的事情,
1 |
|
Output:
1 |
|
想要绑定数据?使用以下方法:
1 |
|
输出:
1 |
|
我们来自定义一个 ‘macroable’ 带有获取绑定数据的 SQL 查询替换 toSql.
添加以下宏方法到 AppServiceProvider boot().
1 |
|
为 Eloquent Builder 添加别名. (Laravel 5.4+)
1 |
|
然后像往常一样调试. (Laravel 5.4+)
E.g. Query Builder
1 |
|
E.g. Eloquent Builder
1 |
|
常用方式
1 |
|
试用gorm时候,唯一索引重复写入mysql会报错1062,用下面方式来捕捉错误
1 |
|
1 |
|
安装yum-utils, 获取yum-complete-transaction命令
1 |
|
清除之前安装遗留的问题
1 |
|
1 |
|
为什么需要sync.WaitGroup?
goroutine并发执行的时候需要一段时间,由于是串行编译运行的,有时会出现并发程序还没执行完毕,而后方的程序已经执行而导致的错误。通常的处理方式是调用time.sleep
延迟并发执行时间
我们开启了1s的等待时间,但这种方法有个问题,我们并不知道并发执行的具体时间,很容易造成等待过久的时间浪费。
sync.WaitGroup的特点
WaitGroup是一个结构体,用来统计goroutine是否执行完毕,它实现了三个方法Add()、Done()、Wait()。
三个函数的主要作用:
wg.Add()设置等待组的数量(counter)。
wg.Done()当子goroutine运行结束,counter-1。
wg.Wait()等待组数量=0,主程序重新启动。counter>0时,主程序阻塞。
1 |
|
注意
等待组的数量必须和goroutine启动数量保持一直,否则会出现错误
add()
数量>goroutine数量
1 |
|
1 |
|
所有goroutine都已经运行完毕,主程序还处于阻塞状态,出现死锁
]]>设置代理
1 |
|
关于https
经过上面设置使用了http开头的源,因此不需要设https_proxy了,否则还要增加一句:
1 |
|
代理用户名和密码
1 |
|
取消代理
1 |
|
nrm 是一个 NPM 源管理器,允许你快速地在如下 NPM 源间切换:
taobao
npm
cnpm
strongloop
enropean
australia
nodejitsu
1 |
|
列出可用的源:
1 |
|
切换:
1 |
|
增加源:
1 |
|
删除源:
1 |
|
测试速度:
1 |
|
所有日志将显示在STDERR上并保存到当前工作目录中的npm-debug.log。
1 |
|
如果使用下面命令将实时显示日志+将日志保存到其运行的目录。
1 |
|
对于永久解决方案,只需编辑
1 |
|
并添加
1 |
|
这样得话。现在每个npm命令都会显示详细的日志。
]]>参考:https://getcomposer.org/doc/05-repositories.md#path
1 |
|
1 |
|
个人常用函数
1 |
|
使用方法:
1 |
|
平时常用到2种方式做并发请求.
简单粗暴, 一次请求开一个线程, 线程中完成请求与响应处理.
优雅一点, 限制线程池, 以master-worker的方式处理并发, 最后又把响应统一处理.
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
Go 语言又称 Golang,由 Google 公司于 2009 年发布,近几年伴随着云计算、微服务、分布式的发展而迅速崛起,跻身主流编程语言之列,和 Java 类似,它是一门静态的、强类型的、编译型编程语言,为并发而生,所以天生适用于并发编程(网络编程)。
目前 Go 语言支持 Windows、Linux 等多个平台,也可以直接在 Android 和 iOS 等移动端执行,从业务角度来看,Go 语言在云计算、微服务、大数据、区块链、物联网、人工智能等领域都有广泛的应用。
Go 设计的初衷是替代 C,所以二者有很多相似之处,但 Go 做的更多:
因此,相对 C/C++,Go 开发效率更高。
适用场景不同:
Go 不适用于高性能嵌入式系统,因为嵌入式系统资源有限,而 Go 运行时调度线程和垃圾回收需要额外的开销。至今没有提供 GUI SDK,所以也不适用于桌面程序开发。
Java 程序编译之后需要安装额外的 Java runtime 运行,Java 程序的可移植性依赖 Java runtime,Go 不需要,Go 运行时已经包含在这个编译的二进制文件中了,这体现在部署上的区别就是需要在服务器安装 Java runtime,而 Go 只需要部署单文件即可。
PHP 是动态语言,而 Go 是静态语言,会做类型检查,可靠性更高。
开发 Web 应用时,PHP 通常躲在 Nginx/Apache 后面作为后台进程,Go 则提供了内置的 Web 服务器,完全可以直接在生产环境使用。
PHP 之所以要借助额外的 Web 服务器是因为对并发请求的处理,PHP 本身就没有多线程多进程机制,一次请求从头到位都是一个独立的进程,为了让基于 PHP 的 Web 应用支持并发请求,必须借助外部 Web 服务器。
而 Go 内置的 Web 服务器充分利用了 goroutine,对并发连接有很好的支持。此外,由于协程的本质是在在同一个进程中调度不同线程,所以还支持共享资源。
PHP 作为动态语言,性能不如 Go,如果要提升性能,必须通过 C 语言编写扩展,复杂度和学习成本太高。
语法简单,并发模型(Goroutine ),内存回收(GC),内存分配等
1 |
|
结构体成员是由一系列的成员变量构成.字段有以下特性:
Go 语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。
Go 语言的结构体与“类”都是复合结构体,但 Go 语言中结构体的内嵌配合接口比面向对象具有更高的扩展性和灵活性。
Go 语言不仅认为结构体能拥有方法,且每种自定义类型也可以拥有自己的方法。
使用Go语言的结构体内嵌实现对象特性组合
1 |
|
Go语言最大的特色就是从语言层面支持并发(Goroutine),Goroutine是Go中最基本的执行单元。事实上每一个Go程序至少有一个Goroutine:主Goroutine。当程序启动时,它会自动创建。
为了更好理解Goroutine,现讲一下线程和协程的概念
线程(Thread):有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程的切换一般也由操作系统调度。
协程(coroutine):又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。
和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。
Goroutine和其他语言的协程(coroutine)在使用方式上类似,但从字面意义上来看不同(一个是Goroutine,一个是coroutine),再就是协程是一种协作任务控制机制,在最简单的意义上,协程不是并发的,而Goroutine支持并发的。因此Goroutine可以理解为一种Go语言的协程。同时它可以运行在一个或多个线程上。
一、Go并发模型
Go实现了两种并发形式。第一种是大家普遍认知的:多线程共享内存。其实就是Java或者C++等语言中的多线程开发。另外一种是Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。
CSP并发模型是在1970年左右提出的概念,属于比较新的概念,不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。
普通的线程并发模型,就是像Java、C++、或者Python,他们线程间通信都是通过共享内存的方式来进行的。非常典型的方式就是,在访问共享数据(例如数组、Map、或者某个结构体或对象)的时候,通过锁来访问。Go中也实现了传统的线程并发模型。
Go的CSP并发模型,是通过goroutine
和channel
来实现的。
goroutine
是Go语言中并发的执行单位。有点抽象,其实就是和传统概念上的”线程“类似,可以理解为”线程“。channel
是Go语言中各个并发结构体(goroutine
)之前的通信机制。 通俗的讲,就是各个goroutine
之间通信的”管道“,有点类似于Linux中的管道。生成一个goroutine
的方式非常的简单:Go一下,就生成了。
1 |
|
通信机制channel
也很方便,传数据用channel <- data
,取数据用<-channel
。
在通信过程中,传数据channel <- data
和取数据<-channel
必然会成对出现,因为这边传,那边取,两个goroutine
之间才会实现通信。
而且正常情况下不管传还是取,必阻塞,直到另外的goroutine
传或者取为止。
不过也可以非阻塞接收数据
使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:
1 |
|
非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少
注意 main()本身也是运行了一个goroutine。
1 |
|
附 Go 语言学习路线图如下:
]]>使用ssh登陆 centos,特别的慢,等至少几十秒才登陆进去。
修改 /etc/ssh/sshd_config
配置,将 useDNS
的值设置为 no
,如果文件中没有,则末尾加入一段useDNS no
即可。再执行重启 sshd,命令 service restart sshd
,问题解决。