基于阿里云的基础架构设施保障(二)IAAS云存储

1. 云硬盘

  1. HDD(普通云盘)

    特征: 性能一般, IOPS大概在数百左右。

    应用场景: 数据不被经常访问或者低I/O负载的应用场景,需要低成本并且有随机读写I/O的应用环境。

  2. 混合HDD(高效云盘)

    特征: 结合HDD和SSD硬盘构建, IOPS为1000~5000左右。

    应用场景: 开发与测试业务、系统盘。

  3. SSD云盘

    特征: 具有稳定的IO能力, IOPS能够达到10000~25000左右。

    应用场景:I/O密集型应用、中小型关系数据库、NoSQL数据库。

  4. 企业级SSD(ESSD云盘)

    特征: 优化增强的SSD云盘, 一般是采用企业级的闪存硬件, IOPS能够达到10000~1000000左右。

    应用场景: 大型OLTP数据库等关系型数据库、NoSQL数据库、ELK分布式日志存储等。

测试:

  1. 安装fio工具

     yum -y install fio
  2. iops测试

    fio --name=disktest --filename=~/disktest --rw=randread --refill_buffers --bs=4k --size=1G -runtime=5 -direct=1 -iodepth=128 -ioengine=libaio

    输出结果:

    [root@iZm5egp1t778ocdk7f1j6fZ ~]# fio --name=disktest --filename=~/disktest --rw=randread --refill_buffers --bs=4k --size=1G -runtime=5 -direct=1 -iodepth=128 -ioengine=libaio
    disktest: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=128
    fio-3.7
    Starting 1 process
    Jobs: 1 (f=1): [r(1)][100.0%][r=8560KiB/s,w=0KiB/s][r=2140,w=0 IOPS][eta 00m:00s]
    disktest: (groupid=0, jobs=1): err= 0: pid=1417: Thu Nov 12 22:09:25 2020
       read: IOPS=2151, BW=8606KiB/s (8812kB/s)(42.3MiB/5032msec)
        slat (usec): min=2, max=166, avg= 6.54, stdev= 3.69
        clat (usec): min=794, max=157946, avg=59467.61, stdev=47971.33
         lat (usec): min=799, max=157950, avg=59474.73, stdev=47971.03
        clat percentiles (usec):
         |  1.00th=[  1172],  5.00th=[  1434], 10.00th=[  1614], 20.00th=[  1860],
         | 30.00th=[  2147], 40.00th=[  2999], 50.00th=[ 98042], 60.00th=[ 98042],
         | 70.00th=[ 99091], 80.00th=[ 99091], 90.00th=[ 99091], 95.00th=[100140],
         | 99.00th=[127402], 99.50th=[127402], 99.90th=[156238], 99.95th=[156238],
         | 99.99th=[158335]
       bw (  KiB/s): min= 8544, max= 8560, per=99.46%, avg=8558.40, stdev= 5.06, samples=10
       iops        : min= 2136, max= 2140, avg=2139.60, stdev= 1.26, samples=10
      lat (usec)   : 1000=0.16%
      lat (msec)   : 2=25.15%, 4=15.13%, 10=0.03%, 50=0.59%, 100=56.23%
      lat (msec)   : 250=2.71%
      cpu          : usr=0.58%, sys=1.93%, ctx=1154, majf=0, minf=163
      IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.3%, >=64=99.4%
         submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
         complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.1%
         issued rwts: total=10826,0,0,0 short=0,0,0,0 dropped=0,0,0,0
         latency   : target=0, window=0, percentile=100.00%, depth=128
    
    Run status group 0 (all jobs):
       READ: bw=8606KiB/s (8812kB/s), 8606KiB/s-8606KiB/s (8812kB/s-8812kB/s), io=42.3MiB (44.3MB), run=5032-5032msec
    
    Disk stats (read/write):
      vda: ios=10486/0, merge=0/1, ticks=614779/0, in_queue=485314, util=75.89%

    iops平均达到2139.60,与高效云盘标示的2120基本是一致。

    也可以挂在动态硬盘进行测试, 不同的类型和存储空间, IOPS是不一样:

    file

2. 对象存储

  1. Amazon S3 vs 阿里云 OSS

    Amazon S3,全称亚马逊简易存储服务(Amazon Simple Storage Service)

    阿里云 OSS(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。

    对比:

功能特性Amazon S3阿里云OSS
存储对象对象对象
对象ACL支持支持
最大对象大小5T48.8T
数据可靠性99.999999999(11个9)99.999999999(11个9)
对象元数据元数据对象元
对象生命周期管理支持支持
对象版本控制支持支持(可选)
更新事件通知支持支持
跨地域复制支持支持
对象追加写入不支持支持
并行或分段上传支持支持
高一致性支持支持
数据加密在客户端和服务端加密在客户端和服务端加密
请求协议HTTP/HTTPSHTTP/HTTPS/Bit Torrent
图片处理不支持支持
  1. 对象存储VS云硬盘

    • 提供接口访问

      对象存储本质是一个网络化的服务, 云硬盘是挂载到虚拟机的虚拟硬盘,必须连接到虚拟机才能操作。

    • 存储结构不一致

      云硬盘是一个可以作为一个真正的文件系统, 而云存储是一个近似键值(key和value)的存储服务。

    • 海量数据存储

      云硬盘一般会受自身容量的限制, 不能支撑海量数据存储, 对象存储得益于其底层设计, 天生就能够支撑大数据存储。对象存储服务不仅可以支持海量的小文件, 也适合处理大型文件。

  2. 实践操作

    流程:

    file

    1. 开通OSS服务OSS产品详情页

    2. 创建存储空间, Bucket名称要具备唯一性。

    3. 开通对应的访问权限

      不要采用主账号,会存在安全隐患, 授权给RAM用户。 file

    4. 添加依赖

      <dependency>
          <groupId>com.aliyun.oss</groupId>
          <artifactId>aliyun-sdk-oss</artifactId>
          <version>3.10.2</version>
      </dependency>
    5. 上传文件

      UploadApplication:

      public class UploadApplication {
      
          public static void main(String[] args) throws Exception{
      
              // 创建OSSClient实例。
              OSS ossClient = new OSSClientBuilder().build(Constants.endpoint, Constants.accessKeyId, Constants.accessKeySecret);
      
              // 创建PutObjectRequest对象。
              PutObjectRequest putObjectRequest = new PutObjectRequest(Constants.bucketName, "readme", new File("d:/readme.txt"));
      
              // 上传文件。
              PutObjectResult result = ossClient.putObject(putObjectRequest);
      
              System.out.println("upload complete.");
              // 关闭OSSClient。
              ossClient.shutdown();
          }
      }
    6. 下载文件

      DownloadApplication:

      public class DownloadApplication {
      
          public static void main(String[] args) {
              // Endpoint以杭州为例,其它Region请按实际情况填写。
              String endpoint = Constants.endpoint;
              // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
              String accessKeyId = Constants.accessKeyId;
              String accessKeySecret = Constants.accessKeySecret;
              String bucketName = Constants.bucketName;
              String objectName = "readme";
      
              // 创建OSSClient实例。
              OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
      
              // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
              ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File("e:/"+ objectName));
      
              // 关闭OSSClient。
              ossClient.shutdown();
      
              System.out.println("download complete.");
      
          }
      }
      

3. 表单上传案例

  1. 应用场景

    表单上传非常适合嵌入在HTML网页中来上传Object,比较常见的场景是网站应用,以招聘网站为例, 流程比对:

    • 不使用表单上传

      1. 网站用户上传简历。
      2. 网站服务器回应上传页面。
      3. 简历被上传到网站服务器。
      4. 网站服务器再将简历上传到OSS。
    • 采用表单上传

      1. 网站用户上传简历。
      2. 网站服务器回应上传页面。
      3. 简历上传到OSS。

    使用表单上传,少了一步转发流程, 并且在上传量过大时, 减少了业务应用方服务扩容的压力。

  2. 通过STS临时授权访问OSS

    通过阿里云STS(Security Token Service)进行临时授权访问, 可以为第三方应用颁发一个自定义时效和权限的访问凭证, 用以保障服务安全性(类似于OAuth2的授权码访问模式)。

    实现机制:

    file

  3. RAM用户STS授权配置

    进入RAM访问控制后台->用户->添加权限, 输入框填写"sts"过滤, 选择AliyunSTSAssumeRoleAccess权限。

    file

  4. 创建权限策略

    输入权限策略名称, 可以选择脚本配置, 更为灵活。

    file

    策略内容:

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "oss:*"
                ],
                "Resource": [
                    "acs:oss:*:*:cloudstorage-test",
                    "acs:oss:*:*:cloudstorage-test/*"
                ]
            }
        ]
    }

    意思是对名称为cloudstorage-test的Bucket具有完全控制权限。如果更细力度的控制, 可以修改Action,例如:

    "Action": [ "oss:ListBuckets", "oss:GetBucketStat", "oss:GetBucketInfo", "oss:GetBucketTagging", "oss:GetBucketAcl" ],  
  5. 创建访问角色

    打开"RAM角色管理",点击"创建RAM角色“,可信实体类型选择“阿里云账号”

    接下来输入角色名称, 选择当前云账号;添加上面所创建的权限策略“oss_access”。

    file

    配置完成后, 会生成一个ARN值, 需要将它记录下来。

  6. 申请STS的访问TOKEN信息

    StsServiceApplication代码:

    public class StsServiceApplication {
        public static void main(String[] args) {
            String endpoint = "sts.cn-beijing.aliyuncs.com";
            String AccessKeyId = Constants.accessKeyId;
            String accessKeySecret = Constants.accessKeySecret;
            String roleArn = "acs:ram::1567235516853620:role/ram-oss-access";
            String roleSessionName = "oss_access_session";
            String policy = "{\n" +
                    "    \"Version\": \"1\", \n" +
                    "    \"Statement\": [\n" +
                    "        {\n" +
                    "            \"Action\": [\n" +
                    "                \"oss:*\"\n" +
                    "            ], \n" +
                    "            \"Resource\": [\n" +
                    "                \"acs:oss:*:*:*\" \n" +
                    "            ], \n" +
                    "            \"Effect\": \"Allow\"\n" +
                    "        }\n" +
                    "    ]\n" +
                    "}";
            try {
                // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
                DefaultProfile.addEndpoint("", "", "Sts", endpoint);
                // 构造default profile(参数留空,无需添加region ID)
                IClientProfile profile = DefaultProfile.getProfile("", AccessKeyId, accessKeySecret);
                // 用profile构造client
                DefaultAcsClient client = new DefaultAcsClient(profile);
                final AssumeRoleRequest request = new AssumeRoleRequest();
                request.setMethod(MethodType.POST);
                request.setRoleArn(roleArn);
                request.setRoleSessionName(roleSessionName);
                request.setPolicy(policy); // 若policy为空,则用户将获得该角色下所有权限
                request.setDurationSeconds(1000L); // 设置凭证有效时间
                final AssumeRoleResponse response = client.getAcsResponse(request);
                System.out.println("Expiration: " + response.getCredentials().getExpiration());
                System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
                System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
                System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
                System.out.println("RequestId: " + response.getRequestId());
            } catch (ClientException e) {
                System.out.println("Failed:");
                System.out.println("Error code: " + e.getErrCode());
                System.out.println("Error message: " + e.getErrMsg());
                System.out.println("RequestId: " + e.getRequestId());
            }
        }
    }

    返回结果:

    Expiration: 2020-11-15T06:37:51Z
    Access Key Id: STS.NT2Mshx5eaKbLScAzcwXLLK5V
    Access Key Secret: 7buxRohgRr6vT1EVAqq4FWjxaUFRQMuC4vvV55utenkJ
    Security Token: CAISjwJ1q6Ft5B2yfSjIr5eHBsnclepE1omJTnXSpXo2e9dgo46etDz2IHxMenFgA+sfv/0ynGBR5/YSlrt0UIRyTEfPYNBr2Y9a6higZIyZdz4iUQhC2vOfAmG2J0PR7q27OpfELr70fvOqdCqz9Etayqf7cjOPRkGsNYbz57dsctUQWHvXD1dBH8wEZHEhyqkgOGDWKOymPzPzn2PUFzAIgAdnjn5l4qnNpa/54xHF3lrh0b1X9cajYLrcNpQyY80kDorsgrwrLfSbiBQ9sUYaqP1E64Vf4irCs92nBF1c3g6LKeK88Kc0cFcnPvhgQPcV9aWkxaQp6rzJ8Z7+zlNKJvoQWi/USZu70Fd2+ykG8lpTGoABiIGFt+WCBkX/yLkY3uHDiWq4Uud32DzXWQAQpGmOWXwYzPRepi0XCcC029hPoXwCsj6mWbd/Ls2bUQsLUPtG3ozr6WawG2XUBXgZI5dNip8dZJCWZSet9qGsNXubhA3hTC+Wi7MNOariEkmr1kjqnG6N/YNaWuMYJ3BUobvLL4g=
    RequestId: 480E0B98-ACA5-4C98-AA82-6D9901CD7EE4
  7. 表单上传

    FormPostApplication代码:

    public class FormPostApplication {
    
        // The local file path to upload.
        private String localFilePath = "d:/trade_stock.sql";
        // OSS domain, such as http://oss-cn-hangzhou.aliyuncs.com
        private String endpoint = Constants.endpoint;
        // Access key Id. Please get it from https://ak-console.aliyun.com
        private String accessKeyId = "STS.NTcqigyooFzFUeV2GRZPWDLt8";
        private String accessKeySecret = "HwdZYJ8wVUopdNscwDYFf7oPgBpA4WXgG6K4JggztqW9";
        private String oss_security_token= "CAISjwJ1q6Ft5B2yfSjIr5fWOtPTlLBO8bitV0Pn1kcHVt97q4nf2jz2IHxMenFgA+sfv/0ynGBR5/YSlrt0UIRyTEfPYNBr2Y9a6higZIyZW2tYUAhC2vOfAmG2J0PR7q27OpfELr70fvOqdCqz9Etayqf7cjOPRkGsNYbz57dsctUQWHvXD1dBH8wEZHEhyqkgOGDWKOymPzPzn2PUFzAIgAdnjn5l4qnNpa/54xHF3lrh0b1X9cajYLrcNpQyY80kDorsgrwrLfSbiBQ9sUYaqP1E64Vf4irCs92nBF1c3g6LKeK88Kc0cFcnPvhgQPcV9aWkxaQp6rzJ8Z7+zlNKJvoQWi/USZu70Fd2+ykG8lpTGoABUJly6VzNT0fNrAW2uTyuuGX+PI/PaV7df5cewy7WoAnvtjDe0PM8vBWuD6zY3dQFgQOPFkY8RxxQUrSkZ9wpS3E7FBjzTfkFGlRHmmc+ad8uCLPaWIb/B9QGI6uKidSXnEnLqcK+8xsB1HBsyCkL600PJfcuSWBs9CHh9uiJTG0=";
    
        // The existing bucket name
        private String bucketName = Constants.bucketName;
        // The key name for the file to upload.
        private String key = "trade_stock";   
    
        private void postObject() throws Exception {
            // append the 'bucketname.' prior to the domain, such as http://bucket1.oss-cn-hangzhou.aliyuncs.com.
            String urlStr = endpoint.replace("http://", "http://" + bucketName + ".");
    
            // form fields
            Map<String, String> formFields = new LinkedHashMap<String, String>();
    
            // key
            formFields.put("key", this.key);
            // Content-Disposition
            formFields.put("Content-Disposition", "attachment;filename="
                    + localFilePath);
            // OSSAccessKeyId
            formFields.put("OSSAccessKeyId", accessKeyId);
            // policy
            String policy
                    = "{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [[\"content-length-range\", 0, 104857600]]}";
            String encodePolicy = new String(Base64.encodeBase64(policy.getBytes()));
            formFields.put("policy", encodePolicy);
            // Signature
            String signaturecom = computeSignature(accessKeySecret, encodePolicy);
            formFields.put("Signature", signaturecom);
            // Set security token.
            formFields.put("x-oss-security-token", oss_security_token);
    
            String ret = formUpload(urlStr, formFields, localFilePath);
    
            System.out.println("Post Object [" + this.key + "] to bucket [" + bucketName + "]");
            System.out.println("post reponse:" + ret);
        }
    
        private static String computeSignature(String accessKeySecret, String encodePolicy)
                throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
            // convert to UTF-8
            byte[] key = accessKeySecret.getBytes("UTF-8");
            byte[] data = encodePolicy.getBytes("UTF-8");
    
            // hmac-sha1
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(new SecretKeySpec(key, "HmacSHA1"));
            byte[] sha = mac.doFinal(data);
    
            // base64
            return new String(Base64.encodeBase64(sha));
        }
    
        private static String formUpload(String urlStr, Map<String, String> formFields, String localFile)
                throws Exception {
            String res = "";
            HttpURLConnection conn = null;
    //        String boundary = "9431149156168";
            String boundary = "abc";
    
            try {
                URL url = new URL(urlStr);
                conn = (HttpURLConnection)url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(30000);
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("User-Agent",
                        "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
                // Set Content-MD5. The MD5 value is calculated based on the whole message body.
    //            conn.setRequestProperty("Content-MD5", "<yourContentMD5>");
                conn.setRequestProperty("Content-Type",
                        "multipart/form-data; boundary=" + boundary);
                OutputStream out = new DataOutputStream(conn.getOutputStream());
    
                // text
                if (formFields != null) {
                    StringBuffer strBuf = new StringBuffer();
                    Iterator<Entry<String, String>> iter = formFields.entrySet().iterator();
                    int i = 0;
    
                    while (iter.hasNext()) {
                        Entry<String, String> entry = iter.next();
                        String inputName = entry.getKey();
                        String inputValue = entry.getValue();
    
                        if (inputValue == null) {
                            continue;
                        }
    
                        if (i == 0) {
                            strBuf.append("--").append(boundary).append("\r\n");
                            strBuf.append("Content-Disposition: form-data; name=\""
                                    + inputName + "\"\r\n\r\n");
                            strBuf.append(inputValue);
                        } else {
                            strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
                            strBuf.append("Content-Disposition: form-data; name=\""
                                    + inputName + "\"\r\n\r\n");
                            strBuf.append(inputValue);
                        }
    
                        i++;
                    }
                    out.write(strBuf.toString().getBytes());
                }
    
                // file
                File file = new File(localFile);
                String filename = file.getName();
                String contentType = new MimetypesFileTypeMap().getContentType(file);
                if (contentType == null || contentType.equals("")) {
                    contentType = "application/octet-stream";
                }
    
                StringBuffer strBuf = new StringBuffer();
                strBuf.append("\r\n").append("--").append(boundary)
                        .append("\r\n");
                strBuf.append("Content-Disposition: form-data; name=\"file\"; "
                        + "filename=\"" + filename + "\"\r\n");
                strBuf.append("Content-Type: " + contentType + "\r\n\r\n");
    
                out.write(strBuf.toString().getBytes());
    
                DataInputStream in = new DataInputStream(new FileInputStream(file));
                int bytes = 0;
                byte[] bufferOut = new byte[1024];
                while ((bytes = in.read(bufferOut)) != -1) {
                    out.write(bufferOut, 0, bytes);
                }
                in.close();
    
                byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
                out.write(endData);
                out.flush();
                out.close();
    
                // Gets the file data
                strBuf = new StringBuffer();
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    strBuf.append(line).append("\n");
                }
                res = strBuf.toString();
                reader.close();
                reader = null;
            } catch (Exception e) {
                System.err.println("Send post request exception: " + e);
                throw e;
            } finally {
                if (conn != null) {
                    conn.disconnect();
                    conn = null;
                }
            }
    
            return res;
        }
    
        public static void main(String[] args) throws Exception {
            FormPostApplication ossPostObject = new FormPostApplication();
            ossPostObject.postObject();
        }
    
    }
    1. 将上面所获取的key,secret和token填入。

    2. bucket名称要和上面授权对应的bucket一致。

    3. 这里是模拟form表单提交,编码采用UTF-8。

    4. policy里面可以配置超时时间, 内容长度范围等。

    5. 如果出现403错误,检查token等权限信息的配置是否正确。

    6. 如果出现400错误, 检查参数配置是否正确, 比如说MD5参数如果传递, 但没配置正确, 会出现此错误。

      conn.setRequestProperty("Content-MD5", "<yourContentMD5>");

    操作成功后, 能够在后台看到对应的文件信息。

    file

4. 服务上传验证

  1. 代码:

    • 添加阿里云依赖。

    • 添加阿里云配置信息。

    • 采用表单方式上传, 直接将数据存至OSS服务中。实现类: FormFileUploadServiceImpl。

  2. 打包app-file服务

    maven clean install

    file

  3. 上传至云服务器

    运行:

    java -jar app-file.jar
  4. 功能验证

    对文件上传和下载进行验证。

    file

5. 云数据库

  1. 云数据库 VS 传统数据库

    云数据库和传统数据库在搭建、运维、管理层面,云数据库提升了一个层次,实现了较高程度的智能化和自动化,极大地提升了用户友好度,降低了使用门槛。比如灵活的性能等级调整、详尽的监控体系、攻击防护机制等等。

    云数据库的高级特性:

    • 读写分离

      提供可视化的读写分离配置管理功能。从数据库实例的创建, 到同步关系以及读写流量分发, 云数据库都能自动化完成。

      ![file](https://img-blog.csdnimg.cn/20210806142713555.png)
    • 自动调优

      云数据库都自带性能分析和改进的模块, 能够自动地发现性能热点,还能够智能地给出调整建议,比如进行个别语句的调整,添加额外的索引等等。云数据库的性能分析和自动调优的能力,是将生产运行数据和服务内置的 AI 模型进行了结合,做到了真正的智能化运维, 极大的节省了成本。

      阿里云的数据库自治服务DAS:

      自治服务DAS是一种基于机器学习和专家经验实现数据库自感知、自修复、自优化、自运维及自安全的云服务,使用了DAS之后您可以避免这样的复杂性和人工操作引起的故障,有效保障数据库服务的稳定、安全及高效。

      ![file](https://img-blog.csdnimg.cn/20210806142714242.png)
    • 监控维护

      云数据库提供了全面强大的监控维护功能, 提供了丰富的性能监控项,能够及时发现并预警。

      ![file](https://img-blog.csdnimg.cn/20210806142715219.png)

      监控包含CPU和内存使用率、磁盘空间、IOPS、连接数、CPU内存使用率和网络流量等。

      报警功能:

      ![file](https://img-blog.csdnimg.cn/20210806142715824.png)

      可以根据不同的规则来组合设定预警条件:

      ![file](https://img-blog.csdnimg.cn/20210806142716270.png)

6. 云数据库操作

  1. 创建云数据库实例

    根据自身需要, 选择相应配置:

    file

  2. 访问权限配置

    申请外网访问地址:

    file

    这里提供了内网和外网不同访问地址。

    file

    需要设定白名单, 0.0.0.0/0是允许所有主机访问, 在实际应用中, 最好要指定具体的IP。

    file

    hdm_security_ips是DAS服务白名单, 自动生成。

  3. 数据库账号配置

    创建访问数据库的账号密码。

    file

    服务授权标签可以开通配置权限与数据权限。

  4. 连接配置

    file

  5. SQL洞察

    连入数据库后, 做一些SQL操作, 通过SQL洞察就能看到详细的信息:

    file

  6. 全量SQL统计

    这里面会侧重性能分析, 并给出自动优化提示。

    file

7. 服务连接云数据库

  1. 代码

    • 编写下单与查询订单的接口。
    • 配置数据源连接, 指向云数据库。
    • 采用JPA方式对数据进行操作。
  2. 修改连接配置

    修改application.yml配置文件:

    file

  3. 服务打包

    maven clean install

    file

  4. 上传至云服务器

    运行:

    java -jar app-server.jar
  5. 功能验证

    测试数据库的新增与查询功能。

    新增: http://47.104.9.75:10692/addOrder?accountNo=1&execPrice=2

    file

    查询:http://47.104.9.75:10692/getAllOrders

    file

8. 新一代原生数据库

  1. 新一代原生数据库 VS 云数据库

    • 更强的性能与扩展性

      云原生数据库由于原生设计, 专门为云设计的专业化存储架构, 可以支撑更大规模的数据量,关系型云原生数据库能够脱离典型的数 TB 的容量上限,达到单库数十 TB 甚至百 TB 的级别。

      云原生数据库可以利用云快速地进行水平扩展,迅速调整、提升数据库的处理能力, 能够有效应对高并发场景。

    • 更高的可用性与可靠性

      云原生数据库默认就具备多副本高可用的,数据同步、读写分离等高级特性,比如Amazon Aurora云原生数据库, 就自动包含了分布在 3 个可用区、多达 6 份的数据副本。

      对于多种数据模型也有很好的支持, 除了兼容关系型数据库外, 还会推出适合不同形态和查询范式的云数据库,与 NoSQL 数据库形成竞争, 比如说AWS的图数据库 Neptune,Azure Cosmos DB的NoSQL 数据库服务。

    • 低成本与易维护性

      大部分云原生数据库, 在存储上不需要预先设置大小, 会随着存储占用自动扩展;在计算上, 也有部分云数据库推出了无服务器版本,比如 亚马逊 的 Aurora Serverless,在面对间歇偶发性工作负载时,都能节省较多的成本。

  2. 阿里云PolarDB

    file

    阿里云 PolarDB 放弃了通用分布式数据库OLTP多路并发写的支持,采用一写多读的架构设计,存储与计算分离的技术架构,简化了分布式系统难以兼顾的理论模型,又能满足绝大多数OLTP的应用场景和性能要求。

    PolarDB 的设计革新:

    1. 通过重新设计特定的文件系统来存取 Redo log 这种特定的 WAL I/O 数据。
    2. 通过高速网络和高效协议将数据库文件和 Redo log 文件放在共享存储设备上,避免了多次长路径 I/O 的重复操作,并且针对 Redolog的I/O 路径,专门设计了多副本共享存储块设备。
  3. 产品架构设计

    file

    • 一写多读

      主节点处理读写请求,只读节点仅处理读请求。一个集群版集群包含一个主节点和最多15个只读节点。

    • 计算与存储分离

      计算与存储分离的设计,计算节点仅存储元数据, 存储节点负责数据文件、Redo Log等存储。

    • 共享分布式存储

      多个计算节点共享一份数据,并非每个计算节点都存储一份数据, 降低存储成本。存储节点的数据采用多副本形式,确保数据的可靠性,并通过Parallel-Raft协议保证数据一致性。基于全新设计的分布式块存储和文件系统,存储容量可以在线平滑扩展。

  4. POLARDB 2.0 vs POLARDB 1.0

    PolarDB-X 1.0 是基于DRDS + RDS 的分布式云数据库服务, 产品的特征是采用 Share-Nothing 架构、以解决存储扩展性为出发点、提供面向用户的产品化交付能力。

    PolarDB-X 2.0 主要是解决企业的各种复杂需求:

    1. 在功能性方面, 既要保障SQL通用性, 又要具备NoSQL的扩展性;既要高并发, 又要支持实时复杂分析。
    2. 企业的历史沉淀数据是一大痛点, 要以最少的成本保障数据能够顺利稳定的迁移, 并且不影响现有服务的稳定性。
    3. 各种应用对GIS数据的处理需求会越来越旺盛,使用开源版本GIS性能、功能无法满足,需要有一个功能强大的存储介质。
    4. 海量数据的运维管理, 高级DBA非常欠缺,在维护方面需要高昂的成本。

    针对以上问题, POLARDB2.0应运而生,不但完全继承了1.0的架构体系,同时兼容了另外两个流行数据库Oracle与PostgreSQL。POLARDBv2.0forOracle,高度兼容Oracle;POLARDBv2.0 for PostgreSQL,完全兼容PostgreSQL。


本文由mirson创作分享,如需进一步交流,请加QQ群:19310171或访问www.softart.cn

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦神-mirson

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值