示例

以下示例演示如何使用 TransactionScope 类定义代码块以参与事务。


C#

复制
// This function takes arguments for 2 connection strings and commands to create a transaction 
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the 
// transaction is rolled back. To test this code, you can connect to two different databases 
// on the same server by altering the connection string, or to another 3rd party RDBMS by 
// altering the code in the connection2 code block.
static public int CreateTransactionScope(
    string connectString1, string connectString2,
    string commandText1, string commandText2)
{
    // Initialize the return value to zero and create a StringWriter to display results.
    int returnValue = 0;
    System.IO.StringWriter writer = new System.IO.StringWriter();

    try
    {
        // Create the TransactionScope to execute the commands, guaranteeing
        // that both commands can commit or roll back as a single unit of work.
        using (TransactionScope scope = new TransactionScope())
        {
            using (SqlConnection connection1 = new SqlConnection(connectString1))
            {
                // Opening the connection automatically enlists it in the 
                // TransactionScope as a lightweight transaction.
                connection1.Open();

                // Create the SqlCommand object and execute the first command.
                SqlCommand command1 = new SqlCommand(commandText1, connection1);
                returnValue = command1.ExecuteNonQuery();
                writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

                // If you get here, this means that command1 succeeded. By nesting
                // the using block for connection2 inside that of connection1, you
                // conserve server and network resources as connection2 is opened
                // only when there is a chance that the transaction can commit.   
                using (SqlConnection connection2 = new SqlConnection(connectString2))
                {
                    // The transaction is escalated to a full distributed
                    // transaction when connection2 is opened.
                    connection2.Open();

                    // Execute the second command in the second database.
                    returnValue = 0;
                    SqlCommand command2 = new SqlCommand(commandText2, connection2);
                    returnValue = command2.ExecuteNonQuery();
                    writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
                }
            }

            // The Complete method commits the transaction. If an exception has been thrown,
            // Complete is not  called and the transaction is rolled back.
            scope.Complete();
        }
    }
    catch (TransactionAbortedException ex)
    {
        writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
    }

    // Display messages.
    Console.WriteLine(writer.ToString());

    return returnValue;
}

注解

如果确信范围内的所有操作都已成功完成,则只应调用此方法一次,以通知事务管理器所有资源的状态都是一致的,并且可以提交事务。 最好将调用作为块中的 using 最后一个语句。

未能调用此方法会中止事务,因为事务管理器将此解释为系统故障或在事务范围内引发的异常。 但是,还应注意,调用此方法并不能保证事务的提交。 它只是一种将状态通知给事务管理器的方式。 调用此方法后,无法再通过 Current 属性访问环境事务,并且尝试这样做会导致引发异常。

如果 TransactionScope 对象创建了事务,则资源管理器之间的实际提交工作将发生在 End Using 语句中。 如果该对象未创建事务,则每当 Commit 对象的所有者调用 CommittableTransaction 时都会执行提交。 此时,事务管理器会调用资源管理器,并根据是否在 对象上 TransactionScope 调用此方法来通知它们提交或回滚。

在Windows系统中,从XP开始就内嵌了一个设置网络端口转发的功能。依靠这个功能,任何到本地端口的TCP连接(ipv4或ipv6)都能够被转发到任意一个本地端口,甚至是远程主机的某个端口。并且,Windows系统并不需要去开启监听这个转发端口的服务。

在Windows服务器中,远程访问控制协议(RRAS)通常被用作端口转发,但是有一种更简单的配置方法,并且这种配置方法适用于windows的任意版本。

Windows系统下的端口转发使用portproxy模式下的netsh命令,该命令的使用前提是要在管理员身份打开cmd进行执行。

netsh interface portproxy add v4tov4  listenaddress=localaddress listenport= localport connectaddress=destaddress  connectport=destport protocol=tcp

listenaddress – 待连接的ip地址。

listenport –待连接的tcp本地端口 。

connectaddress – 待连接被转发的本地或远程主机的ip地址(支持域名)

connectport –从listenport转发到的tcp端口

案例

将一个RDP服务(远程桌面协议)转发到任意端口,将进来的流量从3340端口转发到标准的RDP端口3389。

netsh interface portproxy add v4tov4  listenport=3340 listenaddress=10.1.1.110  connectport=3389 connectaddress=10.1.1.110

1) netstat -ano | findstr :3340来验证3340端口是否正在监听中,如果该命令没有返回任何信息,或者说通过netsh接口并没有实现端口转发的功能,那么需要查看下系统是否开启了iphlpsvc(ip Helper)服务。

2) tasklist | findstr 3340查看监听该端口的进程

3) 检查防火墙是否关闭,如果关闭则跳过。如果打开需要手工配置相应的防火墙。

连接时请确保防火墙(Windows防火墙或者其他的第三方防护软件)允许外部连接到一个全新的端口,如果不允许,那么只能自行添加一个新的Windows防火墙规则,命令如下:netsh advfirewall firewall add rule name=”forwarded_RDPport_3340”  protocol=TCP dir=in localip=10.1.1.110  localport=3340 action=allow

当通过Windows防火墙接口为3340端口建立一个新的规则时,这个端口需要保证没有被任何程序占用,也就是说此端口仅供网络驱动使用。你可以创立任意的Windows端口转发规则,所有的netsh接口下的端口代理规则都是永久的,并且储存在系统中(不受开机重启的影响)。

查看系统中的所有转发规则是否生效:

netsh interface portproxy show all

查看端口转发的设置:netsh interface portproxy dump

删掉一个特定的端口转发规则:

netsh interface portproxy delete v4tov4

清空当前所有的配置规则:

netsh interface portproxy reset

从远程主机来尝试连接这个新转发的端口3340,3340端口等同于原来的3389端口,连接的地址为10.10.1.110:3340。

注意:这些转发规则仅仅适用于TCP端口,对于UDP的端口转发,使用上面的方法是无效的。在配置规则时,不能将127.0.0.1作为连接地址。

其他端口转发招式

1) 通过一台windows机器端口转发到一台windows远程主机

netsh interface portproxy add v4tov4  listenport=3340 listenaddress=10.1.1.110  connectport=3389  connectaddress=10.1.1.110

netsh interface portproxy add v4tov4 listenport=3389 listenaddress=0.0.0.0 connectport=3389 connectaddress=192.168.100.101

2) 通过一台ipv4的Windows机器转发到一台ipv6的服务器。

netsh interface portproxy add v4tov6  listenport=3340 listenaddress=10.1.1.110  connectport=3389  connectaddress=ffff::66

FAQ

1) 在Windows Server 2012 R2中,端口转发规则有可能会在系统重启后被重置,在这种情况下,需要在网络协议中检查是否存在配置不当,导致网络的间断性断开,或者当系统重启时是否出现了ip地址的变换(推荐使用静态ip)。在一个工作组里,通常是在windows任务计划程序里添加了一个实现端口转发的脚本。

2) 在Windows 2003/XP中,必须在注册表(HKLM\SYSTEM\ControlSet001\Services\Tcpip\Parameters)中找到并设置IPEnableRouter参数为1才能实现端口转发。

3) 防火墙规则检查

4) 端口转发依赖的ip helper服务是否启动

5) 端口转发是否生效

Windows日志查看

6273 网络策略服务器拒绝用户访问。

6274 网络策略服务器放弃用户的请求。

4868 证书管理器拒绝了挂起的证书请求。

4870 证书服务吊销了证书。

4944 当启动 Windows 防火墙时,以下策略处于活动状态。

4945 当启动 Windows 防火墙已列出规则。

4946 Windows 防火墙例外列表已更改。添加的规则。

4947 Windows 防火墙例外列表已更改。修改规则的。

4948 Windows 防火墙例外列表已更改。规则已被删除。

4949 Windows 防火墙设置都恢复为默认值。

4950 更改 Windows 防火墙设置。

4951 Windows 防火墙忽略规则,因为无法识别的主要版本号。

4952 Windows 防火墙忽略规则的部分,因为无法识别它的次要版本号。将强制执行该规则的其他部分。

4953 由于无法分析,Windows 防火墙将忽略规则。

4954 Windows 防火墙组策略设置已更改,并且未应用新设置。

4956 Windows 防火墙更改活动配置文件。

5024 Windows 防火墙服务已成功启动。

5025 Windows 防火墙服务已停止。

5027 Windows 防火墙服务无法从本地存储区中检索的安全策略。Windows 防火墙将继续执行当前的策略。

5028 Windows 防火墙无法分析新的安全策略。Windows 防火墙将继续执行当前的策略。

现象描述

日志中出现报错信息 “fork:Cannot allocate memory”。如下图所示:

可能原因

可能是进程数超限导致。系统内部的总进程数达到了 pid_max 时,再创建新进程时会报 “fork:Cannot allocate memory” 错。

解决思路

  1. 参考 处理步骤,查看实例内存使用率是否过高。
  2. 核实总进程数是否超限,并修改总进程数 pid_max 配置。

处理步骤

1、执行以下命令,查看系统 pid_max 值。

sysctl  -a | grep pid_max

根据返回结果,进行对应操作:

1.1、返回结果如下图所示,pid_max 默认值为32768,请执行下一步。

1.2、返回报错信息 “fork:Cannot allocate memory”,则需执行以下命令,临时调大 pid_max

echo 42768 > /proc/sys/kernel/pid_max

您可再次执行命令,查看系统 pid_max 值。

2、执行以下命令,查看系统内部总进程数。

pstree -p | wc -l

若总进程数达到了 pid_max,则系统在创建新进程时会报 “fork Cannot allocate memory” 错。

您可执行 ps -efL 命令,定位启动进程较多的程序。

3、将 /etc/sysctl.conf 配置文件中的 kernel.pid_max 值修改为65535,以增加进程数。修改完成后如下图所示:

4、执行以下命令,使配置立即生效。

sysctl -p

现象描述

Linux 云服务器在内存使用率未占满的情况下触发了 OOM(Out Of Memory)。如下图所示:

可能原因

可能是由系统可用内存低于 min_free_kbytes 值导致。min_free_kbytes 值表示强制 Linux 系统最低保留的空闲内存(Kbytes),如果系统可用内存低于设定的 min_free_kbytes 值,则默认系统启动 oom-killer 或强制重启。具体行为由内核参数 vm.panic_on_oom 值决定:

  • 若 vm.panic_on_oom=0,则系统会提示 OOM,并启动 oom-killer 杀掉占用最高内存的进程。
  • 若 vm.panic_on_oom =1,则系统会自动重启。

解决思路

  1. 参考处理步骤进行排查,查看实例内存使用率是否过高及总进程数是否受限。
  2. 核实 min_free_kbytes 值设置,并修改为正确配置。

处理步骤

1、登录云服务器,执行以下命令查看 min_free_kbytes 值

sysctl -a | grep min_free

min_free_kbytes 值单位为 kbytes,下图所示 min_free_kbytes = 1024000 即为1GB。

2、执行以下命令,使用 VIM 编辑器打开 /etc/sysctl.conf 配置文件。

vim /etc/sysctl.conf

3、按 i 进入编辑模式,修改 vm.min_free_kbytes 配置项。若该配置项不存在,则直接在配置文件中增加即可。

*建议修改 vm.min_free_kbytes 值为不超过总内存的1%即可。

4、按 Esc 并输入 :wq 后,按 Enter 保存并退出 VIM 编辑器。

5、执行以下命令,使配置生效即可。

sysctl -p

Version 22H2 (OS build 22621)

2022-10-1122621.674KB5018427
2022-09-3022621.608KB5017389
2022-09-2722621.525KB5019311
2022-09-2022621.521

1、使用人脸、指纹或 PIN 的Windows Hello可能会受到影响。

已通过KB5017389解决。

2、某些打印机可能只能进行默认设置,一些功能可能不可用,例如颜色、双面打印或更高分辨率。

已缓解。

微软正在努力研究解决方案,将在即将发布的版本中提供更新。

3、使用预配包,可能无法按预期工作。 

如果可以在升级到 Windows 11 版本 22H2 之前预配 Windows 设备,将不会有此问题。

微软正在调查此情况。

4、具有受影响的 Intel SST 驱动程序的 Windows 11 设备可能会收到蓝屏错误。

可以将 Intel® Smart Sound Technology 驱动程序更新为版本 10.30.00.5714 及更高版本或10.29.00.5714 及更高版本来解决此问题。(版本指的是最后一部分数字)

5、使用组策略首选项复制文件/快捷方式可能无法按预期工作。

微软正在努力研究解决方案,将在即将发布的版本中提供更新。

6、安装 KB5012170 时可能收到0x800f0922错误。

微软目前正在调查,将在即将发布的版本中提供更新。

9月20日微软发布了Windows11 2022(22H2)更新,这是Windows11的新版本。

Windows11使用了微软完善的更新系统和流程。当数据显示设备准备就绪时将分阶段逐步获得更新。

如果检测到设备可能有问题,比如应用程序不兼容,可能会采取保护措施,在问题解决之前不提供更新。

若是还没有收到该更新,建议等待后续更新推送。

若是仍然希望马上安装Windows11 22H2,

可以安装电脑健康状况检查应用,并运行后确认是否满足要求。

若是满足要求,再运行Windows11安装助手

*How to get the Windows 11 2022 Update | Windows Experience Blog

VirtualBox 是一款功能强大的虚拟机软件,它具有丰富的功能,性能也很优异,适用服务器、桌面和嵌入式等场景。除了适合企业,也适合家庭使用。VirtualBox 也是目前唯一一个开源的专业虚拟化解决方案。虚拟机的配置设置完全存储在 XML 中,并且独立于本地机器。因此虚拟机的相关设置可以很容易地移植到其他计算机上

目前 VirtualBox 7.0 发布了,上一个大型功能版本还是发布于 2018 年的 VirtualBox 6.0 。VirtualBox 7.0 带来最大的改动是允许虚拟机完全加密运行 —— 包括配置日志和保存状态的加密。但对于 VirtualBox 7.0,这种 VM 加密支持仅支持命令行界面。

此外,该版本还引入了一个基于 DirectX 11 的 3D 堆栈, Oracle 表示正在将 DXVK (尤其是 DXVK-Native)用于非 Windows 主机,意味着 Direct3D 堆栈最终在 Vulkan 上运行。

其他更改项目如下:

  • OCI:可以将云虚拟机添加到 Virtual Machine Manager ,并作为本地 VM 进行控制
  • OCI:可以通过网络管理器工具配置云网络,其方式与主机和 NAT 网络相同
  • 多项 GUI 的优化
  • 录音:使用 Vorbis 作为 WebM 容器的默认音频格式。
  • 音频:添加了 “默认” 主机驱动程序类型,可以在不同平台之间移动虚拟机(设备),无需显式更改音频驱动程序。
  • 来宾控制:实现了对 Linux 来宾 “添加自动更新” 的初始支持
  • 访客控制:通过 VBoxManage 更新添加访客时,实现等待和 / 或重新启动访客的功能
  • VBoxManage:添加了访客控制 “waitrunlevel” 子命令,可以等待访客达到某个运行级别
  • Windows 主机:添加了在会话 0 中运行自动启动 VM 的实验性支持,允许在用户未登录时运行 VMS(默认禁用,请参阅手册)
  • macOS 主机:删除了所有内核扩展。
  • macOS 主机:为具有 Apple 芯片 CPU 的系统提供开发者预览包。
  • Linux 访客:重新设计访客屏幕大小调整功能,添加了与一些访客桌面环境的基本集成
  • 设备:基于 DirectX 11(以及非 Windows 主机上的 DXVK)实现了新的 3D 支持
  • 设备:添加了虚拟 IOMMU 设备(Intel 和 AMD 变体)
  • 设备:添加了虚拟 TPM 1.2 和 2.0 设备
  • 设备:EHCI 和 XHCI USB 控制器设备现已作为开源基础包的一部分
  • EFI:增加了对安全启动的支持
  • 调试:添加了通过 GDB 对来宾调试的实验性支持,以及通过 KD/WinDbg 对来宾调试的高度实验性支持

更新公告:https://www.virtualbox.org/wiki/Changelog-7.0

nginx 发现警告日志提示:

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

原因是max_children设置太小了。

php-fpm.conf有两个至关重要的参数:

一个是”max_children”,另一个是”request_terminate_timeout”。

pm.max_children 表示 php-fpm 能启动的子进程的最大数量。

request_terminate_timeout 表示将执行时间太长的进程直接终止。

我的两个设置的值一个是”40″,一个是”900″,但是这个值不是通用的,而是需要自己计算的。

一、pm.max_children 多大合适?

这个值原则上是越大越好,php-cgi的进程多了就会处理的很快,排队的请求就会很少。

设置”max_children” 也需要根据服务器的性能进行设定。

计算方式如下:

一般来说一台服务器正常情况下每一个php-cgi所耗费的内存在20M~30M左右,因此我的”max_children”我设置成40个,20M*40=800M也就是说在峰值的时候所有PHP-CGI所耗内存在800M以内,低于我的有效内存2Gb。

而如果我 的”max_children”设置的较小,比如5-10个,那么php-cgi就会“很累“,处理速度也很慢,等待的时间也较长,占用的CPU也很高。

如果长时间没有得到处理的请求就会出现 504 Gateway Time-out 这个错误,而正在处理的很累的那几个php-cgi如果遇到了问题就会出现 502 Bad gateway 这个错误。

max_children较好的设置方式根据req/s(吞吐率,单位时间里服务器处理的最大请求数,单位req/s)来设置,若程序是 100 req/s 的处理能力,那么就设置 100比较好,这是动态来调整的。

二、request_terminate_timeout 多大合适?

计算方式如下:

如果你的服务器性能足够好,且宽带资源足够充足,PHP脚本没有循环或BUG的话你可以直接将”request_terminate_timeout”设 置成0s。0s的含义是让PHP-CGI一直执行下去而没有时间限制。

而如果你做不到这一点,也就是说你的PHP-CGI可能出现某个BUG,或者你的宽带不够充足或者其他的原因导致你的PHP-CGI能够假死那么就建议你给”request_terminate_timeout”赋一个值,这个值可以根 据你服务器的性能进行设定。

一般来说性能越好你可以设置越高,20分钟-30分钟都可以。由于我的服务器PHP脚本需要长时间运行,有的可能会超过10分钟因此我设置了900秒,这样不会导致PHP-CGI死掉而出现502 Bad gateway这个错误。

解码:

    public static string UnBase64String(string value)
    {
        if (value == null || value == "")
        {
            return "";
        }
        byte[] bytes = Convert.FromBase64String(value);
        return Encoding.UTF8.GetString(bytes);
    }

编码:

    public static string ToBase64String(string value)
    {
        if (value == null || value == "")
        {
            return "";
        }
        byte[] bytes = Encoding.UTF8.GetBytes(value);
        return Convert.ToBase64String(bytes);
    }