在运行 Go 程序时重新加载配置表
Posted
技术标签:
【中文标题】在运行 Go 程序时重新加载配置表【英文标题】:Reload config table in running Go program 【发布时间】:2021-06-13 12:52:00 【问题描述】:我有一个具有多个 HTTP 处理程序包装器的 Web 服务器。其中之一是 ACL,它作为结构数组从 CSV 加载并传递给 ACL HTTP 处理程序。我希望能够更改 csv 文件以更新新的过滤器条目,而无需重新启动 Web 服务器。
我尝试添加标志,然后使用删除数组的布尔值调用它,并通过调用新的 csv 文件重新加载它。但这并没有真正起作用,它没有调用正在运行的进程中的现有数组表。
实现这一目标的最佳方法是什么?这是我的程序结构,我只是想避免在必须更新 ACL 时重新启动 Web 服务器。我可以使用单独的键值数据库,但在这个阶段我必须保持简单,因为服务器不属于我。
func main()
ACL := aclGroup()
mux := http.NewServeMux()
srv := &http.Server
Handler: aclAction(logRequestHandler(mux), ACL),
Addr: listen,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 5 * time.Second,
MaxHeaderBytes: 1 << 20,
...
func aclAction(h http.Handler, acl []*ACLlist) http.Handler
...
【问题讨论】:
【参考方案1】:一种方法是传递aclAction
一个将返回当前ACLList
的函数,而不是传递ACLList
本身。每当处理程序需要列表时,它应该调用函数来获取它。这样做可以相对简单地实现更新列表的代码(但要确保它是线程安全的!)并且新列表将在下次请求时返回。
这是一个简单的(有些做作和简化的)示例;试试the playground:
package main
import (
"fmt"
"sync"
"time"
)
type ACLlist struct
text string
// For now the ACL List is stored in a global variable; the true structure is likely to be a bit more complex
var currentList []ACLlist
var mu sync.Mutex
func main()
currentList = []ACLlist"one"
go aclAction(aclGroup)
time.Sleep(time.Millisecond) // Give go routine time to get one value
// Lets update the list (in reality this may run on a timer or you might watch a file)
mu.Lock()
currentList = []ACLlist"one", "two"
mu.Unlock()
// Give the go routine time to request the list again
time.Sleep(10 * time.Millisecond)
// aclGroup returns the current ACL List
func aclGroup() []ACLlist
mu.Lock()
defer mu.Unlock()
return currentList
// aclAction - accepts a function which will be called when the current ACL list is needed
func aclAction(getACL func() []ACLlist)
fmt.Printf("First call: %#v\n", getACL())
time.Sleep(5 * time.Millisecond)
fmt.Printf("Second Call: %#v]\n", getACL())
注意:一种潮汐方法是创建一个具有管理更新功能的 ACLListManager
结构和一个传递给 aclAction
的 getter 方法,但这会使示例代码复杂化。
【讨论】:
谢谢英国人!!我的初始代码与您所说的有些相似,aclAction 处理程序调用另一个加载 ACLlist 的函数(它调用另一个函数来加载本地 csv 文件)。读取太多,每个请求都会触发我认为效率不高的文件读取。我想我明白你的意思,让我重新修改并尝试修改想法。 不需要每次都读取文件;我通常会启动一个不时读取它的 goroutine(例如每 10 分钟)。另一种方法是存储读取配置的时间以及当新请求进入时检查它是否太旧并在需要时获取新副本(请小心,因为在刷新它时可能会出现另一个请求,因此请使用sync.Once
或类似的)。
谢谢英国人。我通过将数组的指针和 ACL 传递给处理程序来修改配置。我在 GO 中意识到,当您将数组作为参数传递给函数时,它不会被引用。然后我创建一个更新数组的函数,并有一个可以通过 web 调用的钩子,它将触发重新加载数组。这样,仅当 csv 更新并手动触发时才重新加载。感谢您提出所有想法,如果没有这些想法,它就无法发挥作用。
不用担心;请注意,您确实需要小心一点,以确保您最终不会参加比赛(请参阅question)。
啊...感谢您指出这一点,非常有用且及时的信息!以上是关于在运行 Go 程序时重新加载配置表的主要内容,如果未能解决你的问题,请参考以下文章
在运行时延迟初始化 Spring Security + 重新加载 Spring Security 配置