场景描述:

    在 Linux 服务器上,通过使用 Nginx 实现负载均衡,或者在阿里云直接购买负载均衡,根据配置的转发规则,不同的请求会被转发到其不同的服务器上进行处理。如果遇到需要上传图片的情况,那最后只有其中一台服务器存有这张图片,而其他服务器则没有。随后,如果请求获取这张图片,但是转发到的恰好是没有存有这张图片的服务器,那么请求就失败了。为了避免这类问题,就需要同步相应的目录上的文件。

Lsyncd 简述:

Lsyncd 是一个简单高效的文件同步工具,通过lua语言封装了 inotify 和 rsync 工具,采用了 Linux 内核(2.6.13 及以后)里的 inotify 触发机制,然后通过rsync去差异同步,达到实时的效果。

安装过程:

1、安装 lua 语言依赖包

yum install lua
yum install lua-devel

2、安装 Lsyncd

yum install lsyncd

这里一定要注意,最好安装最新的版本,笔者安装的版本是 2.2.2 。网上很多教程的版本是2.1.5 ,这个版本有 bug ,但在后续的版本里已经修复,直接安装即可。之后,你可以发现在 etc 目录下,不但多了 lsyncd.conf 配置文件,而且还多了 rsync 工具的配置文件 rsyncd.conf 。这说明 Lsyncd 工具确是使用 rsync 工具创建起来的,通过 rsync 去进行目录的差异同步。

远程前提:

通过 Lsyncd 工具同步负载均衡转发规则下的服务器,需要在涉及的服务器上都安装好 Lsyncd ,一般通过 SSH 远程登录,进行远程同步。因此,在远端被同步的服务器上开启 SSH 无密码登录,请注意用户身份,将对应的用户 user 公钥 id_rsa.pub 复制到被同步的服务器的 .ssh 文件目录下的 authorized_keys 文件里,最后测试是否可以无密码登陆。

如果要实现文件的双向同步,那就要对两台服务器进行差不多的 SSH 配置操作,就可以相互进行无密码登陆了。

chmod 600 /user/.ssh/id_rsa
ssh user@192.168.0.3

配置文件:

vi /etc/lsyncd.conf
----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync, but executing moves through on the target.
--
-- For more examples, see /usr/share/doc/lsyncd*/examples/
--
settings{logfile = "/var/log/lsyncd/lsyncd.log",statusFile = "/var/log/lsyncd/lsyncd.status",inotifyMode = "CloseWrite",maxProcesses = 10,nodaemon = false,maxDelays = 7
}
sync{default.rsync, source = "/data/wwwroot/default/application",target = "user@192.168.0.3:/data/wwwroot/default/application",init = false,delete = true,delay = 3,rsync = {binary = "/usr/bin/rsync",compress = true,archive = true,verbose = true}
}
sync{default.rsync,source = "/data/wwwroot/default/public",target = "user@192.168.0.3:/data/wwwroot/default/public",init = false,delete = true,delay = 3,rsync = {binary = "/usr/bin/rsync",compress = true,archive = true,verbose = true}
}
lsyncd /etc/lsyncd.conf

    如果要实现文件的双向同步,那就要对两台服务器进行差不多的 Lsyncd 配置操作,下面列出具体需要更改的参数。

logfile 本地存放 Lsyncd 日志的路径,一般直接使用默认的路径就可以了。

statusFile 本地存放 状态文件的路径,一般直接使用默认的路径就可以了。

source 本地源目录路径。

target 远程目的目录路径,注意这里的SSH远程同步写法。

其他参数具体解释(略)

注意事项:

运行 Lsyncd 工具后,可以到源目录下创建几个文本,查看是否能成功同步到远程的目的目录下。如果没有成功,可以到 /var/log/lsyncd/lsyncd.log 文件查看详情。

如果配置了 lsyncd.conf 文件,可以不配置 rsyncd.conf 了。

操作环境:

Linux version 3.10.0-693.11.6.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) ) #1 SMP Thu Jan 4 01:06:37 UTC 2018

附(lua语言配置示例,可忽略不看):

lalarm.lua
-----
-- User configuration file for lsyncd.
--
-- While this example does not do anything it shows
-- how user custom alarms can be now. It will log
-- "Beep!" every 5 seconds.
--
settings.nodaemon = truelocal function noAction (inlet)-- just discard any events that happes in source dir.inlet.discardEvent(inlet.getEvent())
end-----
-- Adds a watch to some not so large directory for this example.
local in1 = sync{source="/usr/local/etc/", action = noAction }local function myAlarm(timestamp, extra)log("Normal", extra.message)spawn(extra.inlet.createBlanketEvent(), "/bin/echo", extra.message)alarm(timestamp + 5, myAlarm, extra)
endalarm(now() + 5, myAlarm, {inlet = in1, message = "Beep"})
lbash.lua
-----
-- User configuration file for lsyncd.
--
-- This example uses local bash commands to keep two local
-- directory trees in sync.
--
settings {logfile         = "/tmp/lsyncd.log",statusFile      = "/tmp/lsyncd.stat",statusIntervall = 1,nodaemon        = true,
}-----
-- for testing purposes. prefix can be used to slow commands down.
-- prefix = "sleep 5 && "
--
prefix = ""-----
-- for testing purposes. uses bash command to hold local dirs in sync.
--
bash = {delay = 0,maxProcesses = 1,-- calls `cp -r SOURCE/* TARGET` only when there is something in SOURCE-- otherwise it deletes contents in the target if there.onStartup = [[
if [ "$(ls -A ^source)" ]; thencp -r ^source* ^target;
elseif [ "$(ls -A ^target)" ]; then rm -rf ^target/*; fi
fi]],onCreate = prefix..[[cp -r ^sourcePath ^targetPathdir]],onModify = prefix..[[cp -r ^sourcePath ^targetPathdir]],onDelete = prefix..[[rm -rf ^targetPath]],onMove   = prefix..[[mv ^o.targetPath ^d.targetPath]],
}sync{bash, source="src", target="/path/to/trg/"}
lecho.lua
-----
-- User configuration file for lsyncd.
--
-- This example uses just echos the operations
-------
-- for testing purposes. just echos what is happening.
--
echo = {maxProcesses = 1,delay = 1,onStartup = "/bin/echo telling about ^source",onAttrib  = "/bin/echo attrib ^pathname",onCreate  = "/bin/echo create ^pathname",onDelete  = "/bin/echo delete ^pathname",onModify  = "/bin/echo modify ^pathname",onMove    = "/bin/echo move ^o.pathname -> ^d.pathname",
}sync{echo, source="src", target="/path/to/trg/"}
lftp.lua
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- User configuration file for lsyncd.
--
--    Syncs with 'lftp'.
--
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~lftp = {------- Spawns rsync for a list of events--action = function(inlet)-- gets all events ready for syncinglocal elist = inlet.getEvents(function(event)return event.etype ~= 'Init' and event.etype ~= 'Blanket'end)------- replaces filter rule by literals--local function sub(p)if not p thenreturnendreturn p:gsub('%?', '\\?'):gsub('%*', '\\*'):gsub('%[', '\\['):gsub('%]', '\\]')endlocal config = inlet.getConfig()local commands = elist.getPaths(function(etype, path1, path2)if etype == 'Delete' thenif string.byte(path1, -1) == 47 thenreturn 'rm -r '..config.targetdir..sub(path1)elsereturn 'rm '..config.targetdir..sub(path1)endelseifetype == 'Create' oretype == 'Modify' oretype == 'Attrib'thenif string.byte(path1, -1) == 47 thenreturn 'mirror -R '..config.source..sub(path1)..' '..config.targetdir..sub(path1)elsereturn 'put '..config.source..sub(path1)..' -o '..config.targetdir..sub(path1)endendend)if #commands == 0 thenspawn(elist, '/bin/true')returnendcommands = table.concat(commands, ';\n')log('Normal', 'Calling lftp with commands\n', commands)spawn(elist, '/usr/bin/lftp','<', commands,'-u', config.user..','..config.pass, config.host)end,------- Spawns the recursive startup sync--init = function(event)local config = event.configlocal inlet = event.inletlocal excludes = inlet.getExcludes()local delete = nilif config.delete then delete = { '--delete', '--ignore-errors' }; endif #excludes ~= 0 thenerror('lftp does not work with excludes', 4)endlog('Normal', 'recursive startup lftp: ', config.source, ' to host: ', config.host)spawn(event, '/usr/bin/lftp','-c','open -u '..config.user..','..config.pass..' '..config.host..'; '..'mirror -R -e '..config.source..' '..config.targetdir..';')end,------- Checks the configuration.--prepare = function(config)if not config.host thenerror('lftps needs "host" configured', 4);endif not config.user thenerror('lftps needs "user" configured', 4);endif not config.pass thenerror('lftps needs "pass" configured', 4);endif not config.targetdir thenerror('lftp needs "targetdir" configured', 4)endif config.target thenerror('lftp needs NOT "target" configured', 4)endif config.exclude thenerror('lftp does not work with excludes', 4)endif config.rsyncOpts thenerror('lftp needs NOT "rsyncOpts" configured', 4)endif string.sub(config.targetdir, -1) == '/' thenerror('please make targetdir not end with a /', 4)endend,------- Exit codes for rsync.--exitcodes = {[  0] = 'ok',[  1] = 'ok',},------- Default delay--delay = 1,
}sync{lftp,host      = 'localhost',user      = 'test',pass      = 'test',source    = 'src',targetdir = '.',
}
lgforce.lua
-----
-- User configuration file for lsyncd.
--
-- This example refers to one common challenge in multiuser unix systems.
--
-- You have a shared directory for a set of users and you want
-- to ensure all users have read and write permissions on all
-- files in there. Unfortunally sometimes users mess with their
-- umask, and create files in there that are not read/write/deleteable
-- by others. Usually this involves frequent handfixes by a sysadmin,
-- or a cron job that recursively chmods/chowns the whole directory.
--
-- This is another approach to use lsyncd to continously fix permissions.
--
-- One second after a file is created/modified it checks for its permissions
-- and forces group permissions on it.
--
-- This example regards more the handcraft of bash scripting than lsyncd.
-- An alternative to this would be to load a Lua-Posix library and do the
-- permission changes right within the onAction handlers.----
-- forces this group.
--
fgroup = "staff"-----
-- script for all changes.
--
command =
-- checks if the group is the one enforced and sets them if not
[[
perm=`stat -c %A ^sourcePathname`
if [ `stat -c %G ^sourcePathname` != ]]..fgroup..[[ ]; then/bin/chgrp ]]..fgroup..[[ ^sourcePathname || /bin/true;
fi
]] ..-- checks if the group permissions are rw and sets them
[[
if [ `expr match $perm "....rw"` == 0 ]; then/bin/chmod g+rw ^sourcePathname || /bin/true;
fi
]] ..-- and forces the executable bit for directories.
[[
if [ -d ^sourcePathname ]; thenif [ `expr match $perm "......x"` == 0 ]; then/bin/chmod g+x ^^sourcePathname || /bin/true;fi
fi
]]-- on startup recursevily sets all group ownerships
-- all group permissions are set to rw
-- and to executable flag for directories
--
-- the carret as first char tells Lsycnd to call a shell altough it
-- starts with a slash otherwisw
--
startup =
[[^/bin/chgrp -R ]]..fgroup..[[ ^source || /bin/true &&
/bin/chmod -R g+rw ^source || /bin/true &&
/usr/bin/find ^source -type d | xargs chmod g+x
]]gforce = {maxProcesses = 99,delay        = 1,onStartup    = startup,onAttrib     = command,onCreate     = command,onModify     = command,-- does nothing on moves, they won't change permissionsonMove       = true,
}sync{gforce, source="/path/to/share"}
limagemagic.lua
----
-- Lsyncd user-script that creates a "magic" image converter directory.
--
-- This configuration will automatically convert all images that are placed
-- in the directory 'magicdir' all resulting images are placed in the same
-- directory!
--
-- Be sure to mkdir 'magicdir' first.-----
-- Fileformats:   .jpg  .gif  .png
--
local formats = { jpg=true, gif=true, png=true,  }convert = {delay = 0,maxProcesses = 99,action = function(inlet)local event = inlet.getEvent()if event.isdir then-- ignores events on dirsinlet.discardEvent(event)returnend-- extract extension and basefilenamelocal p    = event.pathnamelocal ext  = string.match(p, ".*%.([^.]+)$")local base = string.match(p, "(.*)%.[^.]+$")if not formats[ext] then-- an unknown extenionlog("Normal", "not doing something on ."..ext)inlet.discardEvent(event)returnend-- autoconvert on create and modifyif event.etype == "Create" or event.etype == "Modify" then-- builds one bash commandlocal cmd = ""-- do for all other extensionsfor k, _ in pairs(formats) doif k ~= ext then-- excludes files to be created, so no-- followup actions will occurinlet.addExclude(base..'.'..k)if cmd ~= ""  thencmd = cmd .. " && "endcmd = cmd..'/usr/bin/convert "'..event.source..p..'" "'..event.source..base..'.'..k..'" || /bin/true'endendlog("Normal", "Converting "..p)spawnShell(event, cmd)returnend-- deletes all formats if you delete oneif event.etype == "Delete" then-- builds one bash commandlocal cmd = ""-- do for all other extensionsfor k, _ in pairs(formats) doif k ~= ext then-- excludes files to be created, so no-- followup actions will occurinlet.addExclude(base..'.'..k)if cmd ~= ""  thencmd = cmd .. " && "endcmd = cmd..'rm "'..event.source..base..'.'..k..'" || /bin/true'endendlog("Normal", "Deleting all "..p)spawnShell(event, cmd)returnend-- ignores other events.inlet.discardEvent(event)end,------- Removes excludes when convertions are finished--collect = function(event, exitcode)local p     = event.pathnamelocal ext   = string.match(p, ".*%.([^.]+)$")local base  = string.match(p, "(.*)%.[^.]+$")local inlet = event.inletif event.etype == "Create" orevent.etype == "Modify" orevent.etype == "Delete"thenfor k, _ in pairs(formats) doinlet.rmExclude(base..'.'..k)endendend,------- Does not collapse anythingcollapse = function()return 3end,
}sync{convert, source="magicdir", subdirs=false}
lpostcmd.lua
-----
-- User configuration file for lsyncd.
-- This needs lsyncd >= 2.0.3
--
-- This configuration will execute a command on the remote host
-- after every successfullycompleted rsync operation.
-- for example to restart servlets on the target host or so.local rsyncpostcmd = {-- based on default rsync.default.rsync,checkgauge = {default.rsync.checkgauge,host = true,targetdir = true,target = true,postcmd = true,},-- for this config it is important to keep maxProcesses at 1, so-- the postcmds will only be spawned after the rsync completedmaxProcesses = 1,-- called whenever something is to be doneaction = function(inlet)local event = inlet.getEvent()local config = inlet.getConfig()-- if the event is a blanket event and not the startup,-- its there to spawn the webservice restart at the target.if event.etype == "Blanket" then-- uses rawget to test if "isPostcmd" has been set without-- triggering an error if not.local isPostcmd = rawget(event, "isPostcmd")if isPostcmd thenspawn(event, "/usr/bin/ssh",config.host, config.postcmd)returnelse-- this is the startup, forwards it to default routine.return default.rsync.action(inlet)enderror("this should never be reached")end-- for any other event, a blanket event is created that-- will stack on the queue and do the postcmd when its finishedlocal sync = inlet.createBlanketEvent()sync.isPostcmd = true-- the original event is simply forwarded to the normal action handlerreturn default.rsync.action(inlet)end,-- called when a process exited.-- this can be a rsync command, the startup rsync or the postcmdcollect = function(agent, exitcode)-- for the ssh commands 255 is network error -> try againlocal isPostcmd = rawget(agent, "isPostcmd")if not agent.isList and agent.etype == "Blanket" and isPostcmd thenif exitcode == 255 thenreturn "again"endreturnelse--- everything else, forward to default collection handlerreturn default.collect(agent,exitcode)enderror("this should never be reached")end,-- called before anything else-- builds the target from host and targetdirprepare = function(config, level, skipTarget)if not config.host thenerror("rsyncpostcmd neets 'host' configured", 4)endif not config.targetdir thenerror("rsyncpostcmd needs 'targetdir' configured", 4)endif not config.target thenconfig.target = config.host .. ":" .. config.targetdirendreturn default.rsync.prepare(config, level, skipTarget)end
}sync {rsyncpostcmd,source = "src",host = "beetle",targetdir = "/path/to/trg",postcmd = "/usr/local/bin/restart-servelt.sh",
}
lrsync.lua
----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync.
--
settings {statusFile = "/tmp/lsyncd.stat",statusInterval = 1,
}sync{default.rsync,source="src",target="trg",
}
lrsyncssh.lua
----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync, but executing moves through on the target.
--
sync{default.rsyncssh, source="src", host="localhost", targetdir="dst/"}
lsayirc.lua
-----
-- An Lsyncd+IRC-Bot Config
--
-- Logs into an IRC channel and tells there everything that happens in the
-- watched directory tree.
--
-- The challenge coding Lsyncd configs taking use of TCP sockets is
-- that they must not block! Otherwise Lsyncd will block, no longer
-- empty the kernels monitor queue, no longer collecting zombie processes,
-- no longer spawning processes (this example doesnt do any, but maybe you
-- might want to do that as well), blocking is just bad.
--
-- This demo codes just minimal IRC functionality.
-- it does not respond to anything else than IRC PING messages.
--
-- There is no flood control, if a lot happens the IRC server will disconnect
-- the bot.
--
-- Requires "luasocket" to be installed
require("socket")-- For demo reasons, do not detach
settings.nodaemon = true
hostname = "irc.freenode.org"
--hostname = "127.0.0.1"
port = 6667
nick = "lbot01"
chan = "##lfile01"-- this blocks until the connection is established
-- for once lets say this ok since Lsyncd didnt yet actually
-- start.
local ircSocket, err = socket.connect(hostname, port)
if not ircSocket thenlog("Error", "Cannot connect to IRC: ", err)terminate(-1)
end-- from now on, the socket must not block!
ircSocket:settimeout(0)-- Buffers for stuff to send and receive on IRC:
local ircWBuf = ""
local ircRBuf = ""-- Predeclaration for functions calling each other
local writeIRC-----
-- Called when the IRC socket can be written again.
-- This happens when writeIRC (see below) couldnt write
-- its buffer in one go, call it again so it can continue its task.
local function ircWritey(fd)writeIRC()
end----
-- Called when there is data on the socket
local function ircReady(socket)local l, err, ircRBuf = ircSocket:receive("*l", ircRBuf)if not l thenif err ~= "timeout" thenlog("Error", "IRC connection failed: ", err)terminate(-1)endelseircRBuf = ""endlog("Normal", "ircin :", l)--- answers ping messageslocal ping = l:match("PING :(.*)")if ping thenwriteIRC("PONG :", ping, "\n")end
end-----
-- Writes on IRC socket
-- Do not forget to add an "/n".
function writeIRC(...)-- Appends all arbuments into the write bufferircWBuf = ircWBuf..table.concat({...})-- Gives it to the socket and sees how much it acceptedlocal s, err = ircSocket:send(ircWBuf)-- If it cant the socket terminated.if not s and err~="timeout" thenlog("Error", "IRC connection failed: ", err)terminate(-1)end--- logs what has been send, without the linefeed.if (ircWBuf:sub(s, s) == "\n") thenlog("Normal", "ircout:", ircWBuf:sub(1, s - 1))elselog("Normal", "ircout: ", ircWBuf:sub(1, s), "\\")end---- reduces the buffer by the amount of data sent.ircWBuf = ircWBuf:sub(s + 1, -1)-- when the write buffer is empty tell the core to no longer-- call ircWritey if data can be written on the socket. There-- is nothing to be written. If there is data in the buffer-- asks to be called as soon it can be written againif ircWBuf == "" thenobservefd(ircSocket:getfd(), ircReady, nil)elseobservefd(ircSocket:getfd(), ircReady, ircWritey)end
end-- Aquires the nick on IRC and joins the configured channel
-- This will also register the ircReady/ircWritey function at the core
-- to be called when the socket is ready to be read/written.
writeIRC("NICK ", nick, "\n")
writeIRC("USER ", nick, " 0 * :lsyncd-sayirc-bot", "\n")
writeIRC("JOIN ", chan, "\n")-- As action tells on IRC what the action is, then instead of
-- spawning somthing, it discards the event.
local function action(inlet)-- event2 is the target of a move eventlocal event, event2 = inlet.getEvent()if not event2 thenwriteIRC("PRIVMSG ",chan," :",event.etype," ",event.path, "\n")elsewriteIRC("PRIVMSG ",chan," :",event.etype," ",event.path," -> ",event2.path, "\n")endinlet.discardEvent(event)
end-- Watch a directory, and use a second for delay to aggregate events a little.
sync{source = "src",action = action,delay  = 1,onMove = true}
转载本文,请注明出处、作者。

Lsyncd:负载均衡之后,服务器的文件双向同步相关推荐

  1. Linxu服务器文件双向同步 rsync+sersync 详细讲解

    文章目录 Linxu服务器文件双向同步 rsync+sersync 基础信息 安装 rsync 安装 配置 根据配置文件创建相应的目录.文件.防火墙规则 创建需要同步的目录 创建同步用户 防火墙 启动 ...

  2. SharePoint咨询师之路:设计之前的那些事四:负载均衡 - web服务器

    SharePoint咨询师之路:设计之前的那些事四:负载均衡 - web服务器 提示:本系列只是一个学习笔记系列,大部分内容都可以从微软官方网站找到,本人只是按照自己的学习路径来学习和呈现这些知识.有 ...

  3. f5负载均衡配置文件服务器,f5 负载均衡 dns 服务器 配置

    f5 负载均衡 dns 服务器 配置 内容精选 换一换 查询负载均衡器状态树.可通过该接口查询负载均衡器关联的监听器.后端云服务器组.后端云服务器.健康检查.转发策略.转发规则的主要信息,了解负载均衡 ...

  4. SAP Netweaver的负载均衡消息服务器 vs CloudFoundry的App Router

    Message server for ABAP Netweaver SAP传统应用经典的三层架构: 起到负载均衡的消息服务器(Message Server)在图中没有得到体现.然后,消息服务器在我们每 ...

  5. 游戏服务器高性能负载均衡,游戏服务器高可用负载均衡

    游戏服务器高可用负载均衡 内容精选 换一换 公有云提供弹性公网IP(EIP).NAT网关.弹性负载均衡(ELB)等方式连接公网.EIPEIP提供独立的公网IP资源,包括公网IP地址与公网出口带宽服务. ...

  6. 消息服务器 负载均衡,(33)负载均衡上报Host主机信息API(LoadBalanceAgent部分)-【Lars-基于C++负载均衡远程服务器调度系统教程】...

    [Lars教程目录] 7) 负载均衡上报Host主机信息API(V0.4) 7.1 proto通信协议定义 syntax = "proto3"; package lars; /* ...

  7. f5服务器负载均衡性能指标,服务器负载均衡f5

    服务器负载均衡f5 内容精选 换一换 创建私网类型的负载均衡器.创建成功后,该接口会返回创建的负载均衡器的ID.所属子网ID.负载均衡器内网IP等详细信息.若要创建公网类型的负载均衡器,还需调用创建弹 ...

  8. Nginx负载均衡,服务器宕机问题

    如果Nginx没有仅仅只能代理一台服务器的话,那它也不可能像今天这么火,Nginx可以配置代理多台服务器,当一台服务器宕机之后,仍能保持系统可用.具体配置过程如下: 1. 在http节点下,添加ups ...

  9. f5负载均衡导致服务器响应,什么是F5负载均衡器,看完你就明白怎么回事了

    一.前言 在互联网雄起的时代,随着各个网络请求量的不断增大,利用负载分化请求量,从而达到优化硬件负荷量的目的,一般负载分为软件负载和硬件负载,比如软件中使用nginx等工具实现负载均衡,而F5负载均衡 ...

最新文章

  1. 服务器收到消息怎么推送给app_「刹那问答24」浅谈FCM推送
  2. mysql数据库设计之三范式
  3. 【机器视觉】 dev_get_system算子
  4. mysql开启binlog启动慢_mysql配置开启binlog与慢查询日志功能
  5. 【windows命令】windows系统常用cmd命令合集(持续更新中ing)
  6. 安卓dts音频解码_DTS音效、解码、编码概念剖析
  7. nginx管理面板_吸塑包装自建网站上线,阿里云ecs+bt面板+WordPress
  8. SAP ABAP 打印(smartforms方式)
  9. oracle 的wm_concat函数使用
  10. Intersecting Lines - POJ 1269(判断平面上两条直线的关系)
  11. 基于GMSSL的常用算法特点总结以及源代码分享
  12. 情侣博客源码php,wordpress如何搭建简单的情侣博客
  13. FIT2CLOUD飞致云成为Kubernetes认证服务提供商(KCSP)
  14. lol8月21号服务器维护,lol维护到几点今天?英雄联盟LOL8月21日维护更新内容
  15. python派森知多少_派森吧 - pythonpub.com | 享受python带来的便利以及快乐
  16. 计算机图形学原理及实践学习笔记第一章
  17. 转:用调制解调器打电话收传真-ModemFax
  18. 行走在投资界的程序员:千淘资本合伙人李华兵
  19. rdp(远程桌面协议)配置
  20. 入耳式蓝牙耳机哪个牌子好用?四款高品质音乐游戏耳机

热门文章

  1. buu——girlfriend
  2. 厦门大学计算机学院新院长,吴芸(副院长)-计算机与信息工程学院
  3. 多平台epub阅读器分享
  4. MySQL008:数据库引擎,如何设置引擎独立空间
  5. Vue组件之间的通信-父传子-子传父
  6. python普通类实现接口_python3从零学习-5.8.1、socket—底层网络接口
  7. 私域运营第五讲:实体店私域流量拉新实体餐饮店如何通过搭建私域流量实现营收增长
  8. eclipse导入项目jsp文件报错
  9. 数据治理的四字箴言:理、采、存、用
  10. springboot自带的线程池ThreadPoolTaskExecutor、ThreadPoolTaskScheduler的深入应用——异步任务监听回调,任务中断案例