首页 文章 精选 留言 我的

精选列表

搜索[分布式锁],共10000篇文章
优秀的个人博客,低调大师

文盘Rust -- 生命周期问题引发的 static hashmap | 京东云技术团队

2021年上半年,撸了个rust cli开发的框架,基本上把交互模式,子命令提示这些cli该有的常用功能做进去了。项目地址:https://github.com/jiashiwen/interactcli-rs。 春节以前看到axum已经0.4.x了,于是想看看能不能用rust做个服务端的框架。 春节后开始动手,在做的过程中会碰到各种有趣的问题。于是记下来想和社区的小伙伴一起分享。社区里的小伙伴大部分是DBA和运维同学,如果想进一步了解更底层的东西,代码入手是个好路数。 我个人认为想看懂代码先要写好代码,起码了解开发的基本路数和工程的一般组织模式。但好多同学的主要工作并不是专职开发,所以也就没有机会下探研发技术。代码这个事儿光看书是不管用的。了解一门语言最好的方式是使用它。 那么,问题来了非研发人员如何熟悉语言呢?咏春拳里有句拳谚:”无师无对手,桩与镜中求“。解释两句,就是在没有师兄弟练习的情况下,对着镜子和木人桩练习。在这里我觉得所谓桩有两层含义,一个是木人桩,就是练习的工具,一个是”站桩“,传统武术训练基本功的方法。其实在实际的工作中DBA和运维同学会有很多场景需要编程,比如做一些运维方面的统计工作;分析问题时需要拿到某些数据。如果追求简单用Python的话可能对于其他语言就没有涉猎了。如果结合你运维数据库的原生开发语言,假以时日慢慢就能看懂相关的底层逻辑了。我个人有个观点,产品研发的原生语言是了解产品底层最好的入口。 后面如果在Rust的开发过程中有其他问题,我本人会把问题结合实际也写到这个系列里,也希望社区里对Rust感兴趣的小伙伴一起来”盘Rust“。 言归正传,说说这次在玩儿Rust时遇到的问题吧。 在 Rust 开发过程中,我们经常需要全局变量作为公共数据的存放位置。通常做法是利用 lazy_static/onecell 和 mux/rwlock 生成一个静态的 collection。 代码长这样 use std::collections::HashMap; use std::sync::RwLock; lazy_static::lazy_static! { static ref GLOBAL_MAP: RwLock<HashMap<String,String>> = RwLock::new({ let map = HashMap::new(); map }); } 基本的数据存取这样实现 use std::collections::HashMap; use std::sync::RwLock; lazy_static::lazy_static! { static ref GLOBAL_MAP: RwLock<HashMap<String,String>> = RwLock::new({ let map = HashMap::new(); map }); } fn main() { for i in 0..3 { insert_global_map(i.to_string(), i.to_string()) } print_global_map(); println!("finished!"); } fn insert_global_map(k: String, v: String) { let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.insert(k, v); } fn print_global_map() { let gpr = GLOBAL_MAP.read().unwrap(); for pair in gpr.iter() { println!("{:?}", pair); } } insert_global_map函数用来向GLOBAL_MAP插入数据,print_global_map()用来读取数据,上面程序的运行结果如下 ("0", "0") ("1", "1") ("2", "2") 下面我们来实现一个比较复杂一点儿的需求,从 GLOBAL_MAP 里取一个数,如果存在后面进行删除操作,直觉告诉我们代码似乎应该这样写 use std::collections::HashMap; use std::sync::RwLock; lazy_static::lazy_static! { static ref GLOBAL_MAP: RwLock<HashMap<String,String>> = RwLock::new({ let map = HashMap::new(); map }); } fn main() { for i in 0..3 { insert_global_map(i.to_string(), i.to_string()) } print_global_map(); get_and_remove(1.to_string()); println!("finished!"); } fn insert_global_map(k: String, v: String) { let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.insert(k, v); } fn print_global_map() { let gpr = GLOBAL_MAP.read().unwrap(); for pair in gpr.iter() { println!("{:?}", pair); } } fn get_and_remove(k: String) { println!("execute get_and_remove"); let gpr = GLOBAL_MAP.read().unwrap(); let v = gpr.get(&*k.clone()); let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.remove(&*k.clone()); } 上面这段代码输出长这样 ("0", "0") ("1", "1") ("2", "2") execute get_and_remove 代码没有结束,而是hang在了get_and_remove函数。 为啥会出现这样的情况呢?这也许与生命周期有关。gpr和gpw 这两个返回值分别为 RwLockReadGuard 和 RwLockWriteGuard,查看这两个 struct 发现确实可能引起死锁 must_not_suspend = "holding a RwLockWriteGuard across suspend \ points can cause deadlocks, delays, \ and cause Future's to not implement `Send`" 问题找到了就可以着手解决办法了,既然是与rust的生命周期有关,那是不是可以把读和写分别放在两个不同的生命周期里呢,于是对代码进行改写 use std::collections::HashMap; use std::sync::RwLock; lazy_static::lazy_static! { static ref GLOBAL_MAP: RwLock<HashMap<String,String>> = RwLock::new({ let map = HashMap::new(); map }); } fn main() { for i in 0..3 { insert_global_map(i.to_string(), i.to_string()) } print_global_map(); get_and_remove(1); println!("finished!"); } fn insert_global_map(k: String, v: String) { let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.insert(k, v); } fn print_global_map() { let gpr = GLOBAL_MAP.read().unwrap(); for pair in gpr.iter() { println!("{:?}", pair); } } fn get_and_remove_deadlock(k: String) { println!("execute get_and_remove"); let gpr = GLOBAL_MAP.read().unwrap(); let _v = gpr.get(&*k.clone()); let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.remove(&*k.clone()); } fn get_and_remove(k: i32) { let v = { let gpr = GLOBAL_MAP.read().unwrap(); let v = gpr.get(&*k.to_string().clone()); match v { None => Err(anyhow!("")), Some(pair) => Ok(pair.to_string().clone()), } }; let vstr = v.unwrap(); println!("get value is {:?}", vstr.clone()); let mut gpw = GLOBAL_MAP.write().unwrap(); gpw.remove(&*vstr); } 正确输出 ("1", "1") ("0", "0") ("2", "2") get value is "1" ("0", "0") ("2", "2") finished! Rust的生命周期是个很有意思的概念,从认识到理解确实有个过程。 源码地址 作者:京东科技 贾世闻 来源:京东云开发者社区 转载请注明来源

优秀的个人博客,低调大师

在JAVA中使用DCL双检查机制实现单例的多线程安全

元旦放假期间学代码,我都感动我自己啦。 试过了,OK的。 package demo.thread; public class MyObject { private static MyObject myObject ; private MyObject() { } public static MyObject getInstance() { try { if (myObject != null){ } else { Thread.sleep(3000L); synchronized (MyObject.class) { if (myObject == null){ myObject = new MyObject(); } } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } } package demo.thread; public class MyThread extends Thread { @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } } package demo.thread; public class Run { public static void main(String[] args) { // TODO Auto-generated method stub MyThread t1 = new MyThread(); t1.start(); MyThread t2 = new MyThread(); t2.start(); MyThread t3 = new MyThread(); t3.start(); } }

优秀的个人博客,低调大师

亚信安全Deep Security 全面兼容麒麟 Linux 国产操作系统 配备“安全

今日,亚信安全宣布,旗下的服务器深度安全防护系统(Deep Security)正式支持国产麒麟 Linux操作系统。继支持自主可控的网络基础架构、数据中心和云计算环境之后,亚信安全网络安全产品与解决方案实现了对自主可控操作系统的深入支持,此举对国家重要部门与支柱行业打造完全自主可控的网络安全防护体系意义重大。 麒麟 Linux是由国内企业自主开发的安全可靠操作系统,在国防、政府、企业、电力和金融等各领域的关键业务中实现了广泛应用,是自主可控安全产业中的重要组成部分。针对麒麟 Linux的内核架构与应用场景,亚信安全服务器深度安全防护系统(Deep Security)对产品进行了兼容性上的重大调整。经过严格测试,亚信安全服务器深度安全防护系统(Deep Security)能够完全兼容麒麟 Linux,防恶意软件、防火墙、入侵防御、完整性监控、日志审查等功能均为此重要国产化操作系统提供安全防护。 亚信安全产品研发及业务发展总经理童宁表示:“在与麒麟 Linux实现兼容之后,亚信安全服务器深度安全防护系统(Deep Security)将有助于那些应用与数据敏感、需要从基础架构到操作系统实现完全自主可控的组织,获得领先的安全防护能力。亚信安全服务器深度安全防护系统(Deep Security)提供了至关重要的服务器主机安全防护功能,可以帮助用户在网络安全威胁不断变化的背景下,防范非法控制、数据窃取,以及APT攻击等高级威胁,确保信息化系统、数据的安全性与完整性。” 尤为重要的是,亚信安全服务器深度安全防护系统(Deep Security)是专门为虚拟化环境量身打造的整体解决方案,从虚拟化底层的防护入手,大幅提升数据中心安全管理效率,并成功拦截黑客利用已知与未知漏洞发动的攻击。在国家大力发展云计算和大数据等相关先进产业,同时打造基于国产软件的自主可控安全产业的背景下,亚信安全服务器深度安全防护系统(Deep Security)与麒麟Linux系统实现完美适配,可以协助用户建立安全可信的云数据中心运营环境。 童宁指出:“与麒麟 Linux实现兼容是亚信安全帮助客户实现信息化系统自主可控战略的一部分。从核心知识产权、技术研发、本地化安全服务、战略合作等多个层面着手,亚信安全已经建立了完整的自主可控网络安全生态体系,在国家推动信息化自主可控战略的背景下,确保网络安全防护系统的自主可控,保护我国的网络主权不受侵犯。” 原文发布时间为:2016-04-29 本文来自云栖社区合作伙伴至顶网,了解相关信息可以关注至顶网。

优秀的个人博客,低调大师

Dubbo分布式架构实战--FastDFS分布式文件系统的安装与使用(单节点)

样例参考视频: http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53 跟踪服务器:192.168.4.121 (edu-dfs-tracker-01) 存储服务器:192.168.4.125 (edu-dfs-storage-01) 环境:CentOS 6.6 用户:root 数据目录:/fastdfs (注:数据目录按你的数据盘挂载路径而定) 安装包: FastDFS v5.05 libfastcommon-master.zip(是从FastDFS和FastDHT中提取出来的公共C函数库) fastdfs-nginx-module_v1.16.tar.gz nginx-1.6.2.tar.gz fastdfs_client_java._v1.25.tar.gz 源码地址:https://github.com/happyfish100/ 下载地址:http://sourceforge.net/projects/fastdfs/files/ 官方论坛:http://bbs.chinaunix.net/forum-240-1.html 一、所有跟踪服务器和存储服务器均执行如下操作 1、编译和安装所需的依赖包: # yum install make cmake gcc gcc-c++ 2、安装libfastcommon: (1)上传或下载libfastcommon-master.zip到/usr/local/src目录 (2)解压 # cd /usr/local/src/ # unzip libfastcommon-master.zip # cd libfastcommon-master (3) 编译、安装 # ./make.sh # ./make.sh install libfastcommon默认安装到了 /usr/lib64/libfastcommon.so /usr/lib64/libfdfsclient.so (4)因为FastDFS主程序设置的lib目录是/usr/local/lib,所以需要创建软链接. # ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so # ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so # ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so # ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so 3、安装FastDFS (1)上传或下载FastDFS源码包(FastDFS_v5.05.tar.gz)到 /usr/local/src 目录 (2)解压 # cd /usr/local/src/ # tar -zxvf FastDFS_v5.05.tar.gz # cd FastDFS (3)编译、安装(编译前要确保已经成功安装了libfastcommon) # ./make.sh # ./make.sh install 采用默认安装的方式安装,安装后的相应文件与目录: A、服务脚本在: /etc/init.d/fdfs_storaged /etc/init.d/fdfs_tracker B、配置文件在(样例配置文件): /etc/fdfs/client.conf.sample /etc/fdfs/storage.conf.sample /etc/fdfs/tracker.conf.sample C、命令工具在/usr/bin/目录下的: fdfs_appender_test fdfs_appender_test1 fdfs_append_file fdfs_crc32 fdfs_delete_file fdfs_download_file fdfs_file_info fdfs_monitor fdfs_storaged fdfs_test fdfs_test1 fdfs_trackerd fdfs_upload_appender fdfs_upload_file stop.sh restart.sh (4)因为FastDFS服务脚本设置的bin目录是/usr/local/bin,但实际命令安装在/usr/bin,可以进入 /user/bin目录使用以下命令查看fdfs的相关命令: # cd /usr/bin/ # ls | grep fdfs 因此需要修改FastDFS服务脚本中相应的命令路径,也就是把/etc/init.d/fdfs_storaged 和/etc/init.d/fdfs_tracker两个脚本中的/usr/local/bin修改成/usr/bin: # vi fdfs_trackerd 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin # vi fdfs_storaged 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin 二、配置FastDFS跟踪器(192.168.4.121) 1、 复制FastDFS跟踪器样例配置文件,并重命名: # cd /etc/fdfs/ # cp tracker.conf.sample tracker.conf 2、 编辑跟踪器配置文件: # vi /etc/fdfs/tracker.conf 修改的内容如下: disabled=false port=22122 base_path=/fastdfs/tracker (其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html ) 3、 创建基础数据目录(参考基础目录base_path配置): # mkdir -p /fastdfs/tracker 4、 防火墙中打开跟踪器端口(默认为22122): # vi /etc/sysconfig/iptables 添加如下端口行: -A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT 重启防火墙: # service iptables restart 5、 启动Tracker: # /etc/init.d/fdfs_trackerd start (初次成功启动,会在/fastdfs/tracker目录下创建data、logs两个目录) 查看FastDFS Tracker是否已成功启动: # ps -ef | grep fdfs 6、 关闭Tracker: # /etc/init.d/fdfs_trackerd stop 7、 设置FastDFS跟踪器开机启动: # vi /etc/rc.d/rc.local 添加以下内容: ## FastDFS Tracker /etc/init.d/fdfs_trackerd start 三、配置FastDFS存储(192.168.4.125) 1、 复制FastDFS存储器样例配置文件,并重命名: # cd /etc/fdfs/ # cp storage.conf.sample storage.conf 2、 编辑存储器样例配置文件: # vi /etc/fdfs/storage.conf 修改的内容如下: disabled=false port=23000 base_path=/fastdfs/storage store_path0=/fastdfs/storage tracker_server=192.168.4.121:22122 http.server_port=8888 (其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html ) 3、 创建基础数据目录(参考基础目录base_path配置): # mkdir -p /fastdfs/storage 4、 防火墙中打开存储器端口(默认为23000): # vi /etc/sysconfig/iptables 添加如下端口行: -A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT 重启防火墙: # service iptables restart 5、 启动Storage: # /etc/init.d/fdfs_storaged start (初次成功启动,会在/fastdfs/storage目录下创建data、logs两个目录) 查看FastDFS Storage是否已成功启动 # ps -ef | grep fdfs 6、 关闭Storage: # /etc/init.d/fdfs_storaged stop 7、 设置FastDFS存储器开机启动: # vi /etc/rc.d/rc.local 添加: ## FastDFS Storage /etc/init.d/fdfs_storaged start 四、文件上传测试(192.168.4.121) 1、修改Tracker服务器中的客户端配置文件: # cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf # vi /etc/fdfs/client.conf base_path=/fastdfs/tracker tracker_server=192.168.4.121:22122 2、执行如下文件上传命令: # /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /usr/local/src/FastDFS_v5.05.tar.gz 返回ID号:group1/M00/00/00/wKgEfVUYNYeAb7XFAAVFOL7FJU4.tar.gz (能返回以上文件ID,说明文件上传成功) 六、在每个存储节点上安装nginx 1、fastdfs-nginx-module作用说明 FastDFS通过Tracker服务器,将文件放在Storage服务器存储,但是同组存储服务器之间需要进入文件复制,有同步延迟的问题。假设Tracker服务器将文件上传到了192.168.4.125,上传成功后文件ID已经返回给客户端。此时FastDFS存储集群机制会将这个文件同步到同组存储192.168.4.126,在文件还没有复制完成的情况下,客户端如果用这个文件ID在192.168.4.126上取文件,就会出现文件无法访问的错误。而fastdfs-nginx-module可以重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。(解压后的fastdfs-nginx-module在nginx安装时使用) 2、上传fastdfs-nginx-module_v1.16.tar.gz到/usr/local/src 3、解压 # cd /usr/local/src/ # tar -zxvf fastdfs-nginx-module_v1.16.tar.gz 4、修改fastdfs-nginx-module的config配置文件 # cd fastdfs-nginx-module/src # vi config CORE_INCS="$CORE_INCS /usr/local/include/fastdfs /usr/local/include/fastcommon/" 修改为: CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/" (注意:这个路径修改是很重要的,不然在nginx编译的时候会报错的) 5、上传当前的稳定版本Nginx(nginx-1.6.2.tar.gz)到/usr/local/src目录 6、安装编译Nginx所需的依赖包 # yum install gcc gcc-c++ make automake autoconf libtool pcre* zlib openssl openssl-devel 7、编译安装Nginx(添加fastdfs-nginx-module模块) # cd /usr/local/src/ # tar -zxvf nginx-1.6.2.tar.gz # cd nginx-1.6.2 # ./configure --add-module=/usr/local/src/fastdfs-nginx-module/src # make && make install 8、复制fastdfs-nginx-module源码中的配置文件到/etc/fdfs目录,并修改 # cp /usr/local/src/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/ # vi /etc/fdfs/mod_fastdfs.conf 修改以下配置: connect_timeout=10 base_path=/tmp tracker_server=192.168.4.121:22122 storage_server_port=23000 group_name=group1 url_have_group_name = true store_path0=/fastdfs/storage 9、复制FastDFS的部分配置文件到/etc/fdfs目录 # cd /usr/local/src/FastDFS/conf # cp http.conf mime.types /etc/fdfs/ 10、在/fastdfs/storage文件存储目录下创建软连接,将其链接到实际存放数据的目录 # ln -s /fastdfs/storage/data/ /fastdfs/storage/data/M00 11、配置Nginx 简洁版nginx配置样例: user root; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8888; server_name localhost; location ~/group([0-9])/M00 { #alias /fastdfs/storage/data; ngx_fastdfs_module; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 注意、说明: A、8888端口值是要与/etc/fdfs/storage.conf中的http.server_port=8888 相对应, 因为http.server_port默认为8888,如果想改成80,则要对应修改过来。 B、Storage对应有多个group的情况下,访问路径带group名,如/group1/M00/00/00/xxx, 对应的Nginx配置为: location ~/group([0-9])/M00 { ngx_fastdfs_module; } C、如查下载时如发现老报404,将nginx.conf第一行user nobody修改为user root后重新启动。 12、防火墙中打开Nginx的8888端口 # vi /etc/sysconfig/iptables 添加: -A INPUT -m state --state NEW -m tcp -p tcp --dport 8888 -j ACCEPT # service iptables restart 13、启动Nginx # /usr/local/nginx/sbin/nginx ngx_http_fastdfs_set pid=xxx (重启Nginx的命令为:/usr/local/nginx/sbin/nginx -s reload) 14、通过浏览器访问测试时上传的文件 http://192.168.4.125:8888/group1/M00/00/00/wKgEfVUYNYeAb7XFAAVFOL7FJU4.tar.gz 七、FastDFS的使用的Demo样例讲解与演示: 具体内容请参考样例代码和视频教程 注意:千万不要使用kill -9命令强杀FastDFS进程,否则可能会导致binlog数据丢失。 关注公众号:

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册